diff --git a/DOCKERFILE b/DOCKERFILE index 3e5328472..af421661b 100644 --- a/DOCKERFILE +++ b/DOCKERFILE @@ -1,5 +1,7 @@ FROM ubuntu:20.04 AS build +# DEBIAN_FRONTEND这个环境变量,告知操作系统应该从哪儿获得用户输入。 +# 如果设置为”noninteractive”,你就可以直接运行命令,而无需向用户请求输入(所有操作都是非交互式的)。 ARG DEBIAN_FRONTEND=noninteractive ENV TZ=Asia/Shanghai diff --git a/src/main/java/com/genersoft/iot/vmp/common/VideoManagerConstants.java b/src/main/java/com/genersoft/iot/vmp/common/VideoManagerConstants.java index cb2b1732f..5fd9c7725 100644 --- a/src/main/java/com/genersoft/iot/vmp/common/VideoManagerConstants.java +++ b/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 * diff --git a/src/main/java/com/genersoft/iot/vmp/conf/DynamicTask.java b/src/main/java/com/genersoft/iot/vmp/conf/DynamicTask.java new file mode 100644 index 000000000..145c29b54 --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/conf/DynamicTask.java @@ -0,0 +1,42 @@ +package com.genersoft.iot.vmp.conf; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; +import org.springframework.scheduling.support.CronTrigger; +import org.springframework.stereotype.Component; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ScheduledFuture; + +/** + * 动态定时任务 + */ +@Component +public class DynamicTask { + + @Autowired + private ThreadPoolTaskScheduler threadPoolTaskScheduler; + + private Map> futureMap = new ConcurrentHashMap<>(); + + @Bean + public ThreadPoolTaskScheduler threadPoolTaskScheduler() { + return new ThreadPoolTaskScheduler(); + } + + public String startCron(String key, Runnable task, String corn) { + stopCron(key); + ScheduledFuture future = threadPoolTaskScheduler.schedule(task, new CronTrigger(corn)); + futureMap.put(key, future); + return "startCron"; + } + + public void stopCron(String key) { + if (futureMap.get(key) != null && !futureMap.get(key).isCancelled()) { + futureMap.get(key).cancel(true); + } + } + +} diff --git a/src/main/java/com/genersoft/iot/vmp/conf/RedisConfig.java b/src/main/java/com/genersoft/iot/vmp/conf/RedisConfig.java index ee907882b..dcb0e811b 100644 --- a/src/main/java/com/genersoft/iot/vmp/conf/RedisConfig.java +++ b/src/main/java/com/genersoft/iot/vmp/conf/RedisConfig.java @@ -16,7 +16,7 @@ import redis.clients.jedis.JedisPool; 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 * diff --git a/src/main/java/com/genersoft/iot/vmp/conf/SipConfig.java b/src/main/java/com/genersoft/iot/vmp/conf/SipConfig.java index 709fe9c13..2d3079259 100644 --- a/src/main/java/com/genersoft/iot/vmp/conf/SipConfig.java +++ b/src/main/java/com/genersoft/iot/vmp/conf/SipConfig.java @@ -1,9 +1,7 @@ package com.genersoft.iot.vmp.conf; -import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.context.annotation.Configuration; import org.springframework.stereotype.Component; @Component @@ -27,7 +25,7 @@ public class SipConfig { Integer ptzSpeed = 50; - Integer keepaliveTimeOut = 180; + Integer keepaliveTimeOut = 255; Integer registerTimeInterval = 60; diff --git a/src/main/java/com/genersoft/iot/vmp/conf/SipDeviceRunner.java b/src/main/java/com/genersoft/iot/vmp/conf/SipDeviceRunner.java index 68bb1a610..da1664bdf 100644 --- a/src/main/java/com/genersoft/iot/vmp/conf/SipDeviceRunner.java +++ b/src/main/java/com/genersoft/iot/vmp/conf/SipDeviceRunner.java @@ -32,5 +32,7 @@ public class SipDeviceRunner implements CommandLineRunner { for (String deviceId : onlineForAll) { storager.online(deviceId); } + + // TODO 查询在线设备那些开启了订阅,为设备开启定时的目录订阅 } } diff --git a/src/main/java/com/genersoft/iot/vmp/conf/VManagerConfig.java b/src/main/java/com/genersoft/iot/vmp/conf/VManagerConfig.java index ff9d6439a..85c158c08 100644 --- a/src/main/java/com/genersoft/iot/vmp/conf/VManagerConfig.java +++ b/src/main/java/com/genersoft/iot/vmp/conf/VManagerConfig.java @@ -4,7 +4,7 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Configuration; /** - * @Description: 获取数据库配置 + * @description: 获取数据库配置 * @author: swwheihei * @date: 2020年5月6日 下午2:46:00 */ diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/SipLayer.java b/src/main/java/com/genersoft/iot/vmp/gb28181/SipLayer.java index 1afabb7c6..3d9b827bf 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/SipLayer.java +++ b/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.Bean; 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 @@ public class SipLayer implements SipListener { private SipConfig sipConfig; @Autowired - private SIPProcessorFactory processorFactory; + private SIPProcessorObserver sipProcessorObserver; @Autowired private SipSubscribe sipSubscribe; @@ -50,19 +42,16 @@ public class SipLayer implements SipListener { */ private ThreadPoolExecutor processThreadPool; - @Bean("initSipServer") - private ThreadPoolExecutor initSipServer() { - + public SipLayer() { int processThreadNum = Runtime.getRuntime().availableProcessors() * 10; LinkedBlockingQueue 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 @@ public class SipLayer implements SipListener { } @Bean("sipStack") - @DependsOn({"initSipServer", "sipFactory"}) + @DependsOn({"sipFactory"}) private SipStack createSipStack() throws PeerUnavailableException { Properties properties = new Properties(); properties.setProperty("javax.sip.STACK_NAME", "GB28181_SIP"); @@ -88,7 +77,7 @@ public class SipLayer implements SipListener { return sipStack; } - @Bean("tcpSipProvider") + @Bean(name = "tcpSipProvider") @DependsOn("sipStack") private SipProviderImpl startTcpListener() { ListeningPoint tcpListeningPoint = null; @@ -96,7 +85,7 @@ public class SipLayer implements SipListener { 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(); @@ -111,7 +100,7 @@ public class SipLayer implements SipListener { return tcpSipProvider; } - @Bean("udpSipProvider") + @Bean(name = "udpSipProvider") @DependsOn("sipStack") private SipProviderImpl startUdpListener() { ListeningPoint udpListeningPoint = null; @@ -119,8 +108,7 @@ public class SipLayer implements SipListener { 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) { @@ -135,140 +123,4 @@ public class SipLayer implements SipListener { 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); - } - } - } - } - - - - } - - /** - *

- * Title: processTimeout - *

- *

- * Description: - *

- * - * @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 timeoutEventEventResult = new SipSubscribe.EventResult<>(timeoutEvent); - errorSubscribe.response(timeoutEventEventResult); - } - - /** - *

- * Title: processIOException - *

- *

- * Description: - *

- * - * @param exceptionEvent - */ - @Override - public void processIOException(IOExceptionEvent exceptionEvent) { - // TODO Auto-generated method stub - - } - - /** - *

- * Title: processTransactionTerminated - *

- *

- * Description: - *

- * - * @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 eventResult = new SipSubscribe.EventResult<>(transactionTerminatedEvent); -// errorSubscribe.response(eventResult); - } - - /** - *

- * Title: processDialogTerminated - *

- *

- * Description: - *

- * - * @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 eventResult = new SipSubscribe.EventResult<>(dialogTerminatedEvent); -// errorSubscribe.response(eventResult); - - } - } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/auth/RegisterLogicHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/auth/RegisterLogicHandler.java index 01b0a1294..62d4bec02 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/auth/RegisterLogicHandler.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/auth/RegisterLogicHandler.java @@ -9,7 +9,7 @@ import com.genersoft.iot.vmp.gb28181.bean.Device; import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; /** - * @Description:注册逻辑处理,当设备注册后触发逻辑。 + * @description:注册逻辑处理,当设备注册后触发逻辑。 * @author: swwheihei * @date: 2020年5月8日 下午9:41:46 */ diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/Device.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/Device.java index bfbf5477a..761437fc7 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/Device.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/Device.java @@ -109,6 +109,11 @@ public class Device { */ private String charset ; + /** + * 目录订阅周期,0为不订阅 + */ + private int subscribeCycleForCatalog ; + public String getDeviceId() { @@ -270,4 +275,12 @@ public class Device { public void setCharset(String charset) { this.charset = charset; } + + public int getSubscribeCycleForCatalog() { + return subscribeCycleForCatalog; + } + + public void setSubscribeCycleForCatalog(int subscribeCycleForCatalog) { + this.subscribeCycleForCatalog = subscribeCycleForCatalog; + } } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/MobilePosition.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/MobilePosition.java index aba33924b..c6cf78253 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/MobilePosition.java +++ b/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日 */ diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/RecordInfo.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/RecordInfo.java index 0aaa6879f..dcac49d3b 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/RecordInfo.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/RecordInfo.java @@ -6,7 +6,7 @@ package com.genersoft.iot.vmp.gb28181.bean; import java.util.List; /** - * @Description:设备录像信息bean + * @description:设备录像信息bean * @author: swwheihei * @date: 2020年5月8日 下午2:05:56 */ diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/RecordItem.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/RecordItem.java index 1533b664f..39f894ce5 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/RecordItem.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/RecordItem.java @@ -8,7 +8,7 @@ import java.text.SimpleDateFormat; import java.util.Date; /** - * @Description:设备录像bean + * @description:设备录像bean * @author: swwheihei * @date: 2020年5月8日 下午2:06:54 */ diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/event/DeviceOffLineDetector.java b/src/main/java/com/genersoft/iot/vmp/gb28181/event/DeviceOffLineDetector.java index 60998ea35..e5b57c8b0 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/event/DeviceOffLineDetector.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/event/DeviceOffLineDetector.java @@ -7,7 +7,7 @@ import com.genersoft.iot.vmp.common.VideoManagerConstants; import com.genersoft.iot.vmp.utils.redis.RedisUtil; /** - * @Description:设备离在线状态检测器,用于检测设备状态 + * @description:设备离在线状态检测器,用于检测设备状态 * @author: swwheihei * @date: 2020年5月13日 下午2:40:29 */ diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/event/EventPublisher.java b/src/main/java/com/genersoft/iot/vmp/gb28181/event/EventPublisher.java index 042296218..33d6dd439 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/event/EventPublisher.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/event/EventPublisher.java @@ -13,7 +13,7 @@ import com.genersoft.iot.vmp.gb28181.event.offline.OfflineEvent; import com.genersoft.iot.vmp.gb28181.event.online.OnlineEvent; /** - * @Description:Event事件通知推送器,支持推送在线事件、离线事件 + * @description:Event事件通知推送器,支持推送在线事件、离线事件 * @author: swwheihei * @date: 2020年5月6日 上午11:30:50 */ diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/event/offline/KeepaliveTimeoutListenerForPlatform.java b/src/main/java/com/genersoft/iot/vmp/gb28181/event/offline/KeepaliveTimeoutListenerForPlatform.java index b9ac951a5..8363e581b 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/event/offline/KeepaliveTimeoutListenerForPlatform.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/event/offline/KeepaliveTimeoutListenerForPlatform.java @@ -12,7 +12,7 @@ import com.genersoft.iot.vmp.common.VideoManagerConstants; import com.genersoft.iot.vmp.gb28181.event.EventPublisher; /** - * @Description:设备心跳超时监听,借助redis过期特性,进行监听,监听到说明设备心跳超时,发送离线事件 + * @description:设备心跳超时监听,借助redis过期特性,进行监听,监听到说明设备心跳超时,发送离线事件 * @author: swwheihei * @date: 2020年5月6日 上午11:35:46 */ diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/event/offline/KeepliveTimeoutListener.java b/src/main/java/com/genersoft/iot/vmp/gb28181/event/offline/KeepliveTimeoutListener.java index cc871ef08..db694cc29 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/event/offline/KeepliveTimeoutListener.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/event/offline/KeepliveTimeoutListener.java @@ -12,7 +12,7 @@ import com.genersoft.iot.vmp.common.VideoManagerConstants; import com.genersoft.iot.vmp.gb28181.event.EventPublisher; /** - * @Description:设备心跳超时监听,借助redis过期特性,进行监听,监听到说明设备心跳超时,发送离线事件 + * @description:设备心跳超时监听,借助redis过期特性,进行监听,监听到说明设备心跳超时,发送离线事件 * @author: swwheihei * @date: 2020年5月6日 上午11:35:46 */ diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/event/offline/OfflineEvent.java b/src/main/java/com/genersoft/iot/vmp/gb28181/event/offline/OfflineEvent.java index aa45efe61..9dfeffcaf 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/event/offline/OfflineEvent.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/event/offline/OfflineEvent.java @@ -3,7 +3,7 @@ package com.genersoft.iot.vmp.gb28181.event.offline; import org.springframework.context.ApplicationEvent; /** - * @Description: 离线事件类 + * @description: 离线事件类 * @author: swwheihei * @date: 2020年5月6日 上午11:33:13 */ diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/event/offline/OfflineEventListener.java b/src/main/java/com/genersoft/iot/vmp/gb28181/event/offline/OfflineEventListener.java index 4adc8fba9..4b401c767 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/event/offline/OfflineEventListener.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/event/offline/OfflineEventListener.java @@ -11,8 +11,8 @@ import com.genersoft.iot.vmp.storager.IVideoManagerStorager; 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 @@ public class OfflineEventListener implements ApplicationListener { // 处理离线监听 storager.outline(event.getDeviceId()); + + // TODO 离线取消订阅 + } } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/event/online/OnlineEvent.java b/src/main/java/com/genersoft/iot/vmp/gb28181/event/online/OnlineEvent.java index 1e0195697..73d7f1f74 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/event/online/OnlineEvent.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/event/online/OnlineEvent.java @@ -4,7 +4,7 @@ import com.genersoft.iot.vmp.gb28181.bean.Device; import org.springframework.context.ApplicationEvent; /** - * @Description: 在线事件类 + * @description: 在线事件类 * @author: swwheihei * @date: 2020年5月6日 上午11:32:56 */ diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/event/online/OnlineEventListener.java b/src/main/java/com/genersoft/iot/vmp/gb28181/event/online/OnlineEventListener.java index f2150e548..b347891b6 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/event/online/OnlineEventListener.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/event/online/OnlineEventListener.java @@ -13,12 +13,11 @@ import com.genersoft.iot.vmp.storager.IVideoManagerStorager; 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、设备主动注销,发送注销指令 + * 2、设备未知原因离线,心跳超时 * @author: swwheihei * @date: 2020年5月6日 下午1:51:23 */ diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/event/platformKeepaliveExpire/PlatformKeepaliveExpireEventLister.java b/src/main/java/com/genersoft/iot/vmp/gb28181/event/platformKeepaliveExpire/PlatformKeepaliveExpireEventLister.java index 801e12593..6522387d9 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/event/platformKeepaliveExpire/PlatformKeepaliveExpireEventLister.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/event/platformKeepaliveExpire/PlatformKeepaliveExpireEventLister.java @@ -18,7 +18,7 @@ import javax.sip.ResponseEvent; import javax.sip.message.Response; /** - * @Description: 平台心跳超时事件 + * @description: 平台心跳超时事件 * @author: panll * @date: 2020年11月5日 10:00 */ diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/event/platformNotRegister/PlatformNotRegisterEventLister.java b/src/main/java/com/genersoft/iot/vmp/gb28181/event/platformNotRegister/PlatformNotRegisterEventLister.java index ea79e34fe..20950ca25 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/event/platformNotRegister/PlatformNotRegisterEventLister.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/event/platformNotRegister/PlatformNotRegisterEventLister.java @@ -19,7 +19,7 @@ import org.springframework.stereotype.Component; import java.util.*; /** - * @Description: 平台未注册事件,来源有二: + * @description: 平台未注册事件,来源有二: * 1、平台新添加 * 2、平台心跳超时 * @author: panll diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/session/VideoStreamSessionManager.java b/src/main/java/com/genersoft/iot/vmp/gb28181/session/VideoStreamSessionManager.java index d7cb5d272..ea9aa369e 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/session/VideoStreamSessionManager.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/session/VideoStreamSessionManager.java @@ -15,7 +15,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; /** - * @Description:视频流session管理器,管理视频预览、预览回放的通信句柄 + * @description:视频流session管理器,管理视频预览、预览回放的通信句柄 * @author: swwheihei * @date: 2020年5月13日 下午4:03:02 */ diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPProcessorFactory.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPProcessorFactory.java deleted file mode 100644 index 860f67630..000000000 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPProcessorFactory.java +++ /dev/null @@ -1,243 +0,0 @@ -package com.genersoft.iot.vmp.gb28181.transmit; - -import javax.sip.RequestEvent; -import javax.sip.ResponseEvent; -import javax.sip.SipProvider; -import javax.sip.header.CSeqHeader; -import javax.sip.message.Request; -import javax.sip.message.Response; - -import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform; -import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory; -import com.genersoft.iot.vmp.service.IDeviceAlarmService; -import com.genersoft.iot.vmp.service.IMediaServerService; -import com.genersoft.iot.vmp.storager.IRedisCatchStorage; -import com.genersoft.iot.vmp.gb28181.transmit.response.impl.*; -import com.genersoft.iot.vmp.service.IPlayService; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Lazy; -import org.springframework.stereotype.Component; - -import com.genersoft.iot.vmp.conf.SipConfig; -import com.genersoft.iot.vmp.gb28181.auth.RegisterLogicHandler; -import com.genersoft.iot.vmp.gb28181.event.DeviceOffLineDetector; -import com.genersoft.iot.vmp.gb28181.event.EventPublisher; -import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; -import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; -import com.genersoft.iot.vmp.gb28181.transmit.request.ISIPRequestProcessor; -import com.genersoft.iot.vmp.gb28181.transmit.request.impl.AckRequestProcessor; -import com.genersoft.iot.vmp.gb28181.transmit.request.impl.ByeRequestProcessor; -import com.genersoft.iot.vmp.gb28181.transmit.request.impl.CancelRequestProcessor; -import com.genersoft.iot.vmp.gb28181.transmit.request.impl.InviteRequestProcessor; -import com.genersoft.iot.vmp.gb28181.transmit.request.impl.MessageRequestProcessor; -import com.genersoft.iot.vmp.gb28181.transmit.request.impl.NotifyRequestProcessor; -import com.genersoft.iot.vmp.gb28181.transmit.request.impl.OtherRequestProcessor; -import com.genersoft.iot.vmp.gb28181.transmit.request.impl.RegisterRequestProcessor; -import com.genersoft.iot.vmp.gb28181.transmit.request.impl.SubscribeRequestProcessor; -import com.genersoft.iot.vmp.gb28181.transmit.response.ISIPResponseProcessor; -import com.genersoft.iot.vmp.gb28181.transmit.response.impl.ByeResponseProcessor; -import com.genersoft.iot.vmp.gb28181.transmit.response.impl.CancelResponseProcessor; -import com.genersoft.iot.vmp.gb28181.transmit.response.impl.InviteResponseProcessor; -import com.genersoft.iot.vmp.gb28181.transmit.response.impl.OtherResponseProcessor; -import com.genersoft.iot.vmp.storager.IVideoManagerStorager; -import com.genersoft.iot.vmp.utils.SpringBeanFactory; -import com.genersoft.iot.vmp.utils.redis.RedisUtil; - -/** - * @Description: SIP信令处理分配 - * @author: swwheihei - * @date: 2020年5月3日 下午4:24:37 - */ -@Component -public class SIPProcessorFactory { - - // private final static Logger logger = LoggerFactory.getLogger(SIPProcessorFactory.class); - - @Autowired - private SipConfig sipConfig; - - @Autowired - private RegisterLogicHandler handler; - - @Autowired - private IVideoManagerStorager storager; - - @Autowired - private IRedisCatchStorage redisCatchStorage; - - @Autowired - private EventPublisher publisher; - - @Autowired - private SIPCommander cmder; - - @Autowired - private SIPCommanderFroPlatform cmderFroPlatform; - - @Autowired - private IDeviceAlarmService deviceAlarmService; - - @Autowired - private RedisUtil redis; - - @Autowired - private DeferredResultHolder deferredResultHolder; - - @Autowired - private DeviceOffLineDetector offLineDetector; - - @Autowired - private InviteResponseProcessor inviteResponseProcessor; - - @Autowired - private ByeResponseProcessor byeResponseProcessor; - - @Autowired - private CancelResponseProcessor cancelResponseProcessor; - - @Autowired - @Lazy - private RegisterResponseProcessor registerResponseProcessor; - - - @Autowired - private OtherResponseProcessor otherResponseProcessor; - - @Autowired - private IPlayService playService; - - @Autowired - private ZLMRTPServerFactory zlmrtpServerFactory; - - @Autowired - private IMediaServerService mediaServerService; - - // 注:这里使用注解会导致循环依赖注入,暂用springBean - private SipProvider tcpSipProvider; - - // 注:这里使用注解会导致循环依赖注入,暂用springBean - private SipProvider udpSipProvider; - - public ISIPRequestProcessor createRequestProcessor(RequestEvent evt) { - Request request = evt.getRequest(); - String method = request.getMethod(); -// logger.info("接收到消息:"+request.getMethod()); -// sipSubscribe.getSubscribe(evt.getServerTransaction().getBranchId()).response(evt); - if (Request.INVITE.equals(method)) { - InviteRequestProcessor processor = new InviteRequestProcessor(); - processor.setRequestEvent(evt); - processor.setTcpSipProvider(getTcpSipProvider()); - processor.setUdpSipProvider(getUdpSipProvider()); - - processor.setCmder(cmder); - processor.setCmderFroPlatform(cmderFroPlatform); - processor.setPlayService(playService); - processor.setStorager(storager); - processor.setRedisCatchStorage(redisCatchStorage); - processor.setZlmrtpServerFactory(zlmrtpServerFactory); - processor.setMediaServerService(mediaServerService); - return processor; - } else if (Request.REGISTER.equals(method)) { - RegisterRequestProcessor processor = new RegisterRequestProcessor(); - processor.setRequestEvent(evt); - processor.setTcpSipProvider(getTcpSipProvider()); - processor.setUdpSipProvider(getUdpSipProvider()); - processor.setHandler(handler); - processor.setPublisher(publisher); - processor.setSipConfig(sipConfig); - processor.setVideoManagerStorager(storager); - return processor; - } else if (Request.SUBSCRIBE.equals(method)) { - SubscribeRequestProcessor processor = new SubscribeRequestProcessor(); - processor.setTcpSipProvider(getTcpSipProvider()); - processor.setUdpSipProvider(getUdpSipProvider()); - processor.setRequestEvent(evt); - return processor; - } else if (Request.ACK.equals(method)) { - AckRequestProcessor processor = new AckRequestProcessor(); - processor.setRequestEvent(evt); - processor.setRedisCatchStorage(redisCatchStorage); - processor.setZlmrtpServerFactory(zlmrtpServerFactory); - processor.setMediaServerService(mediaServerService); - return processor; - } else if (Request.BYE.equals(method)) { - ByeRequestProcessor processor = new ByeRequestProcessor(); - processor.setRequestEvent(evt); - processor.setRedisCatchStorage(redisCatchStorage); - processor.setStorager(storager); - processor.setZlmrtpServerFactory(zlmrtpServerFactory); - processor.setSIPCommander(cmder); - processor.setMediaServerService(mediaServerService); - return processor; - } else if (Request.CANCEL.equals(method)) { - CancelRequestProcessor processor = new CancelRequestProcessor(); - processor.setRequestEvent(evt); - return processor; - } else if (Request.MESSAGE.equals(method)) { - MessageRequestProcessor processor = new MessageRequestProcessor(); - processor.setRequestEvent(evt); - processor.setTcpSipProvider(getTcpSipProvider()); - processor.setUdpSipProvider(getUdpSipProvider()); - processor.setPublisher(publisher); - processor.setRedis(redis); - processor.setDeferredResultHolder(deferredResultHolder); - processor.setOffLineDetector(offLineDetector); - processor.setCmder(cmder); - processor.setCmderFroPlatform(cmderFroPlatform); - processor.setDeviceAlarmService(deviceAlarmService); - processor.setStorager(storager); - processor.setRedisCatchStorage(redisCatchStorage); - return processor; - } else if (Request.NOTIFY.equalsIgnoreCase(method)) { - NotifyRequestProcessor processor = new NotifyRequestProcessor(); - processor.setRequestEvent(evt); - processor.setTcpSipProvider(getTcpSipProvider()); - processor.setUdpSipProvider(getUdpSipProvider()); - processor.setPublisher(publisher); - processor.setRedis(redis); - processor.setDeferredResultHolder(deferredResultHolder); - processor.setOffLineDetector(offLineDetector); - processor.setCmder(cmder); - processor.setStorager(storager); - processor.setRedisCatchStorage(redisCatchStorage); - return processor; - } else { - OtherRequestProcessor processor = new OtherRequestProcessor(); - processor.setRequestEvent(evt); - return processor; - } - } - - public ISIPResponseProcessor createResponseProcessor(ResponseEvent evt) { - - Response response = evt.getResponse(); - CSeqHeader cseqHeader = (CSeqHeader) response.getHeader(CSeqHeader.NAME); - String method = cseqHeader.getMethod(); - if(Request.INVITE.equals(method)){ - return inviteResponseProcessor; - } else if (Request.BYE.equals(method)) { - return byeResponseProcessor; - } else if (Request.CANCEL.equals(method)) { - return cancelResponseProcessor; - }else if (Request.REGISTER.equals(method)) { - return registerResponseProcessor; - } else { - return otherResponseProcessor; - } - } - - private SipProvider getTcpSipProvider() { - if (tcpSipProvider == null) { - tcpSipProvider = (SipProvider) SpringBeanFactory.getBean("tcpSipProvider"); - } - return tcpSipProvider; - } - - private SipProvider getUdpSipProvider() { - if (udpSipProvider == null) { - udpSipProvider = (SipProvider) SpringBeanFactory.getBean("udpSipProvider"); - } - return udpSipProvider; - } - -} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPProcessorObserver.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPProcessorObserver.java new file mode 100644 index 000000000..48eebf8aa --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPProcessorObserver.java @@ -0,0 +1,161 @@ +package com.genersoft.iot.vmp.gb28181.transmit; + +import com.genersoft.iot.vmp.gb28181.event.SipSubscribe; +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.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import javax.sip.*; +import javax.sip.header.CSeqHeader; +import javax.sip.header.CallIdHeader; +import javax.sip.message.Response; +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 requestProcessorMap = new ConcurrentHashMap<>(); + private static Map responseProcessorMap = new ConcurrentHashMap<>(); + private static ITimeoutProcessor timeoutProcessor; + + @Autowired + private SipSubscribe sipSubscribe; + + /** + * 添加 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(method).process(requestEvent); + } + + /** + * 分发ResponseEvent事件 + * @param responseEvent responseEvent事件 + */ + @Override + public void processResponse(ResponseEvent responseEvent) { + logger.debug(responseEvent.getResponse().toString()); +// 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); + + + Response response = responseEvent.getResponse(); + logger.debug(responseEvent.getResponse().toString()); + int status = response.getStatusCode(); + if (((status >= 200) && (status < 300)) || status == 401) { // Success! +// ISIPResponseProcessor processor = processorFactory.createResponseProcessor(evt); + CSeqHeader cseqHeader = (CSeqHeader) responseEvent.getResponse().getHeader(CSeqHeader.NAME); + String method = cseqHeader.getMethod(); + ISIPResponseProcessor sipRequestProcessor = responseProcessorMap.get(method); + if (sipRequestProcessor != null) { + sipRequestProcessor.process(responseEvent); + } + if (responseEvent.getResponse() != null && sipSubscribe.getOkSubscribesSize() > 0 ) { + CallIdHeader callIdHeader = (CallIdHeader)responseEvent.getResponse().getHeader(CallIdHeader.NAME); + if (callIdHeader != null) { + SipSubscribe.Event subscribe = sipSubscribe.getOkSubscribe(callIdHeader.getCallId()); + if (subscribe != null) { + SipSubscribe.EventResult eventResult = new SipSubscribe.EventResult(responseEvent); + subscribe.response(eventResult); + } + } + } + } else if ((status >= 100) && (status < 200)) { + // 增加其它无需回复的响应,如101、180等 + } else { + logger.warn("接收到失败的response响应!status:" + status + ",message:" + response.getReasonPhrase()/* .getContent().toString()*/); + if (responseEvent.getResponse() != null && sipSubscribe.getErrorSubscribesSize() > 0 ) { + CallIdHeader callIdHeader = (CallIdHeader)responseEvent.getResponse().getHeader(CallIdHeader.NAME); + if (callIdHeader != null) { + SipSubscribe.Event subscribe = sipSubscribe.getErrorSubscribe(callIdHeader.getCallId()); + if (subscribe != null) { + SipSubscribe.EventResult eventResult = new SipSubscribe.EventResult(responseEvent); + subscribe.response(eventResult); + } + } + } + } + + } + + /** + * 向超时订阅发送消息 + * @param timeoutEvent timeoutEvent事件 + */ + @Override + public void processTimeout(TimeoutEvent timeoutEvent) { + if(timeoutProcessor != null) { + timeoutProcessor.process(timeoutEvent); + } + } + + @Override + public void processIOException(IOExceptionEvent exceptionEvent) { +// System.out.println("processIOException"); + } + + @Override + public void processTransactionTerminated(TransactionTerminatedEvent transactionTerminatedEvent) { +// System.out.println("processTransactionTerminated"); + } + + @Override + public void processDialogTerminated(DialogTerminatedEvent dialogTerminatedEvent) { + CallIdHeader callId = dialogTerminatedEvent.getDialog().getCallId(); + System.out.println("processDialogTerminated:::::" + callId); + } + + +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/callback/CheckForAllRecordsThread.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/callback/CheckForAllRecordsThread.java index ac949e53d..0327cc525 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/callback/CheckForAllRecordsThread.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/callback/CheckForAllRecordsThread.java @@ -1,17 +1,16 @@ package com.genersoft.iot.vmp.gb28181.transmit.callback; +import com.genersoft.iot.vmp.gb28181.bean.RecordInfo; +import com.genersoft.iot.vmp.gb28181.bean.RecordItem; +import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.cmd.RecordInfoResponseMessageHandler; +import com.genersoft.iot.vmp.utils.redis.RedisUtil; +import org.slf4j.Logger; + import java.util.ArrayList; import java.util.Comparator; import java.util.List; import java.util.concurrent.TimeUnit; -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.utils.redis.RedisUtil; - -import org.slf4j.Logger; - @SuppressWarnings("unchecked") public class CheckForAllRecordsThread extends Thread { @@ -58,7 +57,7 @@ public class CheckForAllRecordsThread extends Thread { msg.setData(recordInfo); deferredResultHolder.invokeAllResult(msg); logger.info("处理完成,返回结果"); - MessageRequestProcessor.threadNameList.remove(cacheKey); + RecordInfoResponseMessageHandler.threadNameList.remove(cacheKey); } public void setRedis(RedisUtil redis) { diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/callback/DeferredResultHolder.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/callback/DeferredResultHolder.java index ecfa6665d..51d03b46b 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/callback/DeferredResultHolder.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/callback/DeferredResultHolder.java @@ -11,7 +11,7 @@ import org.springframework.stereotype.Component; import org.springframework.web.context.request.async.DeferredResult; /** - * @Description: 异步请求处理 + * @description: 异步请求处理 * @author: swwheihei * @date: 2020年5月8日 下午7:59:05 */ diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/callback/RequestMessage.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/callback/RequestMessage.java index 5a3ae37c9..42ae577ad 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/callback/RequestMessage.java +++ b/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 */ diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java index 10611dc4c..9f4137796 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java @@ -7,7 +7,7 @@ import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; import com.genersoft.iot.vmp.service.bean.SSRCInfo; /** - * @Description:设备能力接口,用于定义设备的控制、查询能力 + * @description:设备能力接口,用于定义设备的控制、查询能力 * @author: swwheihei * @date: 2020年5月3日 下午9:16:34 */ @@ -299,4 +299,11 @@ public interface ISIPCommander { * @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); } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderPlarformProvider.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderPlarformProvider.java index 4ed942cdb..cc41af7cb 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderPlarformProvider.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderPlarformProvider.java @@ -19,7 +19,7 @@ import java.util.List; import java.util.UUID; /** - * @Description: 平台命令request创造器 TODO 冗余代码太多待优化 + * @description: 平台命令request创造器 TODO 冗余代码太多待优化 * @author: panll * @date: 2020年5月6日 上午9:29:02 */ diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderProvider.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderProvider.java index 48facf65e..bb62902a3 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderProvider.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderProvider.java @@ -18,7 +18,7 @@ import com.genersoft.iot.vmp.conf.SipConfig; import com.genersoft.iot.vmp.gb28181.bean.Device; /** - * @Description:摄像头命令request创造器 TODO 冗余代码太多待优化 + * @description:摄像头命令request创造器 TODO 冗余代码太多待优化 * @author: swwheihei * @date: 2020年5月6日 上午9:29:02 */ diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java index 0d36d527c..7a0e901fe 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java +++ b/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.slf4j.LoggerFactory; 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 @@ public class SIPCommander implements ISIPCommander { @Autowired private SipConfig sipConfig; - @Lazy @Autowired @Qualifier(value="tcpSipProvider") private SipProviderImpl tcpSipProvider; - @Lazy @Autowired @Qualifier(value="udpSipProvider") private SipProviderImpl udpSipProvider; @@ -89,11 +84,6 @@ public class SIPCommander implements ISIPCommander { @Autowired private IMediaServerService mediaServerService; - private SIPDialog dialog; - - public SipConfig getSipConfig() { - return sipConfig; - } /** * 云台方向放控制,使用配置文件中的默认镜头移动速度 @@ -1490,6 +1480,33 @@ public class SIPCommander implements ISIPCommander { } } + @Override + public boolean catalogSubscribe(Device device, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) { + try { + StringBuffer cmdXml = new StringBuffer(200); + cmdXml.append("\r\n"); + cmdXml.append("\r\n"); + cmdXml.append("CataLog\r\n"); + cmdXml.append("" + (int)((Math.random()*9+1)*100000) + "\r\n"); + cmdXml.append("" + device.getDeviceId() + "\r\n"); + cmdXml.append("\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); diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/ISIPRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/ISIPRequestProcessor.java new file mode 100644 index 000000000..8e79941f9 --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/ISIPRequestProcessor.java @@ -0,0 +1,14 @@ +package com.genersoft.iot.vmp.gb28181.transmit.event.request; + +import javax.sip.RequestEvent; + +/** + * @description: 对SIP事件进行处理,包括request, response, timeout, ioException, transactionTerminated,dialogTerminated + * @author: panlinlin + * @date: 2021年11月5日 15:47 + */ +public interface ISIPRequestProcessor { + + void process(RequestEvent event); + +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/SIPRequestProcessorAbstract.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/SIPRequestProcessorAbstract.java new file mode 100644 index 000000000..dd098f7b9 --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/SIPRequestProcessorAbstract.java @@ -0,0 +1,23 @@ +package com.genersoft.iot.vmp.gb28181.transmit.event.request; + +import gov.nist.javax.sip.SipProviderImpl; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; + +/** + * @description:处理接收IPCamera发来的SIP协议请求消息 + * @author: songww + * @date: 2020年5月3日 下午4:42:22 + */ +public abstract class SIPRequestProcessorAbstract { + + + @Autowired + @Qualifier(value="tcpSipProvider") + private SipProviderImpl tcpSipProvider; + + @Autowired + @Qualifier(value="udpSipProvider") + private SipProviderImpl udpSipProvider; + +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/SIPRequestProcessorParent.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/SIPRequestProcessorParent.java new file mode 100644 index 000000000..d6d3dd709 --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/SIPRequestProcessorParent.java @@ -0,0 +1,179 @@ +package com.genersoft.iot.vmp.gb28181.transmit.event.request; + +import gov.nist.javax.sip.SipProviderImpl; +import gov.nist.javax.sip.SipStackImpl; +import gov.nist.javax.sip.message.SIPRequest; +import gov.nist.javax.sip.stack.SIPServerTransaction; +import org.dom4j.Document; +import org.dom4j.DocumentException; +import org.dom4j.Element; +import org.dom4j.io.SAXReader; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; + +import javax.sip.*; +import javax.sip.address.Address; +import javax.sip.address.AddressFactory; +import javax.sip.address.SipURI; +import javax.sip.header.ContentTypeHeader; +import javax.sip.header.HeaderFactory; +import javax.sip.header.ViaHeader; +import javax.sip.message.MessageFactory; +import javax.sip.message.Request; +import javax.sip.message.Response; +import java.io.ByteArrayInputStream; +import java.text.ParseException; + +/** + * @description:处理接收IPCamera发来的SIP协议请求消息 + * @author: songww + * @date: 2020年5月3日 下午4:42:22 + */ +public abstract class SIPRequestProcessorParent { + + private final static Logger logger = LoggerFactory.getLogger(SIPRequestProcessorParent.class); + + @Autowired + @Qualifier(value="tcpSipProvider") + private SipProviderImpl tcpSipProvider; + + @Autowired + @Qualifier(value="udpSipProvider") + private SipProviderImpl udpSipProvider; + + /** + * 根据 RequestEvent 获取 ServerTransaction + * @param evt + * @return + */ + public ServerTransaction getServerTransaction(RequestEvent evt) { + Request request = evt.getRequest(); + ServerTransaction serverTransaction = evt.getServerTransaction(); + // 判断TCP还是UDP + boolean isTcp = false; + ViaHeader reqViaHeader = (ViaHeader) request.getHeader(ViaHeader.NAME); + String transport = reqViaHeader.getTransport(); + if (transport.equals("TCP")) { + isTcp = true; + } + + if (serverTransaction == null) { + try { + if (isTcp) { + SipStackImpl stack = (SipStackImpl)tcpSipProvider.getSipStack(); + serverTransaction = (SIPServerTransaction) stack.findTransaction((SIPRequest)request, true); + if (serverTransaction == null) { + serverTransaction = tcpSipProvider.getNewServerTransaction(request); + } + } else { + SipStackImpl stack = (SipStackImpl)udpSipProvider.getSipStack(); + serverTransaction = (SIPServerTransaction) stack.findTransaction((SIPRequest)request, true); + if (serverTransaction == null) { + serverTransaction = udpSipProvider.getNewServerTransaction(request); + } + } + } catch (TransactionAlreadyExistsException e) { + logger.error(e.getMessage()); + } catch (TransactionUnavailableException e) { + logger.error(e.getMessage()); + } + } + return serverTransaction; + } + + public AddressFactory getAddressFactory() { + try { + return SipFactory.getInstance().createAddressFactory(); + } catch (PeerUnavailableException e) { + e.printStackTrace(); + } + return null; + } + + public HeaderFactory getHeaderFactory() { + try { + return SipFactory.getInstance().createHeaderFactory(); + } catch (PeerUnavailableException e) { + e.printStackTrace(); + } + return null; + } + + public MessageFactory getMessageFactory() { + try { + return SipFactory.getInstance().createMessageFactory(); + } catch (PeerUnavailableException e) { + e.printStackTrace(); + } + return null; + } + + /*** + * 回复状态码 + * 100 trying + * 200 OK + * 400 + * 404 + * @param evt + * @throws SipException + * @throws InvalidArgumentException + * @throws ParseException + */ + public void responseAck(RequestEvent evt, int statusCode) throws SipException, InvalidArgumentException, ParseException { + Response response = getMessageFactory().createResponse(statusCode, evt.getRequest()); + ServerTransaction serverTransaction = getServerTransaction(evt); + serverTransaction.sendResponse(response); + if (statusCode >= 200 && !"NOTIFY".equals(evt.getRequest().getMethod())) { + + if (serverTransaction.getDialog() != null) serverTransaction.getDialog().delete(); + } + } + + public void responseAck(RequestEvent evt, int statusCode, String msg) throws SipException, InvalidArgumentException, ParseException { + Response response = getMessageFactory().createResponse(statusCode, evt.getRequest()); + response.setReasonPhrase(msg); + ServerTransaction serverTransaction = getServerTransaction(evt); + serverTransaction.sendResponse(response); + if (statusCode >= 200 && !"NOTIFY".equals(evt.getRequest().getMethod())) { + if (serverTransaction.getDialog() != null) serverTransaction.getDialog().delete(); + } + } + + /** + * 回复带sdp的200 + * @param evt + * @param sdp + * @throws SipException + * @throws InvalidArgumentException + * @throws ParseException + */ + public void responseAck(RequestEvent evt, String sdp) throws SipException, InvalidArgumentException, ParseException { + Response response = getMessageFactory().createResponse(Response.OK, evt.getRequest()); + SipFactory sipFactory = SipFactory.getInstance(); + ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader("APPLICATION", "SDP"); + response.setContent(sdp, contentTypeHeader); + + SipURI sipURI = (SipURI)evt.getRequest().getRequestURI(); + + Address concatAddress = sipFactory.createAddressFactory().createAddress( + sipFactory.createAddressFactory().createSipURI(sipURI.getUser(), sipURI.getHost()+":"+sipURI.getPort() + )); + response.addHeader(sipFactory.createHeaderFactory().createContactHeader(concatAddress)); + getServerTransaction(evt).sendResponse(response); + } + + public Element getRootElement(RequestEvent evt) throws DocumentException { + return getRootElement(evt, "gb2312"); + } + public Element getRootElement(RequestEvent evt, String charset) throws DocumentException { + if (charset == null) charset = "gb2312"; + Request request = evt.getRequest(); + SAXReader reader = new SAXReader(); + reader.setEncoding(charset); + Document xml = reader.read(new ByteArrayInputStream(request.getRawContent())); + return xml.getRootElement(); + } + +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/AckRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/AckRequestProcessor.java similarity index 68% rename from src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/AckRequestProcessor.java rename to src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/AckRequestProcessor.java index 7d9e5f7b3..8363d6f33 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/AckRequestProcessor.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/AckRequestProcessor.java @@ -1,142 +1,125 @@ -package com.genersoft.iot.vmp.gb28181.transmit.request.impl; - -import java.util.HashMap; -import java.util.Map; - -import javax.sip.*; -import javax.sip.address.SipURI; -import javax.sip.header.FromHeader; -import javax.sip.header.HeaderAddress; -import javax.sip.header.ToHeader; - -import com.genersoft.iot.vmp.common.StreamInfo; -import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem; -import com.genersoft.iot.vmp.gb28181.transmit.request.SIPRequestAbstractProcessor; -import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory; -import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; -import com.genersoft.iot.vmp.service.IMediaServerService; -import com.genersoft.iot.vmp.storager.IRedisCatchStorage; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * @Description:ACK请求处理器 - * @author: swwheihei - * @date: 2020年5月3日 下午5:31:45 - */ -public class AckRequestProcessor extends SIPRequestAbstractProcessor { - - private Logger logger = LoggerFactory.getLogger(AckRequestProcessor.class); - - private IRedisCatchStorage redisCatchStorage; - - private ZLMRTPServerFactory zlmrtpServerFactory; - - private IMediaServerService mediaServerService; - - /** - * 处理 ACK请求 - * - * @param evt - */ - @Override - public void process(RequestEvent evt) { - //Request request = evt.getRequest(); - Dialog dialog = evt.getDialog(); - if (dialog == null) return; - //DialogState state = dialog.getState(); - if (/*request.getMecodewwthod().equals(Request.INVITE) &&*/ dialog.getState()== DialogState.CONFIRMED) { - String platformGbId = ((SipURI) ((HeaderAddress) evt.getRequest().getHeader(FromHeader.NAME)).getAddress().getURI()).getUser(); - String channelId = ((SipURI) ((HeaderAddress) evt.getRequest().getHeader(ToHeader.NAME)).getAddress().getURI()).getUser(); - SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(platformGbId, channelId); - String is_Udp = sendRtpItem.isTcp() ? "0" : "1"; - String deviceId = sendRtpItem.getDeviceId(); - StreamInfo streamInfo = null; - if (deviceId == null) { - streamInfo = new StreamInfo(); - streamInfo.setApp(sendRtpItem.getApp()); - streamInfo.setStreamId(sendRtpItem.getStreamId()); - }else { - streamInfo = redisCatchStorage.queryPlayByDevice(deviceId, channelId); - sendRtpItem.setStreamId(streamInfo.getStreamId()); - streamInfo.setApp("rtp"); - } - - redisCatchStorage.updateSendRTPSever(sendRtpItem); - logger.info(platformGbId); - logger.info(channelId); - Map param = new HashMap<>(); - param.put("vhost","__defaultVhost__"); - param.put("app",streamInfo.getApp()); - param.put("stream",streamInfo.getStreamId()); - param.put("ssrc", sendRtpItem.getSsrc()); - param.put("dst_url",sendRtpItem.getIp()); - param.put("dst_port", sendRtpItem.getPort()); - param.put("is_udp", is_Udp); - //param.put ("src_port", sendRtpItem.getLocalPort()); - // 设备推流查询,成功后才能转推 - boolean rtpPushed = false; - long startTime = System.currentTimeMillis(); - while (!rtpPushed) { - try { - if (System.currentTimeMillis() - startTime < 30 * 1000) { - MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId()); - if (zlmrtpServerFactory.isStreamReady(mediaInfo, streamInfo.getApp(), streamInfo.getStreamId())) { - rtpPushed = true; - logger.info("已获取设备推流[{}/{}],开始向上级推流[{}:{}]", - streamInfo.getApp() ,streamInfo.getStreamId(), sendRtpItem.getIp(), sendRtpItem.getPort()); - zlmrtpServerFactory.startSendRtpStream(mediaInfo, param); - } else { - logger.info("等待设备推流[{}/{}].......", - streamInfo.getApp() ,streamInfo.getStreamId()); - Thread.sleep(1000); - continue; - } - } else { - rtpPushed = true; - logger.info("设备推流[{}/{}]超时,终止向上级推流", - streamInfo.getApp() ,streamInfo.getStreamId()); - } - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - } - // try { - // Request ackRequest = null; - // CSeq csReq = (CSeq) request.getHeader(CSeq.NAME); - // ackRequest = dialog.createAck(csReq.getSeqNumber()); - // dialog.sendAck(ackRequest); - // logger.info("send ack to callee:" + ackRequest.toString()); - // } catch (SipException e) { - // e.printStackTrace(); - // } catch (InvalidArgumentException e) { - // e.printStackTrace(); - // } - - } - - public IRedisCatchStorage getRedisCatchStorage() { - return redisCatchStorage; - } - - public void setRedisCatchStorage(IRedisCatchStorage redisCatchStorage) { - this.redisCatchStorage = redisCatchStorage; - } - - public ZLMRTPServerFactory getZlmrtpServerFactory() { - return zlmrtpServerFactory; - } - - public void setZlmrtpServerFactory(ZLMRTPServerFactory zlmrtpServerFactory) { - this.zlmrtpServerFactory = zlmrtpServerFactory; - } - - public IMediaServerService getMediaServerService() { - return mediaServerService; - } - - public void setMediaServerService(IMediaServerService mediaServerService) { - this.mediaServerService = mediaServerService; - } -} +package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl; + +import com.genersoft.iot.vmp.common.StreamInfo; +import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem; +import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver; +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.ZLMRTPServerFactory; +import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; +import com.genersoft.iot.vmp.service.IMediaServerService; +import com.genersoft.iot.vmp.storager.IRedisCatchStorage; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import javax.sip.Dialog; +import javax.sip.DialogState; +import javax.sip.RequestEvent; +import javax.sip.address.SipURI; +import javax.sip.header.FromHeader; +import javax.sip.header.HeaderAddress; +import javax.sip.header.ToHeader; +import java.util.HashMap; +import java.util.Map; + +/** + * @description:ACK请求处理器 + * @author: swwheihei + * @date: 2020年5月3日 下午5:31:45 + */ +@Component +public class AckRequestProcessor extends SIPRequestProcessorParent implements InitializingBean, ISIPRequestProcessor { + + private Logger logger = LoggerFactory.getLogger(AckRequestProcessor.class); + private String method = "ACK"; + + @Autowired + private SIPProcessorObserver sipProcessorObserver; + + @Override + public void afterPropertiesSet() throws Exception { + // 添加消息处理的订阅 + sipProcessorObserver.addRequestProcessor(method, this); + } + + @Autowired + private IRedisCatchStorage redisCatchStorage; + + @Autowired + private ZLMRTPServerFactory zlmrtpServerFactory; + + @Autowired + private IMediaServerService mediaServerService; + + + /** + * 处理 ACK请求 + * + * @param evt + */ + @Override + public void process(RequestEvent evt) { + Dialog dialog = evt.getDialog(); + if (dialog == null) return; + if (dialog.getState()== DialogState.CONFIRMED) { + String platformGbId = ((SipURI) ((HeaderAddress) evt.getRequest().getHeader(FromHeader.NAME)).getAddress().getURI()).getUser(); + String channelId = ((SipURI) ((HeaderAddress) evt.getRequest().getHeader(ToHeader.NAME)).getAddress().getURI()).getUser(); + SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(platformGbId, channelId); + String is_Udp = sendRtpItem.isTcp() ? "0" : "1"; + String deviceId = sendRtpItem.getDeviceId(); + StreamInfo streamInfo = null; + if (deviceId == null) { + streamInfo = new StreamInfo(); + streamInfo.setApp(sendRtpItem.getApp()); + streamInfo.setStreamId(sendRtpItem.getStreamId()); + }else { + streamInfo = redisCatchStorage.queryPlayByDevice(deviceId, channelId); + sendRtpItem.setStreamId(streamInfo.getStreamId()); + streamInfo.setApp("rtp"); + } + + redisCatchStorage.updateSendRTPSever(sendRtpItem); + logger.info(platformGbId); + logger.info(channelId); + Map param = new HashMap<>(); + param.put("vhost","__defaultVhost__"); + param.put("app",streamInfo.getApp()); + param.put("stream",streamInfo.getStreamId()); + param.put("ssrc", sendRtpItem.getSsrc()); + param.put("dst_url",sendRtpItem.getIp()); + param.put("dst_port", sendRtpItem.getPort()); + param.put("is_udp", is_Udp); + //param.put ("src_port", sendRtpItem.getLocalPort()); + // 设备推流查询,成功后才能转推 + boolean rtpPushed = false; + long startTime = System.currentTimeMillis(); + while (!rtpPushed) { + try { + if (System.currentTimeMillis() - startTime < 30 * 1000) { + MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId()); + if (zlmrtpServerFactory.isStreamReady(mediaInfo, streamInfo.getApp(), streamInfo.getStreamId())) { + rtpPushed = true; + logger.info("已获取设备推流[{}/{}],开始向上级推流[{}:{}]", + streamInfo.getApp() ,streamInfo.getStreamId(), sendRtpItem.getIp(), sendRtpItem.getPort()); + zlmrtpServerFactory.startSendRtpStream(mediaInfo, param); + } else { + logger.info("等待设备推流[{}/{}].......", + streamInfo.getApp() ,streamInfo.getStreamId()); + Thread.sleep(1000); + continue; + } + } else { + rtpPushed = true; + logger.info("设备推流[{}/{}]超时,终止向上级推流", + streamInfo.getApp() ,streamInfo.getStreamId()); + } + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + } +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/ByeRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/ByeRequestProcessor.java similarity index 63% rename from src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/ByeRequestProcessor.java rename to src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/ByeRequestProcessor.java index a1640773c..c97b55a21 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/ByeRequestProcessor.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/ByeRequestProcessor.java @@ -1,150 +1,117 @@ -package com.genersoft.iot.vmp.gb28181.transmit.request.impl; - -import javax.sip.*; -import javax.sip.address.SipURI; -import javax.sip.header.FromHeader; -import javax.sip.header.HeaderAddress; -import javax.sip.header.ToHeader; -import javax.sip.message.Response; - -import com.genersoft.iot.vmp.common.StreamInfo; -import com.genersoft.iot.vmp.gb28181.bean.Device; -import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem; -import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander; -import com.genersoft.iot.vmp.gb28181.transmit.request.SIPRequestAbstractProcessor; -import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory; -import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; -import com.genersoft.iot.vmp.service.IMediaServerService; -import com.genersoft.iot.vmp.storager.IRedisCatchStorage; -import com.genersoft.iot.vmp.storager.IVideoManagerStorager; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.text.ParseException; -import java.util.HashMap; -import java.util.Map; - -/** - * @Description: BYE请求处理器 - * @author: lawrencehj - * @date: 2021年3月9日 - */ -public class ByeRequestProcessor extends SIPRequestAbstractProcessor { - - private Logger logger = LoggerFactory.getLogger(ByeRequestProcessor.class); - - private ISIPCommander cmder; - - private IRedisCatchStorage redisCatchStorage; - - private IVideoManagerStorager storager; - - private ZLMRTPServerFactory zlmrtpServerFactory; - - private IMediaServerService mediaServerService; - - /** - * 处理BYE请求 - * @param evt - */ - @Override - public void process(RequestEvent evt) { - try { - responseAck(evt); - Dialog dialog = evt.getDialog(); - if (dialog == null) return; - if (dialog.getState().equals(DialogState.TERMINATED)) { - String platformGbId = ((SipURI) ((HeaderAddress) evt.getRequest().getHeader(FromHeader.NAME)).getAddress().getURI()).getUser(); - String channelId = ((SipURI) ((HeaderAddress) evt.getRequest().getHeader(ToHeader.NAME)).getAddress().getURI()).getUser(); - SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(platformGbId, channelId); - logger.info("收到bye, [{}/{}]", platformGbId, channelId); - if (sendRtpItem != null){ - String streamId = sendRtpItem.getStreamId(); - Map param = new HashMap<>(); - param.put("vhost","__defaultVhost__"); - param.put("app",sendRtpItem.getApp()); - param.put("stream",streamId); - param.put("ssrc",sendRtpItem.getSsrc()); - logger.info("停止向上级推流:" + streamId); - MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId()); - zlmrtpServerFactory.stopSendRtpStream(mediaInfo, param); - redisCatchStorage.deleteSendRTPServer(platformGbId, channelId); - if (zlmrtpServerFactory.totalReaderCount(mediaInfo, sendRtpItem.getApp(), streamId) == 0) { - logger.info(streamId + "无其它观看者,通知设备停止推流"); - cmder.streamByeCmd(sendRtpItem.getDeviceId(), channelId); - } - } - // 可能是设备主动停止 - Device device = storager.queryVideoDeviceByChannelId(platformGbId); - if (device != null) { - StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(device.getDeviceId(), channelId); - if (streamInfo != null) { - redisCatchStorage.stopPlay(streamInfo); - } - storager.stopPlay(device.getDeviceId(), channelId); - mediaServerService.closeRTPServer(device, channelId); - } - } - } catch (SipException e) { - e.printStackTrace(); - } catch (InvalidArgumentException e) { - e.printStackTrace(); - } catch (ParseException e) { - e.printStackTrace(); - } - } - - /*** - * 回复200 OK - * @param evt - * @throws SipException - * @throws InvalidArgumentException - * @throws ParseException - */ - private void responseAck(RequestEvent evt) throws SipException, InvalidArgumentException, ParseException { - Response response = getMessageFactory().createResponse(Response.OK, evt.getRequest()); - ServerTransaction serverTransaction = getServerTransaction(evt); - serverTransaction.sendResponse(response); - if (serverTransaction.getDialog() != null) serverTransaction.getDialog().delete(); - } - - public IRedisCatchStorage getRedisCatchStorage() { - return redisCatchStorage; - } - - public void setRedisCatchStorage(IRedisCatchStorage redisCatchStorage) { - this.redisCatchStorage = redisCatchStorage; - } - - public ZLMRTPServerFactory getZlmrtpServerFactory() { - return zlmrtpServerFactory; - } - - public void setZlmrtpServerFactory(ZLMRTPServerFactory zlmrtpServerFactory) { - this.zlmrtpServerFactory = zlmrtpServerFactory; - } - - public ISIPCommander getSIPCommander() { - return cmder; - } - - public void setSIPCommander(ISIPCommander cmder) { - this.cmder = cmder; - } - - public IMediaServerService getMediaServerService() { - return mediaServerService; - } - - public void setMediaServerService(IMediaServerService mediaServerService) { - this.mediaServerService = mediaServerService; - } - - public IVideoManagerStorager getStorager() { - return storager; - } - - public void setStorager(IVideoManagerStorager storager) { - this.storager = storager; - } -} +package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl; + +import com.genersoft.iot.vmp.common.StreamInfo; +import com.genersoft.iot.vmp.gb28181.bean.Device; +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.event.request.ISIPRequestProcessor; +import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent; +import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory; +import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; +import com.genersoft.iot.vmp.service.IMediaServerService; +import com.genersoft.iot.vmp.storager.IRedisCatchStorage; +import com.genersoft.iot.vmp.storager.IVideoManagerStorager; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import javax.sip.*; +import javax.sip.address.SipURI; +import javax.sip.header.FromHeader; +import javax.sip.header.HeaderAddress; +import javax.sip.header.ToHeader; +import javax.sip.message.Response; +import java.text.ParseException; +import java.util.HashMap; +import java.util.Map; + +/** + * @description: BYE请求处理器 + * @author: lawrencehj + * @date: 2021年3月9日 + */ +@Component +public class ByeRequestProcessor extends SIPRequestProcessorParent implements InitializingBean, ISIPRequestProcessor { + + private Logger logger = LoggerFactory.getLogger(ByeRequestProcessor.class); + + @Autowired + private ISIPCommander cmder; + + @Autowired + private IRedisCatchStorage redisCatchStorage; + + @Autowired + private IVideoManagerStorager storager; + + @Autowired + private ZLMRTPServerFactory zlmrtpServerFactory; + + @Autowired + private IMediaServerService mediaServerService; + + private String method = "BYE"; + + @Autowired + private SIPProcessorObserver sipProcessorObserver; + + @Override + public void afterPropertiesSet() throws Exception { + // 添加消息处理的订阅 + sipProcessorObserver.addRequestProcessor(method, this); + } + + /** + * 处理BYE请求 + * @param evt + */ + @Override + public void process(RequestEvent evt) { + try { + responseAck(evt, Response.OK); + Dialog dialog = evt.getDialog(); + if (dialog == null) return; + if (dialog.getState().equals(DialogState.TERMINATED)) { + String platformGbId = ((SipURI) ((HeaderAddress) evt.getRequest().getHeader(FromHeader.NAME)).getAddress().getURI()).getUser(); + String channelId = ((SipURI) ((HeaderAddress) evt.getRequest().getHeader(ToHeader.NAME)).getAddress().getURI()).getUser(); + SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(platformGbId, channelId); + logger.info("收到bye, [{}/{}]", platformGbId, channelId); + if (sendRtpItem != null){ + String streamId = sendRtpItem.getStreamId(); + Map param = new HashMap<>(); + param.put("vhost","__defaultVhost__"); + param.put("app",sendRtpItem.getApp()); + param.put("stream",streamId); + param.put("ssrc",sendRtpItem.getSsrc()); + logger.info("停止向上级推流:" + streamId); + MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId()); + zlmrtpServerFactory.stopSendRtpStream(mediaInfo, param); + redisCatchStorage.deleteSendRTPServer(platformGbId, channelId); + if (zlmrtpServerFactory.totalReaderCount(mediaInfo, sendRtpItem.getApp(), streamId) == 0) { + logger.info(streamId + "无其它观看者,通知设备停止推流"); + cmder.streamByeCmd(sendRtpItem.getDeviceId(), channelId); + } + } + // 可能是设备主动停止 + Device device = storager.queryVideoDeviceByChannelId(platformGbId); + if (device != null) { + StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(device.getDeviceId(), channelId); + if (streamInfo != null) { + redisCatchStorage.stopPlay(streamInfo); + } + storager.stopPlay(device.getDeviceId(), channelId); + mediaServerService.closeRTPServer(device, channelId); + } + } + } catch (SipException e) { + e.printStackTrace(); + } catch (InvalidArgumentException e) { + e.printStackTrace(); + } catch (ParseException e) { + e.printStackTrace(); + } + } +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/CancelRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/CancelRequestProcessor.java new file mode 100644 index 000000000..2e98e335f --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/CancelRequestProcessor.java @@ -0,0 +1,42 @@ +package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl; + +import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver; +import com.genersoft.iot.vmp.gb28181.transmit.event.request.ISIPRequestProcessor; +import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import javax.sip.RequestEvent; + +/** + * @description:CANCEL请求处理器 + * @author: swwheihei + * @date: 2020年5月3日 下午5:32:23 + */ +@Component +public class CancelRequestProcessor extends SIPRequestProcessorParent implements InitializingBean, ISIPRequestProcessor { + + private String method = "CANCEL"; + + @Autowired + private SIPProcessorObserver sipProcessorObserver; + + @Override + public void afterPropertiesSet() throws Exception { + // 添加消息处理的订阅 + sipProcessorObserver.addRequestProcessor(method, this); + } + + /** + * 处理CANCEL请求 + * + * @param evt 事件 + */ + @Override + public void process(RequestEvent evt) { + // TODO 优先级99 Cancel Request消息实现,此消息一般为级联消息,上级给下级发送请求取消指令 + + } + +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/InviteRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java similarity index 76% rename from src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/InviteRequestProcessor.java rename to src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java index a2bda77fa..5eda75dda 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/InviteRequestProcessor.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java @@ -1,478 +1,388 @@ -package com.genersoft.iot.vmp.gb28181.transmit.request.impl; - -import javax.sdp.*; -import javax.sip.*; -import javax.sip.address.Address; -import javax.sip.address.SipURI; -import javax.sip.header.*; -import javax.sip.message.Request; -import javax.sip.message.Response; - -import com.genersoft.iot.vmp.gb28181.bean.*; -import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; -import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform; -import com.genersoft.iot.vmp.gb28181.transmit.request.SIPRequestAbstractProcessor; -import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory; -import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; -import com.genersoft.iot.vmp.service.IMediaServerService; -import com.genersoft.iot.vmp.storager.IRedisCatchStorage; -import com.genersoft.iot.vmp.storager.IVideoManagerStorager; -import com.genersoft.iot.vmp.vmanager.gb28181.play.bean.PlayResult; -import com.genersoft.iot.vmp.service.IPlayService; -import gov.nist.javax.sip.address.AddressImpl; -import gov.nist.javax.sip.address.SipUri; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.text.ParseException; -import java.util.Vector; - -/** - * @Description:处理INVITE请求 - * @author: panll - * @date: 2021年1月14日 - */ -@SuppressWarnings("rawtypes") -public class InviteRequestProcessor extends SIPRequestAbstractProcessor { - - private final static Logger logger = LoggerFactory.getLogger(InviteRequestProcessor.class); - - private SIPCommanderFroPlatform cmderFroPlatform; - - private IVideoManagerStorager storager; - - private IRedisCatchStorage redisCatchStorage; - - private SIPCommander cmder; - - private IPlayService playService; - - private ZLMRTPServerFactory zlmrtpServerFactory; - - private IMediaServerService mediaServerService; - - public ZLMRTPServerFactory getZlmrtpServerFactory() { - return zlmrtpServerFactory; - } - - public void setZlmrtpServerFactory(ZLMRTPServerFactory zlmrtpServerFactory) { - this.zlmrtpServerFactory = zlmrtpServerFactory; - } - - /** - * 处理invite请求 - * - * @param evt - * 请求消息 - */ - @Override - public void process(RequestEvent evt) { - // Invite Request消息实现,此消息一般为级联消息,上级给下级发送请求视频指令 - try { - Request request = evt.getRequest(); - SipURI sipURI = (SipURI) request.getRequestURI(); - String channelId = sipURI.getUser(); - String requesterId = null; - - FromHeader fromHeader = (FromHeader)request.getHeader(FromHeader.NAME); - AddressImpl address = (AddressImpl) fromHeader.getAddress(); - SipUri uri = (SipUri) address.getURI(); - requesterId = uri.getUser(); - - if (requesterId == null || channelId == null) { - logger.info("无法从FromHeader的Address中获取到平台id,返回400"); - responseAck(evt, Response.BAD_REQUEST); // 参数不全, 发400,请求错误 - return; - } - - // 查询请求方是否上级平台 - ParentPlatform platform = storager.queryParentPlatByServerGBId(requesterId); - if (platform != null) { - // 查询平台下是否有该通道 - DeviceChannel channel = storager.queryChannelInParentPlatform(requesterId, channelId); - GbStream gbStream = storager.queryStreamInParentPlatform(requesterId, channelId); - MediaServerItem mediaServerItem = null; - // 不是通道可能是直播流 - if (channel != null && gbStream == null ) { - if (channel.getStatus() == 0) { - logger.info("通道离线,返回400"); - responseAck(evt, Response.BAD_REQUEST, "channel [" + channel.getChannelId() + "] offline"); - return; - } - responseAck(evt, Response.CALL_IS_BEING_FORWARDED); // 通道存在,发181,呼叫转接中 - }else if(channel == null && gbStream != null){ - String mediaServerId = gbStream.getMediaServerId(); - mediaServerItem = mediaServerService.getOne(mediaServerId); - if (mediaServerItem == null) { - logger.info("[ app={}, stream={} ]找不到zlm {},返回410",gbStream.getApp(), gbStream.getStream(), mediaServerId); - responseAck(evt, Response.GONE, "media server not found"); - return; - } - Boolean streamReady = zlmrtpServerFactory.isStreamReady(mediaServerItem, gbStream.getApp(), gbStream.getStream()); - if (!streamReady ) { - logger.info("[ app={}, stream={} ]通道离线,返回400",gbStream.getApp(), gbStream.getStream()); - responseAck(evt, Response.BAD_REQUEST, "channel [" + gbStream.getGbId() + "] offline"); - return; - } - responseAck(evt, Response.CALL_IS_BEING_FORWARDED); // 通道存在,发181,呼叫转接中 - }else { - logger.info("通道不存在,返回404"); - responseAck(evt, Response.NOT_FOUND); // 通道不存在,发404,资源不存在 - return; - } - // 解析sdp消息, 使用jainsip 自带的sdp解析方式 - String contentString = new String(request.getRawContent()); - - // jainSip不支持y=字段, 移除移除以解析。 - int ssrcIndex = contentString.indexOf("y="); - //ssrc规定长度为10字节,不取余下长度以避免后续还有“f=”字段 - String ssrc = contentString.substring(ssrcIndex + 2, ssrcIndex + 12); - String substring = contentString.substring(0, contentString.indexOf("y=")); - SessionDescription sdp = SdpFactory.getInstance().createSessionDescription(substring); - - // 获取支持的格式 - Vector mediaDescriptions = sdp.getMediaDescriptions(true); - // 查看是否支持PS 负载96 - //String ip = null; - int port = -1; - //boolean recvonly = false; - boolean mediaTransmissionTCP = false; - Boolean tcpActive = null; - for (Object description : mediaDescriptions) { - MediaDescription mediaDescription = (MediaDescription) description; - Media media = mediaDescription.getMedia(); - - Vector mediaFormats = media.getMediaFormats(false); - if (mediaFormats.contains("96")) { - port = media.getMediaPort(); - //String mediaType = media.getMediaType(); - String protocol = media.getProtocol(); - - // 区分TCP发流还是udp, 当前默认udp - if ("TCP/RTP/AVP".equals(protocol)) { - String setup = mediaDescription.getAttribute("setup"); - if (setup != null) { - mediaTransmissionTCP = true; - if ("active".equals(setup)) { - tcpActive = true; - } else if ("passive".equals(setup)) { - tcpActive = false; - } - } - } - break; - } - } - if (port == -1) { - logger.info("不支持的媒体格式,返回415"); - // 回复不支持的格式 - responseAck(evt, Response.UNSUPPORTED_MEDIA_TYPE); // 不支持的格式,发415 - return; - } - String username = sdp.getOrigin().getUsername(); - String addressStr = sdp.getOrigin().getAddress(); - //String sessionName = sdp.getSessionName().getValue(); - logger.info("[上级点播]用户:{}, 地址:{}:{}, ssrc:{}", username, addressStr, port, ssrc); - Device device = null; - // 通过 channel 和 gbStream 是否为null 值判断来源是直播流合适国标 - if (channel != null) { - device = storager.queryVideoDeviceByPlatformIdAndChannelId(requesterId, channelId); - if (device == null) { - logger.warn("点播平台{}的通道{}时未找到设备信息", requesterId, channel); - responseAck(evt, Response.SERVER_INTERNAL_ERROR); - return; - } - mediaServerItem = playService.getNewMediaServerItem(device); - if (mediaServerItem == null) { - logger.warn("未找到可用的zlm"); - responseAck(evt, Response.BUSY_HERE); - return; - } - SendRtpItem sendRtpItem = zlmrtpServerFactory.createSendRtpItem(mediaServerItem, addressStr, port, ssrc, requesterId, - device.getDeviceId(), channelId, - mediaTransmissionTCP); - if (tcpActive != null) { - sendRtpItem.setTcpActive(tcpActive); - } - if (sendRtpItem == null) { - logger.warn("服务器端口资源不足"); - responseAck(evt, Response.BUSY_HERE); - return; - } - - // 写入redis, 超时时回复 - redisCatchStorage.updateSendRTPSever(sendRtpItem); - // 通知下级推流, - PlayResult playResult = playService.play(mediaServerItem,device.getDeviceId(), channelId, (mediaServerItemInUSe, responseJSON)->{ - // 收到推流, 回复200OK, 等待ack - // if (sendRtpItem == null) return; - sendRtpItem.setStatus(1); - redisCatchStorage.updateSendRTPSever(sendRtpItem); - // TODO 添加对tcp的支持 - - StringBuffer content = new StringBuffer(200); - content.append("v=0\r\n"); - content.append("o="+ channelId +" 0 0 IN IP4 "+mediaServerItemInUSe.getSdpIp()+"\r\n"); - content.append("s=Play\r\n"); - content.append("c=IN IP4 "+mediaServerItemInUSe.getSdpIp()+"\r\n"); - content.append("t=0 0\r\n"); - content.append("m=video "+ sendRtpItem.getLocalPort()+" RTP/AVP 96\r\n"); - content.append("a=sendonly\r\n"); - content.append("a=rtpmap:96 PS/90000\r\n"); - content.append("y="+ ssrc + "\r\n"); - content.append("f=\r\n"); - - try { - responseAck(evt, content.toString()); - } catch (SipException e) { - e.printStackTrace(); - } catch (InvalidArgumentException e) { - e.printStackTrace(); - } catch (ParseException e) { - e.printStackTrace(); - } - } ,((event) -> { - // 未知错误。直接转发设备点播的错误 - Response response = null; - try { - response = getMessageFactory().createResponse(event.statusCode, evt.getRequest()); - ServerTransaction serverTransaction = getServerTransaction(evt); - serverTransaction.sendResponse(response); - if (serverTransaction.getDialog() != null) serverTransaction.getDialog().delete(); - } catch (ParseException | SipException | InvalidArgumentException e) { - e.printStackTrace(); - } - })); - if (logger.isDebugEnabled()) { - logger.debug(playResult.getResult().toString()); - } - - }else if (gbStream != null) { - SendRtpItem sendRtpItem = zlmrtpServerFactory.createSendRtpItem(mediaServerItem, addressStr, port, ssrc, requesterId, - gbStream.getApp(), gbStream.getStream(), channelId, - mediaTransmissionTCP); - - if (tcpActive != null) { - sendRtpItem.setTcpActive(tcpActive); - } - if (sendRtpItem == null) { - logger.warn("服务器端口资源不足"); - responseAck(evt, Response.BUSY_HERE); - return; - } - - // 写入redis, 超时时回复 - redisCatchStorage.updateSendRTPSever(sendRtpItem); - - sendRtpItem.setStatus(1); - redisCatchStorage.updateSendRTPSever(sendRtpItem); - // TODO 添加对tcp的支持 - StringBuffer content = new StringBuffer(200); - content.append("v=0\r\n"); - content.append("o="+ channelId +" 0 0 IN IP4 "+mediaServerItem.getSdpIp()+"\r\n"); - content.append("s=Play\r\n"); - content.append("c=IN IP4 "+mediaServerItem.getSdpIp()+"\r\n"); - content.append("t=0 0\r\n"); - content.append("m=video "+ sendRtpItem.getLocalPort()+" RTP/AVP 96\r\n"); - content.append("a=sendonly\r\n"); - content.append("a=rtpmap:96 PS/90000\r\n"); - content.append("y="+ ssrc + "\r\n"); - content.append("f=\r\n"); - - try { - responseAck(evt, content.toString()); - } catch (SipException e) { - e.printStackTrace(); - } catch (InvalidArgumentException e) { - e.printStackTrace(); - } catch (ParseException e) { - e.printStackTrace(); - } - } - - } else { - // 非上级平台请求,查询是否设备请求(通常为接收语音广播的设备) - Device device = storager.queryVideoDevice(requesterId); - if (device != null) { - logger.info("收到设备" + requesterId + "的语音广播Invite请求"); - responseAck(evt, Response.TRYING); - - String contentString = new String(request.getRawContent()); - // jainSip不支持y=字段, 移除移除以解析。 - String substring = contentString; - String ssrc = "0000000404"; - int ssrcIndex = contentString.indexOf("y="); - if (ssrcIndex > 0) { - substring = contentString.substring(0, ssrcIndex); - ssrc = contentString.substring(ssrcIndex + 2, ssrcIndex + 12); - } - ssrcIndex = substring.indexOf("f="); - if (ssrcIndex > 0) { - substring = contentString.substring(0, ssrcIndex); - } - SessionDescription sdp = SdpFactory.getInstance().createSessionDescription(substring); - - // 获取支持的格式 - Vector mediaDescriptions = sdp.getMediaDescriptions(true); - // 查看是否支持PS 负载96 - int port = -1; - //boolean recvonly = false; - boolean mediaTransmissionTCP = false; - Boolean tcpActive = null; - for (int i = 0; i < mediaDescriptions.size(); i++) { - MediaDescription mediaDescription = (MediaDescription)mediaDescriptions.get(i); - Media media = mediaDescription.getMedia(); - - Vector mediaFormats = media.getMediaFormats(false); - if (mediaFormats.contains("8")) { - port = media.getMediaPort(); - String protocol = media.getProtocol(); - // 区分TCP发流还是udp, 当前默认udp - if ("TCP/RTP/AVP".equals(protocol)) { - String setup = mediaDescription.getAttribute("setup"); - if (setup != null) { - mediaTransmissionTCP = true; - if ("active".equals(setup)) { - tcpActive = true; - } else if ("passive".equals(setup)) { - tcpActive = false; - } - } - } - break; - } - } - if (port == -1) { - logger.info("不支持的媒体格式,返回415"); - // 回复不支持的格式 - responseAck(evt, Response.UNSUPPORTED_MEDIA_TYPE); // 不支持的格式,发415 - return; - } - String username = sdp.getOrigin().getUsername(); - String addressStr = sdp.getOrigin().getAddress(); - logger.info("设备{}请求语音流,地址:{}:{},ssrc:{}", username, addressStr, port, ssrc); - - } else { - logger.warn("来自无效设备/平台的请求"); - responseAck(evt, Response.BAD_REQUEST); - } - } - - } catch (SipException | InvalidArgumentException | ParseException e) { - e.printStackTrace(); - logger.warn("sdp解析错误"); - e.printStackTrace(); - } catch (SdpParseException e) { - e.printStackTrace(); - } catch (SdpException e) { - e.printStackTrace(); - } - } - - - /*** - * 回复状态码 - * 100 trying - * 200 OK - * 400 - * 404 - * @param evt - * @throws SipException - * @throws InvalidArgumentException - * @throws ParseException - */ - private void responseAck(RequestEvent evt, int statusCode) throws SipException, InvalidArgumentException, ParseException { - Response response = getMessageFactory().createResponse(statusCode, evt.getRequest()); - ServerTransaction serverTransaction = getServerTransaction(evt); - serverTransaction.sendResponse(response); - if (statusCode >= 200) { - if (serverTransaction.getDialog() != null) serverTransaction.getDialog().delete(); - } - } - - private void responseAck(RequestEvent evt, int statusCode, String msg) throws SipException, InvalidArgumentException, ParseException { - Response response = getMessageFactory().createResponse(statusCode, evt.getRequest()); - response.setReasonPhrase(msg); - ServerTransaction serverTransaction = getServerTransaction(evt); - serverTransaction.sendResponse(response); - if (statusCode >= 200) { - if (serverTransaction.getDialog() != null) serverTransaction.getDialog().delete(); - } - } - - /** - * 回复带sdp的200 - * @param evt - * @param sdp - * @throws SipException - * @throws InvalidArgumentException - * @throws ParseException - */ - private void responseAck(RequestEvent evt, String sdp) throws SipException, InvalidArgumentException, ParseException { - Response response = getMessageFactory().createResponse(Response.OK, evt.getRequest()); - SipFactory sipFactory = SipFactory.getInstance(); - ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader("APPLICATION", "SDP"); - response.setContent(sdp, contentTypeHeader); - - SipURI sipURI = (SipURI)evt.getRequest().getRequestURI(); - - Address concatAddress = sipFactory.createAddressFactory().createAddress( - sipFactory.createAddressFactory().createSipURI(sipURI.getUser(), sipURI.getHost()+":"+sipURI.getPort() - )); - response.addHeader(sipFactory.createHeaderFactory().createContactHeader(concatAddress)); - getServerTransaction(evt).sendResponse(response); - } - - - - - - - public SIPCommanderFroPlatform getCmderFroPlatform() { - return cmderFroPlatform; - } - - public void setCmderFroPlatform(SIPCommanderFroPlatform cmderFroPlatform) { - this.cmderFroPlatform = cmderFroPlatform; - } - - public IVideoManagerStorager getStorager() { - return storager; - } - - public void setStorager(IVideoManagerStorager storager) { - this.storager = storager; - } - - public SIPCommander getCmder() { - return cmder; - } - - public void setCmder(SIPCommander cmder) { - this.cmder = cmder; - } - - public IPlayService getPlayService() { - return playService; - } - - public void setPlayService(IPlayService playService) { - this.playService = playService; - } - - public IRedisCatchStorage getRedisCatchStorage() { - return redisCatchStorage; - } - - public void setRedisCatchStorage(IRedisCatchStorage redisCatchStorage) { - this.redisCatchStorage = redisCatchStorage; - } - - public IMediaServerService getMediaServerService() { - return mediaServerService; - } - - public void setMediaServerService(IMediaServerService mediaServerService) { - this.mediaServerService = mediaServerService; - } -} +package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl; + +import com.genersoft.iot.vmp.gb28181.bean.*; +import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver; +import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; +import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform; +import com.genersoft.iot.vmp.gb28181.transmit.event.request.ISIPRequestProcessor; +import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent; +import com.genersoft.iot.vmp.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.IPlayService; +import com.genersoft.iot.vmp.storager.IRedisCatchStorage; +import com.genersoft.iot.vmp.storager.IVideoManagerStorager; +import com.genersoft.iot.vmp.vmanager.gb28181.play.bean.PlayResult; +import gov.nist.javax.sip.address.AddressImpl; +import gov.nist.javax.sip.address.SipUri; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import javax.sdp.*; +import javax.sip.InvalidArgumentException; +import javax.sip.RequestEvent; +import javax.sip.ServerTransaction; +import javax.sip.SipException; +import javax.sip.address.SipURI; +import javax.sip.header.FromHeader; +import javax.sip.message.Request; +import javax.sip.message.Response; +import java.text.ParseException; +import java.util.Vector; + +/** + * @description:处理INVITE请求 + * @author: panll + * @date: 2021年1月14日 + */ +@SuppressWarnings("rawtypes") +@Component +public class InviteRequestProcessor extends SIPRequestProcessorParent implements InitializingBean, ISIPRequestProcessor { + + private final static Logger logger = LoggerFactory.getLogger(InviteRequestProcessor.class); + + private String method = "INVITE"; + + @Autowired + private SIPCommanderFroPlatform cmderFroPlatform; + + @Autowired + private IVideoManagerStorager storager; + + @Autowired + private IRedisCatchStorage redisCatchStorage; + + @Autowired + private SIPCommander cmder; + + @Autowired + private IPlayService playService; + + @Autowired + private ZLMRTPServerFactory zlmrtpServerFactory; + + @Autowired + private IMediaServerService mediaServerService; + + @Autowired + private SIPProcessorObserver sipProcessorObserver; + + @Override + public void afterPropertiesSet() throws Exception { + // 添加消息处理的订阅 + sipProcessorObserver.addRequestProcessor(method, this); + } + + /** + * 处理invite请求 + * + * @param evt + * 请求消息 + */ + @Override + public void process(RequestEvent evt) { + // Invite Request消息实现,此消息一般为级联消息,上级给下级发送请求视频指令 + try { + Request request = evt.getRequest(); + SipURI sipURI = (SipURI) request.getRequestURI(); + String channelId = sipURI.getUser(); + String requesterId = null; + + FromHeader fromHeader = (FromHeader)request.getHeader(FromHeader.NAME); + AddressImpl address = (AddressImpl) fromHeader.getAddress(); + SipUri uri = (SipUri) address.getURI(); + requesterId = uri.getUser(); + + if (requesterId == null || channelId == null) { + logger.info("无法从FromHeader的Address中获取到平台id,返回400"); + responseAck(evt, Response.BAD_REQUEST); // 参数不全, 发400,请求错误 + return; + } + + // 查询请求方是否上级平台 + ParentPlatform platform = storager.queryParentPlatByServerGBId(requesterId); + if (platform != null) { + // 查询平台下是否有该通道 + DeviceChannel channel = storager.queryChannelInParentPlatform(requesterId, channelId); + GbStream gbStream = storager.queryStreamInParentPlatform(requesterId, channelId); + MediaServerItem mediaServerItem = null; + // 不是通道可能是直播流 + if (channel != null && gbStream == null ) { + if (channel.getStatus() == 0) { + logger.info("通道离线,返回400"); + responseAck(evt, Response.BAD_REQUEST, "channel [" + channel.getChannelId() + "] offline"); + return; + } + responseAck(evt, Response.CALL_IS_BEING_FORWARDED); // 通道存在,发181,呼叫转接中 + }else if(channel == null && gbStream != null){ + String mediaServerId = gbStream.getMediaServerId(); + mediaServerItem = mediaServerService.getOne(mediaServerId); + if (mediaServerItem == null) { + logger.info("[ app={}, stream={} ]找不到zlm {},返回410",gbStream.getApp(), gbStream.getStream(), mediaServerId); + responseAck(evt, Response.GONE, "media server not found"); + return; + } + Boolean streamReady = zlmrtpServerFactory.isStreamReady(mediaServerItem, gbStream.getApp(), gbStream.getStream()); + if (!streamReady ) { + logger.info("[ app={}, stream={} ]通道离线,返回400",gbStream.getApp(), gbStream.getStream()); + responseAck(evt, Response.BAD_REQUEST, "channel [" + gbStream.getGbId() + "] offline"); + return; + } + responseAck(evt, Response.CALL_IS_BEING_FORWARDED); // 通道存在,发181,呼叫转接中 + }else { + logger.info("通道不存在,返回404"); + responseAck(evt, Response.NOT_FOUND); // 通道不存在,发404,资源不存在 + return; + } + // 解析sdp消息, 使用jainsip 自带的sdp解析方式 + String contentString = new String(request.getRawContent()); + + // jainSip不支持y=字段, 移除移除以解析。 + int ssrcIndex = contentString.indexOf("y="); + //ssrc规定长度为10字节,不取余下长度以避免后续还有“f=”字段 + String ssrc = contentString.substring(ssrcIndex + 2, ssrcIndex + 12); + String substring = contentString.substring(0, contentString.indexOf("y=")); + SessionDescription sdp = SdpFactory.getInstance().createSessionDescription(substring); + + // 获取支持的格式 + Vector mediaDescriptions = sdp.getMediaDescriptions(true); + // 查看是否支持PS 负载96 + //String ip = null; + int port = -1; + //boolean recvonly = false; + boolean mediaTransmissionTCP = false; + Boolean tcpActive = null; + for (Object description : mediaDescriptions) { + MediaDescription mediaDescription = (MediaDescription) description; + Media media = mediaDescription.getMedia(); + + Vector mediaFormats = media.getMediaFormats(false); + if (mediaFormats.contains("96")) { + port = media.getMediaPort(); + //String mediaType = media.getMediaType(); + String protocol = media.getProtocol(); + + // 区分TCP发流还是udp, 当前默认udp + if ("TCP/RTP/AVP".equals(protocol)) { + String setup = mediaDescription.getAttribute("setup"); + if (setup != null) { + mediaTransmissionTCP = true; + if ("active".equals(setup)) { + tcpActive = true; + } else if ("passive".equals(setup)) { + tcpActive = false; + } + } + } + break; + } + } + if (port == -1) { + logger.info("不支持的媒体格式,返回415"); + // 回复不支持的格式 + responseAck(evt, Response.UNSUPPORTED_MEDIA_TYPE); // 不支持的格式,发415 + return; + } + String username = sdp.getOrigin().getUsername(); + String addressStr = sdp.getOrigin().getAddress(); + //String sessionName = sdp.getSessionName().getValue(); + logger.info("[上级点播]用户:{}, 地址:{}:{}, ssrc:{}", username, addressStr, port, ssrc); + Device device = null; + // 通过 channel 和 gbStream 是否为null 值判断来源是直播流合适国标 + if (channel != null) { + device = storager.queryVideoDeviceByPlatformIdAndChannelId(requesterId, channelId); + if (device == null) { + logger.warn("点播平台{}的通道{}时未找到设备信息", requesterId, channel); + responseAck(evt, Response.SERVER_INTERNAL_ERROR); + return; + } + mediaServerItem = playService.getNewMediaServerItem(device); + if (mediaServerItem == null) { + logger.warn("未找到可用的zlm"); + responseAck(evt, Response.BUSY_HERE); + return; + } + SendRtpItem sendRtpItem = zlmrtpServerFactory.createSendRtpItem(mediaServerItem, addressStr, port, ssrc, requesterId, + device.getDeviceId(), channelId, + mediaTransmissionTCP); + if (tcpActive != null) { + sendRtpItem.setTcpActive(tcpActive); + } + if (sendRtpItem == null) { + logger.warn("服务器端口资源不足"); + responseAck(evt, Response.BUSY_HERE); + return; + } + + // 写入redis, 超时时回复 + redisCatchStorage.updateSendRTPSever(sendRtpItem); + // 通知下级推流, + PlayResult playResult = playService.play(mediaServerItem,device.getDeviceId(), channelId, (mediaServerItemInUSe, responseJSON)->{ + // 收到推流, 回复200OK, 等待ack + // if (sendRtpItem == null) return; + sendRtpItem.setStatus(1); + redisCatchStorage.updateSendRTPSever(sendRtpItem); + // TODO 添加对tcp的支持 + + StringBuffer content = new StringBuffer(200); + content.append("v=0\r\n"); + content.append("o="+ channelId +" 0 0 IN IP4 "+mediaServerItemInUSe.getSdpIp()+"\r\n"); + content.append("s=Play\r\n"); + content.append("c=IN IP4 "+mediaServerItemInUSe.getSdpIp()+"\r\n"); + content.append("t=0 0\r\n"); + content.append("m=video "+ sendRtpItem.getLocalPort()+" RTP/AVP 96\r\n"); + content.append("a=sendonly\r\n"); + content.append("a=rtpmap:96 PS/90000\r\n"); + content.append("y="+ ssrc + "\r\n"); + content.append("f=\r\n"); + + try { + responseAck(evt, content.toString()); + } catch (SipException e) { + e.printStackTrace(); + } catch (InvalidArgumentException e) { + e.printStackTrace(); + } catch (ParseException e) { + e.printStackTrace(); + } + } ,((event) -> { + // 未知错误。直接转发设备点播的错误 + Response response = null; + try { + response = getMessageFactory().createResponse(event.statusCode, evt.getRequest()); + ServerTransaction serverTransaction = getServerTransaction(evt); + serverTransaction.sendResponse(response); + if (serverTransaction.getDialog() != null) serverTransaction.getDialog().delete(); + } catch (ParseException | SipException | InvalidArgumentException e) { + e.printStackTrace(); + } + })); + if (logger.isDebugEnabled()) { + logger.debug(playResult.getResult().toString()); + } + + }else if (gbStream != null) { + SendRtpItem sendRtpItem = zlmrtpServerFactory.createSendRtpItem(mediaServerItem, addressStr, port, ssrc, requesterId, + gbStream.getApp(), gbStream.getStream(), channelId, + mediaTransmissionTCP); + + if (tcpActive != null) { + sendRtpItem.setTcpActive(tcpActive); + } + if (sendRtpItem == null) { + logger.warn("服务器端口资源不足"); + responseAck(evt, Response.BUSY_HERE); + return; + } + + // 写入redis, 超时时回复 + redisCatchStorage.updateSendRTPSever(sendRtpItem); + + sendRtpItem.setStatus(1); + redisCatchStorage.updateSendRTPSever(sendRtpItem); + // TODO 添加对tcp的支持 + StringBuffer content = new StringBuffer(200); + content.append("v=0\r\n"); + content.append("o="+ channelId +" 0 0 IN IP4 "+mediaServerItem.getSdpIp()+"\r\n"); + content.append("s=Play\r\n"); + content.append("c=IN IP4 "+mediaServerItem.getSdpIp()+"\r\n"); + content.append("t=0 0\r\n"); + content.append("m=video "+ sendRtpItem.getLocalPort()+" RTP/AVP 96\r\n"); + content.append("a=sendonly\r\n"); + content.append("a=rtpmap:96 PS/90000\r\n"); + content.append("y="+ ssrc + "\r\n"); + content.append("f=\r\n"); + + try { + responseAck(evt, content.toString()); + } catch (SipException e) { + e.printStackTrace(); + } catch (InvalidArgumentException e) { + e.printStackTrace(); + } catch (ParseException e) { + e.printStackTrace(); + } + } + + } else { + // 非上级平台请求,查询是否设备请求(通常为接收语音广播的设备) + Device device = storager.queryVideoDevice(requesterId); + if (device != null) { + logger.info("收到设备" + requesterId + "的语音广播Invite请求"); + responseAck(evt, Response.TRYING); + + String contentString = new String(request.getRawContent()); + // jainSip不支持y=字段, 移除移除以解析。 + String substring = contentString; + String ssrc = "0000000404"; + int ssrcIndex = contentString.indexOf("y="); + if (ssrcIndex > 0) { + substring = contentString.substring(0, ssrcIndex); + ssrc = contentString.substring(ssrcIndex + 2, ssrcIndex + 12); + } + ssrcIndex = substring.indexOf("f="); + if (ssrcIndex > 0) { + substring = contentString.substring(0, ssrcIndex); + } + SessionDescription sdp = SdpFactory.getInstance().createSessionDescription(substring); + + // 获取支持的格式 + Vector mediaDescriptions = sdp.getMediaDescriptions(true); + // 查看是否支持PS 负载96 + int port = -1; + //boolean recvonly = false; + boolean mediaTransmissionTCP = false; + Boolean tcpActive = null; + for (int i = 0; i < mediaDescriptions.size(); i++) { + MediaDescription mediaDescription = (MediaDescription)mediaDescriptions.get(i); + Media media = mediaDescription.getMedia(); + + Vector mediaFormats = media.getMediaFormats(false); + if (mediaFormats.contains("8")) { + port = media.getMediaPort(); + String protocol = media.getProtocol(); + // 区分TCP发流还是udp, 当前默认udp + if ("TCP/RTP/AVP".equals(protocol)) { + String setup = mediaDescription.getAttribute("setup"); + if (setup != null) { + mediaTransmissionTCP = true; + if ("active".equals(setup)) { + tcpActive = true; + } else if ("passive".equals(setup)) { + tcpActive = false; + } + } + } + break; + } + } + if (port == -1) { + logger.info("不支持的媒体格式,返回415"); + // 回复不支持的格式 + responseAck(evt, Response.UNSUPPORTED_MEDIA_TYPE); // 不支持的格式,发415 + return; + } + String username = sdp.getOrigin().getUsername(); + String addressStr = sdp.getOrigin().getAddress(); + logger.info("设备{}请求语音流,地址:{}:{},ssrc:{}", username, addressStr, port, ssrc); + + } else { + logger.warn("来自无效设备/平台的请求"); + responseAck(evt, Response.BAD_REQUEST); + } + } + + } catch (SipException | InvalidArgumentException | ParseException e) { + e.printStackTrace(); + logger.warn("sdp解析错误"); + e.printStackTrace(); + } catch (SdpParseException e) { + e.printStackTrace(); + } catch (SdpException e) { + e.printStackTrace(); + } + } +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/MessageRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/MessageRequestProcessor1.java similarity index 74% rename from src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/MessageRequestProcessor.java rename to src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/MessageRequestProcessor1.java index ae01a70d1..847f7e18c 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/MessageRequestProcessor.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/MessageRequestProcessor1.java @@ -1,1177 +1,1105 @@ -package com.genersoft.iot.vmp.gb28181.transmit.request.impl; - -import java.io.ByteArrayInputStream; -import java.text.ParseException; -import java.util.*; - -import javax.sip.*; -import javax.sip.address.Address; -import javax.sip.address.SipURI; - -import javax.sip.header.FromHeader; -import javax.sip.header.Header; -import javax.sip.header.HeaderAddress; -import javax.sip.header.ToHeader; -import javax.sip.message.Request; -import javax.sip.message.Response; - -import com.alibaba.fastjson.JSONObject; -import com.genersoft.iot.vmp.VManageBootstrap; -import com.genersoft.iot.vmp.common.StreamInfo; -import com.genersoft.iot.vmp.common.VideoManagerConstants; -import com.genersoft.iot.vmp.conf.UserSetup; -import com.genersoft.iot.vmp.gb28181.bean.*; -import com.genersoft.iot.vmp.gb28181.event.DeviceOffLineDetector; -import com.genersoft.iot.vmp.gb28181.event.EventPublisher; -import com.genersoft.iot.vmp.gb28181.transmit.callback.CheckForAllRecordsThread; -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.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform; -import com.genersoft.iot.vmp.gb28181.transmit.request.SIPRequestAbstractProcessor; -import com.genersoft.iot.vmp.gb28181.utils.DateUtil; -import com.genersoft.iot.vmp.gb28181.utils.NumericUtil; -import com.genersoft.iot.vmp.gb28181.utils.XmlUtil; -import com.genersoft.iot.vmp.service.IDeviceAlarmService; -import com.genersoft.iot.vmp.storager.IRedisCatchStorage; -import com.genersoft.iot.vmp.storager.IVideoManagerStorager; -import com.genersoft.iot.vmp.utils.GpsUtil; -import com.genersoft.iot.vmp.utils.SipUtils; -import com.genersoft.iot.vmp.utils.SpringBeanFactory; -import com.genersoft.iot.vmp.utils.redis.RedisUtil; -import com.genersoft.iot.vmp.vmanager.gb28181.platform.bean.ChannelReduce; - -import gov.nist.javax.sip.SipStackImpl; -import gov.nist.javax.sip.address.AddressImpl; -import gov.nist.javax.sip.address.SipUri; - -import org.dom4j.Document; -import org.dom4j.DocumentException; -import org.dom4j.Element; -import org.dom4j.io.SAXReader; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.util.StringUtils; - -/** - * @Description:MESSAGE请求处理器 - * @author: swwheihei - * @date: 2020年5月3日 下午5:32:41 - */ -@SuppressWarnings(value={"unchecked", "rawtypes"}) -public class MessageRequestProcessor extends SIPRequestAbstractProcessor { - - public static volatile List threadNameList = new ArrayList(); - - private UserSetup userSetup = (UserSetup) SpringBeanFactory.getBean("userSetup"); - - private final static Logger logger = LoggerFactory.getLogger(MessageRequestProcessor.class); - - private SIPCommander cmder; - - private SIPCommanderFroPlatform cmderFroPlatform; - - private IVideoManagerStorager storager; - - private IRedisCatchStorage redisCatchStorage; - - private EventPublisher publisher; - - private RedisUtil redis; - - private DeferredResultHolder deferredResultHolder; - - private DeviceOffLineDetector offLineDetector; - - private IDeviceAlarmService deviceAlarmService; - - private final static String CACHE_RECORDINFO_KEY = "CACHE_RECORDINFO_"; - - private static final String MESSAGE_KEEP_ALIVE = "Keepalive"; - private static final String MESSAGE_CONFIG_DOWNLOAD = "ConfigDownload"; - private static final String MESSAGE_CATALOG = "Catalog"; - private static final String MESSAGE_DEVICE_INFO = "DeviceInfo"; - private static final String MESSAGE_ALARM = "Alarm"; - private static final String MESSAGE_RECORD_INFO = "RecordInfo"; - private static final String MESSAGE_MEDIA_STATUS = "MediaStatus"; - private static final String MESSAGE_BROADCAST = "Broadcast"; - private static final String MESSAGE_DEVICE_STATUS = "DeviceStatus"; - private static final String MESSAGE_DEVICE_CONTROL = "DeviceControl"; - private static final String MESSAGE_DEVICE_CONFIG = "DeviceConfig"; - private static final String MESSAGE_MOBILE_POSITION = "MobilePosition"; - // private static final String MESSAGE_MOBILE_POSITION_INTERVAL = "Interval"; - private static final String MESSAGE_PRESET_QUERY = "PresetQuery"; - - /** - * 处理MESSAGE请求 - * - * @param evt - */ - @Override - public void process(RequestEvent evt) { - - try { - Element rootElement = getRootElement(evt); - String cmd = XmlUtil.getText(rootElement, "CmdType"); - - if (MESSAGE_KEEP_ALIVE.equals(cmd)) { - logger.debug("接收到KeepAlive消息"); - processMessageKeepAlive(evt); - } else if (MESSAGE_CONFIG_DOWNLOAD.equals(cmd)) { - logger.debug("接收到ConfigDownload消息"); - processMessageConfigDownload(evt); - } else if (MESSAGE_CATALOG.equals(cmd)) { - logger.debug("接收到Catalog消息"); - processMessageCatalogList(evt); - } else if (MESSAGE_DEVICE_INFO.equals(cmd)) { - // DeviceInfo消息处理 - processMessageDeviceInfo(evt); - } else if (MESSAGE_DEVICE_STATUS.equals(cmd)) { - // DeviceStatus消息处理 - processMessageDeviceStatus(evt); - } else if (MESSAGE_DEVICE_CONTROL.equals(cmd)) { - logger.debug("接收到DeviceControl消息"); - processMessageDeviceControl(evt); - } else if (MESSAGE_DEVICE_CONFIG.equals(cmd)) { - logger.info("接收到DeviceConfig消息"); - processMessageDeviceConfig(evt); - } else if (MESSAGE_ALARM.equals(cmd)) { - logger.debug("接收到Alarm消息"); - processMessageAlarm(evt); - } else if (MESSAGE_RECORD_INFO.equals(cmd)) { - logger.debug("接收到RecordInfo消息"); - processMessageRecordInfo(evt); - }else if (MESSAGE_MEDIA_STATUS.equals(cmd)) { - logger.debug("接收到MediaStatus消息"); - processMessageMediaStatus(evt); - } else if (MESSAGE_MOBILE_POSITION.equals(cmd)) { - logger.debug("接收到MobilePosition消息"); - processMessageMobilePosition(evt); - } else if (MESSAGE_PRESET_QUERY.equals(cmd)) { - logger.debug("接收到PresetQuery消息"); - processMessagePresetQuery(evt); - } else if (MESSAGE_BROADCAST.equals(cmd)) { - // Broadcast消息处理 - processMessageBroadcast(evt); - } else { - logger.debug("接收到消息:" + cmd); - responseAck(evt); - } - } catch (DocumentException | SipException |InvalidArgumentException | ParseException e) { - e.printStackTrace(); - } - } - - /** - * 处理MobilePosition移动位置消息 - * - * @param evt - */ - private void processMessageMobilePosition(RequestEvent evt) { - try { - String deviceId = SipUtils.getUserIdFromFromHeader(evt.getRequest()); - Device device = storager.queryVideoDevice(deviceId); - if (device == null) { - logger.warn("处理MobilePosition移动位置消息时未找到设备信息"); - response404Ack(evt); - return; - } - Element rootElement = getRootElement(evt, device.getCharset()); - - MobilePosition mobilePosition = new MobilePosition(); - if (!StringUtils.isEmpty(device.getName())) { - mobilePosition.setDeviceName(device.getName()); - } - mobilePosition.setDeviceId(deviceId); - mobilePosition.setChannelId(XmlUtil.getText(rootElement, "DeviceID")); - mobilePosition.setTime(XmlUtil.getText(rootElement, "Time")); - mobilePosition.setLongitude(Double.parseDouble(XmlUtil.getText(rootElement, "Longitude"))); - mobilePosition.setLatitude(Double.parseDouble(XmlUtil.getText(rootElement, "Latitude"))); - if (NumericUtil.isDouble(XmlUtil.getText(rootElement, "Speed"))) { - mobilePosition.setSpeed(Double.parseDouble(XmlUtil.getText(rootElement, "Speed"))); - } else { - mobilePosition.setSpeed(0.0); - } - if (NumericUtil.isDouble(XmlUtil.getText(rootElement, "Direction"))) { - mobilePosition.setDirection(Double.parseDouble(XmlUtil.getText(rootElement, "Direction"))); - } else { - mobilePosition.setDirection(0.0); - } - if (NumericUtil.isDouble(XmlUtil.getText(rootElement, "Altitude"))) { - mobilePosition.setAltitude(Double.parseDouble(XmlUtil.getText(rootElement, "Altitude"))); - } else { - mobilePosition.setAltitude(0.0); - } - mobilePosition.setReportSource("Mobile Position"); - BaiduPoint bp = new BaiduPoint(); - bp = GpsUtil.Wgs84ToBd09(String.valueOf(mobilePosition.getLongitude()), String.valueOf(mobilePosition.getLatitude())); - logger.info("百度坐标:" + bp.getBdLng() + ", " + bp.getBdLat()); - mobilePosition.setGeodeticSystem("BD-09"); - mobilePosition.setCnLng(bp.getBdLng()); - mobilePosition.setCnLat(bp.getBdLat()); - if (!userSetup.getSavePositionHistory()) { - storager.clearMobilePositionsByDeviceId(deviceId); - } - storager.insertMobilePosition(mobilePosition); - //回复 200 OK - responseAck(evt); - } catch (DocumentException | SipException | InvalidArgumentException | ParseException e) { - e.printStackTrace(); - } - } - - /** - * 处理DeviceStatus设备状态Message - * - * @param evt - */ - private void processMessageDeviceStatus(RequestEvent evt) { - try { - String deviceId = SipUtils.getUserIdFromFromHeader(evt.getRequest()); - Device device = storager.queryVideoDevice(deviceId); - if (device == null) { - logger.warn("处理DeviceStatus设备状态Message时未找到设备信息"); - response404Ack(evt); - return; - } - Element rootElement = getRootElement(evt); - String name = rootElement.getName(); - Element deviceIdElement = rootElement.element("DeviceID"); - String channelId = deviceIdElement.getText(); - if (name.equalsIgnoreCase("Query")) { // 区分是Response——查询响应,还是Query——查询请求 - logger.info("接收到DeviceStatus查询消息"); - FromHeader fromHeader = (FromHeader) evt.getRequest().getHeader(FromHeader.NAME); - String platformId = ((SipUri) fromHeader.getAddress().getURI()).getUser(); - if (platformId == null) { - response404Ack(evt); - return; - } else { - // 回复200 OK - responseAck(evt); - String sn = rootElement.element("SN").getText(); - ParentPlatform parentPlatform = storager.queryParentPlatByServerGBId(platformId); - cmderFroPlatform.deviceStatusResponse(parentPlatform, sn, fromHeader.getTag()); - } - } else { - logger.info("接收到DeviceStatus应答消息"); - // 检查设备是否存在, 不存在则不回复 - if (storager.exists(deviceId)) { - // 回复200 OK - responseAck(evt); - JSONObject json = new JSONObject(); - XmlUtil.node2Json(rootElement, json); - if (logger.isDebugEnabled()) { - logger.debug(json.toJSONString()); - } - RequestMessage msg = new RequestMessage(); - msg.setKey(DeferredResultHolder.CALLBACK_CMD_DEVICESTATUS + deviceId + channelId); - msg.setData(json); - deferredResultHolder.invokeAllResult(msg); - - if (offLineDetector.isOnline(deviceId)) { - publisher.onlineEventPublish(device, VideoManagerConstants.EVENT_ONLINE_MESSAGE); - } else { - } - } - } - - } catch (ParseException | SipException | InvalidArgumentException | DocumentException e) { - e.printStackTrace(); - } - } - - /** - * 处理DeviceControl设备状态Message - * - * @param evt - */ - private void processMessageDeviceControl(RequestEvent evt) { - try { - String deviceId = SipUtils.getUserIdFromFromHeader(evt.getRequest()); - Device device = storager.queryVideoDevice(deviceId); - if (device == null) { - logger.warn("处理DeviceControl设备状态Message未找到设备信息"); - response404Ack(evt); - return; - } - Element rootElement = getRootElement(evt); - String channelId = XmlUtil.getText(rootElement, "DeviceID"); - //String result = XmlUtil.getText(rootElement, "Result"); - // 回复200 OK - responseAck(evt); - if (rootElement.getName().equals("Response")) {//} !StringUtils.isEmpty(result)) { - // 此处是对本平台发出DeviceControl指令的应答 - JSONObject json = new JSONObject(); - XmlUtil.node2Json(rootElement, json); - if (logger.isDebugEnabled()) { - logger.debug(json.toJSONString()); - } - RequestMessage msg = new RequestMessage(); - String key = DeferredResultHolder.CALLBACK_CMD_DEVICECONTROL + deviceId + channelId; - msg.setKey(key); - msg.setData(json); - deferredResultHolder.invokeAllResult(msg); - } else { - // 此处是上级发出的DeviceControl指令 - String platformId = ((SipURI) ((HeaderAddress) evt.getRequest().getHeader(FromHeader.NAME)).getAddress().getURI()).getUser(); - String targetGBId = ((SipURI) ((HeaderAddress) evt.getRequest().getHeader(ToHeader.NAME)).getAddress().getURI()).getUser(); - // 远程启动功能 - if (!StringUtils.isEmpty(XmlUtil.getText(rootElement, "TeleBoot"))) { - if (deviceId.equals(targetGBId)) { - // 远程启动本平台:需要在重新启动程序后先对SipStack解绑 - logger.info("执行远程启动本平台命令"); - ParentPlatform parentPlatform = storager.queryParentPlatByServerGBId(platformId); - cmderFroPlatform.unregister(parentPlatform, null, null); - - Thread restartThread = new Thread(new Runnable() { - @Override - public void run() { - try { - Thread.sleep(3000); - SipProvider up = (SipProvider) SpringBeanFactory.getBean("udpSipProvider"); - SipStackImpl stack = (SipStackImpl)up.getSipStack(); - stack.stop(); - Iterator listener = stack.getListeningPoints(); - while (listener.hasNext()) { - stack.deleteListeningPoint((ListeningPoint) listener.next()); - } - Iterator providers = stack.getSipProviders(); - while (providers.hasNext()) { - stack.deleteSipProvider((SipProvider) providers.next()); - } - VManageBootstrap.restart(); - } catch (InterruptedException ignored) { - } catch (ObjectInUseException e) { - e.printStackTrace(); - } - } - }); - - restartThread.setDaemon(false); - restartThread.start(); - } else { - // 远程启动指定设备 - } - } - // 云台/前端控制命令 - if (!StringUtils.isEmpty(XmlUtil.getText(rootElement,"PTZCmd")) && !deviceId.equals(targetGBId)) { - String cmdString = XmlUtil.getText(rootElement,"PTZCmd"); - Device deviceForPlatform = storager.queryVideoDeviceByPlatformIdAndChannelId(platformId, deviceId); - cmder.fronEndCmd(deviceForPlatform, deviceId, cmdString); - } - } - } catch (ParseException | SipException | InvalidArgumentException | DocumentException e) { - e.printStackTrace(); - } - } - - /** - * 处理DeviceConfig设备状态Message - * - * @param evt - */ - private void processMessageDeviceConfig(RequestEvent evt) { - try { - String deviceId = SipUtils.getUserIdFromFromHeader(evt.getRequest()); - // 查询设备是否存在 - Device device = storager.queryVideoDevice(deviceId); - if (device == null) { - logger.warn("处理DeviceConfig设备状态Message消息时未找到设备信息"); - response404Ack(evt); - return; - } - Element rootElement = getRootElement(evt); - String channelId = XmlUtil.getText(rootElement, "DeviceID"); - // 回复200 OK - responseAck(evt); - if (rootElement.getName().equals("Response")) { - // 此处是对本平台发出DeviceControl指令的应答 - JSONObject json = new JSONObject(); - XmlUtil.node2Json(rootElement, json); - if (logger.isDebugEnabled()) { - logger.debug(json.toJSONString()); - } - String key = DeferredResultHolder.CALLBACK_CMD_DEVICECONFIG + deviceId + channelId; - RequestMessage msg = new RequestMessage(); - msg.setKey(key); - msg.setData(json); - deferredResultHolder.invokeAllResult(msg); - } else { - // 此处是上级发出的DeviceConfig指令 - } - } catch (ParseException | SipException | InvalidArgumentException | DocumentException e) { - e.printStackTrace(); - } - } - - /** - * 处理ConfigDownload设备状态Message - * - * @param evt - */ - private void processMessageConfigDownload(RequestEvent evt) { - try { - String deviceId = SipUtils.getUserIdFromFromHeader(evt.getRequest()); - // 查询设备是否存在 - Device device = storager.queryVideoDevice(deviceId); - if (device == null) { - logger.warn("处理ConfigDownload设备状态Message时未找到设备信息"); - response404Ack(evt); - return; - } - Element rootElement = getRootElement(evt); - String channelId = XmlUtil.getText(rootElement, "DeviceID"); - String key = DeferredResultHolder.CALLBACK_CMD_CONFIGDOWNLOAD + deviceId + channelId; - // 回复200 OK - responseAck(evt); - if (rootElement.getName().equals("Response")) { - // 此处是对本平台发出DeviceControl指令的应答 - JSONObject json = new JSONObject(); - XmlUtil.node2Json(rootElement, json); - if (logger.isDebugEnabled()) { - logger.debug(json.toJSONString()); - } - RequestMessage msg = new RequestMessage(); - msg.setKey(key); - msg.setData(json); - deferredResultHolder.invokeAllResult(msg); - } else { - // 此处是上级发出的DeviceConfig指令 - } - } catch (ParseException | SipException | InvalidArgumentException | DocumentException e) { - e.printStackTrace(); - } - } - - /** - * 处理PresetQuery预置位列表Message - * - * @param evt - */ - private void processMessagePresetQuery(RequestEvent evt) { - try { - String deviceId = SipUtils.getUserIdFromFromHeader(evt.getRequest()); - // 查询设备是否存在 - Device device = storager.queryVideoDevice(deviceId); - if (device == null) { - logger.warn("处理PresetQuery预置位列表Message时未找到设备信息"); - response404Ack(evt); - return; - } - Element rootElement = getRootElement(evt); - String channelId = XmlUtil.getText(rootElement, "DeviceID"); - String key = DeferredResultHolder.CALLBACK_CMD_PRESETQUERY + deviceId + channelId; - // 回复200 OK - responseAck(evt); - if (rootElement.getName().equals("Response")) {// !StringUtils.isEmpty(result)) { - // 此处是对本平台发出DeviceControl指令的应答 - JSONObject json = new JSONObject(); - XmlUtil.node2Json(rootElement, json); - if (logger.isDebugEnabled()) { - logger.debug(json.toJSONString()); - } - RequestMessage msg = new RequestMessage(); - msg.setKey(key); - msg.setData(json); - deferredResultHolder.invokeAllResult(msg); - } else { - // 此处是上级发出的DeviceControl指令 - } - } catch (ParseException | SipException | InvalidArgumentException | DocumentException e) { - e.printStackTrace(); - } - } - - /** - * 处理DeviceInfo设备信息Message - * - * @param evt - */ - private void processMessageDeviceInfo(RequestEvent evt) { - try { - String deviceId = SipUtils.getUserIdFromFromHeader(evt.getRequest()); - // 查询设备是否存在 - Device device = storager.queryVideoDevice(deviceId); - ParentPlatform parentPlatform = storager.queryParentPlatByServerGBId(deviceId); - - Element rootElement = getRootElement(evt); - String requestName = rootElement.getName(); - Element deviceIdElement = rootElement.element("DeviceID"); - String channelId = deviceIdElement.getTextTrim(); - String key = DeferredResultHolder.CALLBACK_CMD_DEVICEINFO + deviceId + channelId; - if (device != null ) { - rootElement = getRootElement(evt, device.getCharset()); - } - if (requestName.equals("Query")) { - logger.info("接收到DeviceInfo查询消息"); - FromHeader fromHeader = (FromHeader) evt.getRequest().getHeader(FromHeader.NAME); - if (parentPlatform == null) { - response404Ack(evt); - return; - } else { - // 回复200 OK - responseAck(evt); - String sn = rootElement.element("SN").getText(); - cmderFroPlatform.deviceInfoResponse(parentPlatform, sn, fromHeader.getTag()); - } - } else { - logger.debug("接收到DeviceInfo应答消息"); - if (device == null) { - logger.warn("处理DeviceInfo设备信息Message时未找到设备信息"); - response404Ack(evt); - return; - } - - device.setName(XmlUtil.getText(rootElement, "DeviceName")); - - device.setManufacturer(XmlUtil.getText(rootElement, "Manufacturer")); - device.setModel(XmlUtil.getText(rootElement, "Model")); - device.setFirmware(XmlUtil.getText(rootElement, "Firmware")); - if (StringUtils.isEmpty(device.getStreamMode())) { - device.setStreamMode("UDP"); - } - storager.updateDevice(device); - - RequestMessage msg = new RequestMessage(); - msg.setKey(key); - msg.setData(device); - deferredResultHolder.invokeAllResult(msg); - // 回复200 OK - responseAck(evt); - if (offLineDetector.isOnline(deviceId)) { - publisher.onlineEventPublish(device, VideoManagerConstants.EVENT_ONLINE_MESSAGE); - } - } - } catch (DocumentException | SipException | InvalidArgumentException | ParseException e) { - e.printStackTrace(); - } - } - - /*** - * 收到catalog设备目录列表请求 处理 - * - * @param evt - */ - private void processMessageCatalogList(RequestEvent evt) { - try { - - String deviceId = SipUtils.getUserIdFromFromHeader(evt.getRequest()); - // 查询设备是否存在 - Device device = storager.queryVideoDevice(deviceId); - ParentPlatform parentPlatform = storager.queryParentPlatByServerGBId(deviceId); - - - Element rootElement = getRootElement(evt); - String name = rootElement.getName(); - Element deviceIdElement = rootElement.element("DeviceID"); - String channelId = deviceIdElement.getText(); - Element deviceListElement = rootElement.element("DeviceList"); - String key = DeferredResultHolder.CALLBACK_CMD_CATALOG + deviceId; - FromHeader fromHeader = (FromHeader) evt.getRequest().getHeader(FromHeader.NAME); - if (name.equalsIgnoreCase("Query")) { // 区分是Response——查询响应,还是Query——查询请求 - // TODO 后续将代码拆分 - if (parentPlatform == null) { - response404Ack(evt); - return; - } else { - // 回复200 OK - responseAck(evt); - - Element snElement = rootElement.element("SN"); - String sn = snElement.getText(); - // 准备回复通道信息 - List channelReduces = storager.queryChannelListInParentPlatform(parentPlatform.getServerGBId()); - // 查询关联的直播通道 - List gbStreams = storager.queryGbStreamListInPlatform(parentPlatform.getServerGBId()); - int size = channelReduces.size() + gbStreams.size(); - // 回复级联的通道 - if (channelReduces.size() > 0) { - for (ChannelReduce channelReduce : channelReduces) { - DeviceChannel deviceChannel = storager.queryChannel(channelReduce.getDeviceId(), channelReduce.getChannelId()); - cmderFroPlatform.catalogQuery(deviceChannel, parentPlatform, sn, fromHeader.getTag(), size); - } - } - // 回复直播的通道 - if (gbStreams.size() > 0) { - for (GbStream gbStream : gbStreams) { - DeviceChannel deviceChannel = new DeviceChannel(); - deviceChannel.setChannelId(gbStream.getGbId()); - deviceChannel.setName(gbStream.getName()); - deviceChannel.setLongitude(gbStream.getLongitude()); - deviceChannel.setLatitude(gbStream.getLatitude()); - deviceChannel.setDeviceId(parentPlatform.getDeviceGBId()); - deviceChannel.setManufacture("wvp-pro"); - deviceChannel.setStatus(gbStream.isStatus()?1:0); -// deviceChannel.setParentId(parentPlatform.getDeviceGBId()); - deviceChannel.setRegisterWay(1); - deviceChannel.setCivilCode(cmder.getSipConfig().getDomain()); - deviceChannel.setModel("live"); - deviceChannel.setOwner("wvp-pro"); -// deviceChannel.setAddress("test"); - deviceChannel.setParental(0); - deviceChannel.setSecrecy("0"); - deviceChannel.setSecrecy("0"); - - cmderFroPlatform.catalogQuery(deviceChannel, parentPlatform, sn, fromHeader.getTag(), size); - } - } - if (size == 0) { - // 回复无通道 - cmderFroPlatform.catalogQuery(null, parentPlatform, sn, fromHeader.getTag(), size); - } - } - - - } else { - if (device == null) { - logger.warn("收到catalog设备目录列表请求时未找到设备信息"); - response404Ack(evt); - return; - } - deviceListElement = getRootElement(evt, device.getCharset()).element("DeviceList"); - Iterator deviceListIterator = deviceListElement.elementIterator(); - if (deviceListIterator != null) { - - // 遍历DeviceList - while (deviceListIterator.hasNext()) { - Element itemDevice = deviceListIterator.next(); - Element channelDeviceElement = itemDevice.element("DeviceID"); - if (channelDeviceElement == null) { - continue; - } - String channelDeviceId = channelDeviceElement.getText(); - Element channdelNameElement = itemDevice.element("Name"); - String channelName = channdelNameElement != null ? channdelNameElement.getTextTrim().toString() : ""; - Element statusElement = itemDevice.element("Status"); - String status = statusElement != null ? statusElement.getText().toString() : "ON"; - DeviceChannel deviceChannel = new DeviceChannel(); - deviceChannel.setName(channelName); - deviceChannel.setChannelId(channelDeviceId); - // ONLINE OFFLINE HIKVISION DS-7716N-E4 NVR的兼容性处理 - if (status.equals("ON") || status.equals("On") || status.equals("ONLINE")) { - deviceChannel.setStatus(1); - } - if (status.equals("OFF") || status.equals("Off") || status.equals("OFFLINE")) { - deviceChannel.setStatus(0); - } - - deviceChannel.setManufacture(XmlUtil.getText(itemDevice, "Manufacturer")); - deviceChannel.setModel(XmlUtil.getText(itemDevice, "Model")); - deviceChannel.setOwner(XmlUtil.getText(itemDevice, "Owner")); - deviceChannel.setCivilCode(XmlUtil.getText(itemDevice, "CivilCode")); - deviceChannel.setBlock(XmlUtil.getText(itemDevice, "Block")); - deviceChannel.setAddress(XmlUtil.getText(itemDevice, "Address")); - if (XmlUtil.getText(itemDevice, "Parental") == null || XmlUtil.getText(itemDevice, "Parental") == "") { - deviceChannel.setParental(0); - } else { - deviceChannel.setParental(Integer.parseInt(XmlUtil.getText(itemDevice, "Parental"))); - } - deviceChannel.setParentId(XmlUtil.getText(itemDevice, "ParentID")); - if (XmlUtil.getText(itemDevice, "SafetyWay") == null || XmlUtil.getText(itemDevice, "SafetyWay") == "") { - deviceChannel.setSafetyWay(0); - } else { - deviceChannel.setSafetyWay(Integer.parseInt(XmlUtil.getText(itemDevice, "SafetyWay"))); - } - if (XmlUtil.getText(itemDevice, "RegisterWay") == null || XmlUtil.getText(itemDevice, "RegisterWay") == "") { - deviceChannel.setRegisterWay(1); - } else { - deviceChannel.setRegisterWay(Integer.parseInt(XmlUtil.getText(itemDevice, "RegisterWay"))); - } - deviceChannel.setCertNum(XmlUtil.getText(itemDevice, "CertNum")); - if (XmlUtil.getText(itemDevice, "Certifiable") == null || XmlUtil.getText(itemDevice, "Certifiable") == "") { - deviceChannel.setCertifiable(0); - } else { - deviceChannel.setCertifiable(Integer.parseInt(XmlUtil.getText(itemDevice, "Certifiable"))); - } - if (XmlUtil.getText(itemDevice, "ErrCode") == null || XmlUtil.getText(itemDevice, "ErrCode") == "") { - deviceChannel.setErrCode(0); - } else { - deviceChannel.setErrCode(Integer.parseInt(XmlUtil.getText(itemDevice, "ErrCode"))); - } - deviceChannel.setEndTime(XmlUtil.getText(itemDevice, "EndTime")); - deviceChannel.setSecrecy(XmlUtil.getText(itemDevice, "Secrecy")); - deviceChannel.setIpAddress(XmlUtil.getText(itemDevice, "IPAddress")); - if (XmlUtil.getText(itemDevice, "Port") == null || XmlUtil.getText(itemDevice, "Port") == "") { - deviceChannel.setPort(0); - } else { - deviceChannel.setPort(Integer.parseInt(XmlUtil.getText(itemDevice, "Port"))); - } - deviceChannel.setPassword(XmlUtil.getText(itemDevice, "Password")); - if (NumericUtil.isDouble(XmlUtil.getText(itemDevice, "Longitude"))) { - deviceChannel.setLongitude(Double.parseDouble(XmlUtil.getText(itemDevice, "Longitude"))); - } else { - deviceChannel.setLongitude(0.00); - } - if (NumericUtil.isDouble(XmlUtil.getText(itemDevice, "Latitude"))) { - deviceChannel.setLatitude(Double.parseDouble(XmlUtil.getText(itemDevice, "Latitude"))); - } else { - deviceChannel.setLatitude(0.00); - } - if (XmlUtil.getText(itemDevice, "PTZType") == null || XmlUtil.getText(itemDevice, "PTZType") == "") { - deviceChannel.setPTZType(0); - } else { - deviceChannel.setPTZType(Integer.parseInt(XmlUtil.getText(itemDevice, "PTZType"))); - } - deviceChannel.setHasAudio(true); // 默认含有音频,播放时再检查是否有音频及是否AAC - storager.updateChannel(device.getDeviceId(), deviceChannel); - } - - RequestMessage msg = new RequestMessage(); - msg.setKey(key); - msg.setData(device); - deferredResultHolder.invokeAllResult(msg); - // 回复200 OK - responseAck(evt); - if (offLineDetector.isOnline(deviceId)) { - publisher.onlineEventPublish(device, VideoManagerConstants.EVENT_ONLINE_MESSAGE); - } - } - } - } catch (DocumentException | SipException | InvalidArgumentException | ParseException e) { - e.printStackTrace(); - } - } - - /*** - * 收到alarm设备报警信息 处理 - * - * @param evt - */ - private void processMessageAlarm(RequestEvent evt) { - try { - String deviceId = SipUtils.getUserIdFromFromHeader(evt.getRequest()); - Device device = storager.queryVideoDevice(deviceId); - if (device == null) { - logger.warn("处理alarm设备报警信息未找到设备信息"); - response404Ack(evt); - return; - } - Element rootElement = getRootElement(evt, device.getCharset()); - Element deviceIdElement = rootElement.element("DeviceID"); - String channelId = deviceIdElement.getText().toString(); - String key = DeferredResultHolder.CALLBACK_CMD_ALARM + deviceId + channelId; - // 回复200 OK - responseAck(evt); - - if (device.getCharset() != null) { - rootElement = getRootElement(evt, device.getCharset()); - } - - if (rootElement.getName().equals("Notify")) { // 处理报警通知 - DeviceAlarm deviceAlarm = new DeviceAlarm(); - deviceAlarm.setDeviceId(deviceId); - deviceAlarm.setChannelId(channelId); - deviceAlarm.setAlarmPriority(XmlUtil.getText(rootElement, "AlarmPriority")); - deviceAlarm.setAlarmMethod(XmlUtil.getText(rootElement, "AlarmMethod")); - deviceAlarm.setAlarmTime(XmlUtil.getText(rootElement, "AlarmTime")); - if (XmlUtil.getText(rootElement, "AlarmDescription") == null) { - deviceAlarm.setAlarmDescription(""); - } else { - deviceAlarm.setAlarmDescription(XmlUtil.getText(rootElement, "AlarmDescription")); - } - if (NumericUtil.isDouble(XmlUtil.getText(rootElement, "Longitude"))) { - deviceAlarm.setLongitude(Double.parseDouble(XmlUtil.getText(rootElement, "Longitude"))); - } else { - deviceAlarm.setLongitude(0.00); - } - if (NumericUtil.isDouble(XmlUtil.getText(rootElement, "Latitude"))) { - deviceAlarm.setLatitude(Double.parseDouble(XmlUtil.getText(rootElement, "Latitude"))); - } else { - deviceAlarm.setLatitude(0.00); - } - - if (!StringUtils.isEmpty(deviceAlarm.getAlarmMethod())) { - if ( deviceAlarm.getAlarmMethod().equals("4")) { - MobilePosition mobilePosition = new MobilePosition(); - mobilePosition.setDeviceId(deviceAlarm.getDeviceId()); - mobilePosition.setTime(deviceAlarm.getAlarmTime()); - mobilePosition.setLongitude(deviceAlarm.getLongitude()); - mobilePosition.setLatitude(deviceAlarm.getLatitude()); - mobilePosition.setReportSource("GPS Alarm"); - BaiduPoint bp = new BaiduPoint(); - bp = GpsUtil.Wgs84ToBd09(String.valueOf(mobilePosition.getLongitude()), String.valueOf(mobilePosition.getLatitude())); - logger.info("百度坐标:" + bp.getBdLng() + ", " + bp.getBdLat()); - mobilePosition.setGeodeticSystem("BD-09"); - mobilePosition.setCnLng(bp.getBdLng()); - mobilePosition.setCnLat(bp.getBdLat()); - if (!userSetup.getSavePositionHistory()) { - storager.clearMobilePositionsByDeviceId(deviceId); - } - storager.insertMobilePosition(mobilePosition); - } - } - logger.debug("存储报警信息、报警分类"); - // 存储报警信息、报警分类 - deviceAlarmService.add(deviceAlarm); - - if (offLineDetector.isOnline(deviceId)) { - publisher.deviceAlarmEventPublish(deviceAlarm); - } - } else if (rootElement.getName().equals("Response")) { // 处理报警查询响应 - JSONObject json = new JSONObject(); - XmlUtil.node2Json(rootElement, json); - if (logger.isDebugEnabled()) { - logger.debug(json.toJSONString()); - } - RequestMessage msg = new RequestMessage(); - msg.setKey(key); - msg.setData(json); - deferredResultHolder.invokeAllResult(msg); - } - } catch (DocumentException | SipException | InvalidArgumentException | ParseException e) { - e.printStackTrace(); - } - } - - /*** - * 收到keepalive请求 处理 - * - * @param evt - */ - private void processMessageKeepAlive(RequestEvent evt) { - try { - - String deviceId = SipUtils.getUserIdFromFromHeader(evt.getRequest()); - // 查询设备是否存在 - Device device = storager.queryVideoDevice(deviceId); - - Element rootElement = getRootElement(evt); - String channelId = XmlUtil.getText(rootElement, "DeviceID"); - - // 检查设备是否存在并在线, 不在线则设置为在线 - if (device != null ) { - // 回复200 OK - responseAck(evt); - publisher.onlineEventPublish(device, VideoManagerConstants.EVENT_ONLINE_KEEPLIVE); - }else{ - logger.warn("收到[ "+deviceId+" ]心跳信息, 但是设备不存在, 回复404"); - Response response = getMessageFactory().createResponse(Response.NOT_FOUND, evt.getRequest()); - ServerTransaction serverTransaction = getServerTransaction(evt); - serverTransaction.sendResponse(response); - if (serverTransaction.getDialog() != null) { - serverTransaction.getDialog().delete(); - } - } - -// if (device != null && device.getOnline() == 1) { -// -// if (offLineDetector.isOnline(deviceId)) { -// publisher.onlineEventPublish(device, VideoManagerConstants.EVENT_ONLINE_KEEPLIVE); -// } else { -// } -// }else { -//// logger.warn("收到[ "+deviceId+" ]心跳信息, 但是设备" + (device == null? "不存在":"离线") + ", 回复401"); -//// Response response = getMessageFactory().createResponse(Response.UNAUTHORIZED, evt.getRequest()); -//// getServerTransaction(evt).sendResponse(response); -// publisher.onlineEventPublish(device, VideoManagerConstants.EVENT_ONLINE_KEEPLIVE); -// -// } - } catch (ParseException | SipException | InvalidArgumentException | DocumentException e) { - e.printStackTrace(); - } - } - - /*** - * 处理RecordInfo设备录像列表Message请求 TODO 过期时间暂时写死180秒,后续与DeferredResult超时时间保持一致 - * - * @param evt - */ - private void processMessageRecordInfo(RequestEvent evt) { - try { - - String deviceId = SipUtils.getUserIdFromFromHeader(evt.getRequest()); - // 查询设备是否存在 - Device device = storager.queryVideoDevice(deviceId); - if (device == null) { - logger.warn("处理DeviceInfo设备信息Message时未找到设备信息"); - response404Ack(evt); - return; - } - - // 回复200 OK - responseAck(evt); - String uuid = UUID.randomUUID().toString().replace("-", ""); - RecordInfo recordInfo = new RecordInfo(); - Element rootElement = getRootElement(evt); - Element deviceIdElement = rootElement.element("DeviceID"); - String channelId = deviceIdElement.getText().toString(); - String key = DeferredResultHolder.CALLBACK_CMD_RECORDINFO + deviceId + channelId; - if (device != null ) { - rootElement = getRootElement(evt, device.getCharset()); - } - recordInfo.setDeviceId(deviceId); - recordInfo.setChannelId(channelId); - recordInfo.setName(XmlUtil.getText(rootElement, "Name")); - if (XmlUtil.getText(rootElement, "SumNum")== null || XmlUtil.getText(rootElement, "SumNum") =="") { - recordInfo.setSumNum(0); - } else { - recordInfo.setSumNum(Integer.parseInt(XmlUtil.getText(rootElement, "SumNum"))); - } - String sn = XmlUtil.getText(rootElement, "SN"); - Element recordListElement = rootElement.element("RecordList"); - if (recordListElement == null || recordInfo.getSumNum() == 0) { - logger.info("无录像数据"); - RequestMessage msg = new RequestMessage(); - msg.setKey(key); - msg.setData(recordInfo); - deferredResultHolder.invokeAllResult(msg); - } else { - Iterator recordListIterator = recordListElement.elementIterator(); - List recordList = new ArrayList(); - if (recordListIterator != null) { - RecordItem record = new RecordItem(); - logger.info("处理录像列表数据..."); - // 遍历DeviceList - while (recordListIterator.hasNext()) { - Element itemRecord = recordListIterator.next(); - Element recordElement = itemRecord.element("DeviceID"); - if (recordElement == null) { - logger.info("记录为空,下一个..."); - continue; - } - record = new RecordItem(); - record.setDeviceId(XmlUtil.getText(itemRecord, "DeviceID")); - record.setName(XmlUtil.getText(itemRecord, "Name")); - record.setFilePath(XmlUtil.getText(itemRecord, "FilePath")); - record.setAddress(XmlUtil.getText(itemRecord, "Address")); - record.setStartTime( - DateUtil.ISO8601Toyyyy_MM_dd_HH_mm_ss(XmlUtil.getText(itemRecord, "StartTime"))); - record.setEndTime( - DateUtil.ISO8601Toyyyy_MM_dd_HH_mm_ss(XmlUtil.getText(itemRecord, "EndTime"))); - record.setSecrecy(itemRecord.element("Secrecy") == null ? 0 - : Integer.parseInt(XmlUtil.getText(itemRecord, "Secrecy"))); - record.setType(XmlUtil.getText(itemRecord, "Type")); - record.setRecorderId(XmlUtil.getText(itemRecord, "RecorderID")); - recordList.add(record); - } - recordInfo.setRecordList(recordList); - } - - // 改用单独线程统计已获取录像文件数量,避免多包并行分别统计不完整的问题 - String cacheKey = CACHE_RECORDINFO_KEY + deviceId + sn; - redis.set(cacheKey + "_" + uuid, recordList, 90); - if (!threadNameList.contains(cacheKey)) { - threadNameList.add(cacheKey); - CheckForAllRecordsThread chk = new CheckForAllRecordsThread(cacheKey, recordInfo); - chk.setName(cacheKey); - chk.setDeferredResultHolder(deferredResultHolder); - chk.setRedis(redis); - chk.setLogger(logger); - chk.start(); - if (logger.isDebugEnabled()) { - logger.debug("Start Thread " + cacheKey + "."); - } - } else { - if (logger.isDebugEnabled()) { - logger.debug("Thread " + cacheKey + " already started."); - } - } - - // 存在录像且如果当前录像明细个数小于总条数,说明拆包返回,需要组装,暂不返回 - // if (recordInfo.getSumNum() > 0 && recordList.size() > 0 && recordList.size() < recordInfo.getSumNum()) { - // // 为防止连续请求该设备的录像数据,返回数据错乱,特增加sn进行区分 - // String cacheKey = CACHE_RECORDINFO_KEY + deviceId + sn; - - // redis.set(cacheKey + "_" + uuid, recordList, 90); - // List cacheKeys = redis.scan(cacheKey + "_*"); - // List totalRecordList = new ArrayList(); - // for (int i = 0; i < cacheKeys.size(); i++) { - // totalRecordList.addAll((List) redis.get(cacheKeys.get(i).toString())); - // } - // if (totalRecordList.size() < recordInfo.getSumNum()) { - // logger.info("已获取" + totalRecordList.size() + "项录像数据,共" + recordInfo.getSumNum() + "项"); - // return; - // } - // logger.info("录像数据已全部获取,共" + recordInfo.getSumNum() + "项"); - // recordInfo.setRecordList(totalRecordList); - // for (int i = 0; i < cacheKeys.size(); i++) { - // redis.del(cacheKeys.get(i).toString()); - // } - // } - // // 自然顺序排序, 元素进行升序排列 - // recordInfo.getRecordList().sort(Comparator.naturalOrder()); - } - // 走到这里,有以下可能:1、没有录像信息,第一次收到recordinfo的消息即返回响应数据,无redis操作 - // 2、有录像数据,且第一次即收到完整数据,返回响应数据,无redis操作 - // 3、有录像数据,在超时时间内收到多次包组装后数量足够,返回数据 - - // RequestMessage msg = new RequestMessage(); - // msg.setDeviceId(deviceId); - // msg.setType(DeferredResultHolder.CALLBACK_CMD_RECORDINFO); - // msg.setData(recordInfo); - // deferredResultHolder.invokeResult(msg); - // logger.info("处理完成,返回结果"); - } catch (DocumentException | SipException | InvalidArgumentException | ParseException e) { - e.printStackTrace(); - } - } - - /** - * 收到MediaStatus消息处理 - * - * @param evt - */ - private void processMessageMediaStatus(RequestEvent evt){ - try { - - String deviceId = SipUtils.getUserIdFromFromHeader(evt.getRequest()); - // 查询设备是否存在 - Device device = storager.queryVideoDevice(deviceId); - if (device == null) { - logger.warn("处理DeviceInfo设备信息Message时未找到设备信息"); - response404Ack(evt); - return; - } - - // 回复200 OK - responseAck(evt); - Element rootElement = getRootElement(evt); - String channelId = XmlUtil.getText(rootElement, "DeviceID"); - String NotifyType =XmlUtil.getText(rootElement, "NotifyType"); - if (NotifyType.equals("121")){ - logger.info("媒体播放完毕,通知关流"); - StreamInfo streamInfo = redisCatchStorage.queryPlaybackByDevice(deviceId, "*"); - if (streamInfo != null) { - redisCatchStorage.stopPlayback(streamInfo); - cmder.streamByeCmd(streamInfo.getDeviceID(), streamInfo.getChannelId()); - } - } - } catch (ParseException | SipException | InvalidArgumentException | DocumentException e) { - e.printStackTrace(); - } - } - - /** - * 处理AudioBroadcast语音广播Message - * - * @param evt - */ - private void processMessageBroadcast(RequestEvent evt) { - try { - - String deviceId = SipUtils.getUserIdFromFromHeader(evt.getRequest()); - // 查询设备是否存在 - Device device = storager.queryVideoDevice(deviceId); - if (device == null) { - logger.warn("处理DeviceInfo设备信息Message时未找到设备信息"); - response404Ack(evt); - return; - } - - Element rootElement = getRootElement(evt); - String channelId = XmlUtil.getText(rootElement, "DeviceID"); - String key = DeferredResultHolder.CALLBACK_CMD_BROADCAST + deviceId + channelId; - // 回复200 OK - responseAck(evt); - if (rootElement.getName().equals("Response")) { - // 此处是对本平台发出Broadcast指令的应答 - JSONObject json = new JSONObject(); - XmlUtil.node2Json(rootElement, json); - if (logger.isDebugEnabled()) { - logger.debug(json.toJSONString()); - } - RequestMessage msg = new RequestMessage(); - msg.setKey(key); - msg.setData(json); - deferredResultHolder.invokeAllResult(msg); - } else { - // 此处是上级发出的Broadcast指令 - } - } catch (ParseException | SipException | InvalidArgumentException | DocumentException e) { - e.printStackTrace(); - } - } - - - /*** - * 回复200 OK - * @param evt - * @throws SipException - * @throws InvalidArgumentException - * @throws ParseException - */ - private void responseAck(RequestEvent evt) throws SipException, InvalidArgumentException, ParseException { - Response response = getMessageFactory().createResponse(Response.OK, evt.getRequest()); - ServerTransaction serverTransaction = getServerTransaction(evt); - serverTransaction.sendResponse(response); - if (serverTransaction.getDialog() != null) { - serverTransaction.getDialog().delete(); - } - } - - /*** - * 回复404 - * @param evt - * @throws SipException - * @throws InvalidArgumentException - * @throws ParseException - */ - private void response404Ack(RequestEvent evt) throws SipException, InvalidArgumentException, ParseException { - Response response = getMessageFactory().createResponse(Response.NOT_FOUND, evt.getRequest()); - ServerTransaction serverTransaction = getServerTransaction(evt); - serverTransaction.sendResponse(response); - if (serverTransaction.getDialog() != null) { - serverTransaction.getDialog().delete(); - } - } - - private Element getRootElement(RequestEvent evt) throws DocumentException { - - return getRootElement(evt, "gb2312"); - } - - private Element getRootElement(RequestEvent evt, String charset) throws DocumentException { - if (charset == null) { - charset = "gb2312"; - } - Request request = evt.getRequest(); - SAXReader reader = new SAXReader(); - reader.setEncoding(charset); - Document xml = reader.read(new ByteArrayInputStream(request.getRawContent())); - return xml.getRootElement(); - } - - public void setCmder(SIPCommander cmder) { - this.cmder = cmder; - } - - public void setStorager(IVideoManagerStorager storager) { - this.storager = storager; - } - - public void setPublisher(EventPublisher publisher) { - this.publisher = publisher; - } - - public void setRedis(RedisUtil redis) { - this.redis = redis; - } - - public void setDeferredResultHolder(DeferredResultHolder deferredResultHolder) { - this.deferredResultHolder = deferredResultHolder; - } - - public void setOffLineDetector(DeviceOffLineDetector offLineDetector) { - this.offLineDetector = offLineDetector; - } - - public IRedisCatchStorage getRedisCatchStorage() { - return redisCatchStorage; - } - - public void setRedisCatchStorage(IRedisCatchStorage redisCatchStorage) { - this.redisCatchStorage = redisCatchStorage; - } - - public SIPCommanderFroPlatform getCmderFroPlatform() { - return cmderFroPlatform; - } - - public void setCmderFroPlatform(SIPCommanderFroPlatform cmderFroPlatform) { - this.cmderFroPlatform = cmderFroPlatform; - } - - public void setDeviceAlarmService(IDeviceAlarmService deviceAlarmService) { - this.deviceAlarmService = deviceAlarmService; - } -} +package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl; + +import com.alibaba.fastjson.JSONObject; +import com.genersoft.iot.vmp.VManageBootstrap; +import com.genersoft.iot.vmp.common.StreamInfo; +import com.genersoft.iot.vmp.common.VideoManagerConstants; +import com.genersoft.iot.vmp.conf.SipConfig; +import com.genersoft.iot.vmp.conf.UserSetup; +import com.genersoft.iot.vmp.gb28181.bean.*; +import com.genersoft.iot.vmp.gb28181.event.DeviceOffLineDetector; +import com.genersoft.iot.vmp.gb28181.event.EventPublisher; +import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver; +import com.genersoft.iot.vmp.gb28181.transmit.callback.CheckForAllRecordsThread; +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.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform; +import com.genersoft.iot.vmp.gb28181.transmit.event.request.ISIPRequestProcessor; +import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent; +import com.genersoft.iot.vmp.gb28181.utils.DateUtil; +import com.genersoft.iot.vmp.gb28181.utils.NumericUtil; +import com.genersoft.iot.vmp.gb28181.utils.SipUtils; +import com.genersoft.iot.vmp.gb28181.utils.XmlUtil; +import com.genersoft.iot.vmp.service.IDeviceAlarmService; +import com.genersoft.iot.vmp.storager.IRedisCatchStorage; +import com.genersoft.iot.vmp.storager.IVideoManagerStorager; +import com.genersoft.iot.vmp.utils.GpsUtil; +import com.genersoft.iot.vmp.utils.SpringBeanFactory; +import com.genersoft.iot.vmp.utils.redis.RedisUtil; +import com.genersoft.iot.vmp.vmanager.gb28181.platform.bean.ChannelReduce; +import gov.nist.javax.sip.SipStackImpl; +import gov.nist.javax.sip.address.SipUri; +import org.dom4j.DocumentException; +import org.dom4j.Element; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.util.StringUtils; + +import javax.sip.*; +import javax.sip.address.SipURI; +import javax.sip.header.FromHeader; +import javax.sip.header.HeaderAddress; +import javax.sip.header.ToHeader; +import javax.sip.message.Response; +import java.text.ParseException; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; + +import static com.genersoft.iot.vmp.gb28181.utils.XmlUtil.getText; + +/** + * @description: MESSAGE请求分发处理器, + * @author: panlinlin + * @date: 2021年11月8日 10:28 + */ +@SuppressWarnings(value={"unchecked", "rawtypes"}) +@Component +public class MessageRequestProcessor1 extends SIPRequestProcessorParent implements InitializingBean, ISIPRequestProcessor { + + public static volatile List threadNameList = new ArrayList(); + private final static Logger logger = LoggerFactory.getLogger(MessageRequestProcessor1.class); + private static Map messageHandlerMap = new ConcurrentHashMap<>(); + + + private final static String CACHE_RECORDINFO_KEY = "CACHE_RECORDINFO_"; + private static final String MESSAGE_KEEP_ALIVE = "Keepalive"; + private static final String MESSAGE_CONFIG_DOWNLOAD = "ConfigDownload"; + private static final String MESSAGE_CATALOG = "Catalog"; + private static final String MESSAGE_DEVICE_INFO = "DeviceInfo"; + private static final String MESSAGE_ALARM = "Alarm"; + private static final String MESSAGE_RECORD_INFO = "RecordInfo"; + private static final String MESSAGE_MEDIA_STATUS = "MediaStatus"; + private static final String MESSAGE_BROADCAST = "Broadcast"; + private static final String MESSAGE_DEVICE_STATUS = "DeviceStatus"; + private static final String MESSAGE_DEVICE_CONTROL = "DeviceControl"; + private static final String MESSAGE_DEVICE_CONFIG = "DeviceConfig"; + private static final String MESSAGE_MOBILE_POSITION = "MobilePosition"; + private static final String MESSAGE_PRESET_QUERY = "PresetQuery"; + private String method = "MESSAGE1111"; + + @Autowired + private UserSetup userSetup; + + @Autowired + private SIPCommander cmder; + + @Autowired + private SipConfig config; + + @Autowired + private SIPCommanderFroPlatform cmderFroPlatform; + + @Autowired + private IVideoManagerStorager storager; + + @Autowired + private IRedisCatchStorage redisCatchStorage; + + @Autowired + private EventPublisher publisher; + + @Autowired + private RedisUtil redis; + + @Autowired + private DeferredResultHolder deferredResultHolder; + + @Autowired + private DeviceOffLineDetector offLineDetector; + + @Autowired + private IDeviceAlarmService deviceAlarmService; + + @Autowired + private SIPProcessorObserver sipProcessorObserver; + + @Override + public void afterPropertiesSet() throws Exception { + // 添加消息处理的订阅 + sipProcessorObserver.addRequestProcessor(method, this); + } + + /** + * 处理MESSAGE请求 + * + * @param evt + */ + @Override + public void process(RequestEvent evt) { + + try { + Element rootElement = getRootElement(evt); + String cmd = getText(rootElement, "CmdType"); + + if (MESSAGE_KEEP_ALIVE.equals(cmd)) { + logger.debug("接收到KeepAlive消息"); + processMessageKeepAlive(evt); + } else if (MESSAGE_CONFIG_DOWNLOAD.equals(cmd)) { + logger.debug("接收到ConfigDownload消息"); + processMessageConfigDownload(evt); + } else if (MESSAGE_CATALOG.equals(cmd)) { + logger.debug("接收到Catalog消息"); + processMessageCatalogList(evt); + } else if (MESSAGE_DEVICE_INFO.equals(cmd)) { + // DeviceInfo消息处理 + processMessageDeviceInfo(evt); + } else if (MESSAGE_DEVICE_STATUS.equals(cmd)) { + // DeviceStatus消息处理 + processMessageDeviceStatus(evt); + } else if (MESSAGE_DEVICE_CONTROL.equals(cmd)) { + logger.debug("接收到DeviceControl消息"); + processMessageDeviceControl(evt); + } else if (MESSAGE_DEVICE_CONFIG.equals(cmd)) { + logger.info("接收到DeviceConfig消息"); + processMessageDeviceConfig(evt); + } else if (MESSAGE_ALARM.equals(cmd)) { + logger.debug("接收到Alarm消息"); + processMessageAlarm(evt); + } else if (MESSAGE_RECORD_INFO.equals(cmd)) { + logger.debug("接收到RecordInfo消息"); + processMessageRecordInfo(evt); + }else if (MESSAGE_MEDIA_STATUS.equals(cmd)) { + logger.debug("接收到MediaStatus消息"); + processMessageMediaStatus(evt); + } else if (MESSAGE_MOBILE_POSITION.equals(cmd)) { + logger.debug("接收到MobilePosition消息"); + processMessageMobilePosition(evt); + } else if (MESSAGE_PRESET_QUERY.equals(cmd)) { + logger.debug("接收到PresetQuery消息"); + processMessagePresetQuery(evt); + } else if (MESSAGE_BROADCAST.equals(cmd)) { + // Broadcast消息处理 + processMessageBroadcast(evt); + } else { + logger.debug("接收到消息:" + cmd); + responseAck(evt, Response.OK); + } + } catch (DocumentException | SipException |InvalidArgumentException | ParseException e) { + e.printStackTrace(); + } + } + + /** + * 处理MobilePosition移动位置消息 + * + * @param evt + */ + private void processMessageMobilePosition(RequestEvent evt) { + try { + String deviceId = SipUtils.getUserIdFromFromHeader(evt.getRequest()); + Device device = storager.queryVideoDevice(deviceId); + if (device == null) { + logger.warn("处理MobilePosition移动位置消息时未找到设备信息"); + responseAck(evt, Response.NOT_FOUND); + return; + } + Element rootElement = getRootElement(evt, device.getCharset()); + + MobilePosition mobilePosition = new MobilePosition(); + if (!StringUtils.isEmpty(device.getName())) { + mobilePosition.setDeviceName(device.getName()); + } + mobilePosition.setDeviceId(deviceId); + mobilePosition.setChannelId(getText(rootElement, "DeviceID")); + mobilePosition.setTime(getText(rootElement, "Time")); + mobilePosition.setLongitude(Double.parseDouble(getText(rootElement, "Longitude"))); + mobilePosition.setLatitude(Double.parseDouble(getText(rootElement, "Latitude"))); + if (NumericUtil.isDouble(getText(rootElement, "Speed"))) { + mobilePosition.setSpeed(Double.parseDouble(getText(rootElement, "Speed"))); + } else { + mobilePosition.setSpeed(0.0); + } + if (NumericUtil.isDouble(getText(rootElement, "Direction"))) { + mobilePosition.setDirection(Double.parseDouble(getText(rootElement, "Direction"))); + } else { + mobilePosition.setDirection(0.0); + } + if (NumericUtil.isDouble(getText(rootElement, "Altitude"))) { + mobilePosition.setAltitude(Double.parseDouble(getText(rootElement, "Altitude"))); + } else { + mobilePosition.setAltitude(0.0); + } + mobilePosition.setReportSource("Mobile Position"); + BaiduPoint bp = new BaiduPoint(); + bp = GpsUtil.Wgs84ToBd09(String.valueOf(mobilePosition.getLongitude()), String.valueOf(mobilePosition.getLatitude())); + logger.info("百度坐标:" + bp.getBdLng() + ", " + bp.getBdLat()); + mobilePosition.setGeodeticSystem("BD-09"); + mobilePosition.setCnLng(bp.getBdLng()); + mobilePosition.setCnLat(bp.getBdLat()); + if (!userSetup.getSavePositionHistory()) { + storager.clearMobilePositionsByDeviceId(deviceId); + } + storager.insertMobilePosition(mobilePosition); + //回复 200 OK + responseAck(evt, Response.OK); + } catch (DocumentException | SipException | InvalidArgumentException | ParseException e) { + e.printStackTrace(); + } + } + + /** + * 处理DeviceStatus设备状态Message + * + * @param evt + */ + private void processMessageDeviceStatus(RequestEvent evt) { + try { + String deviceId = SipUtils.getUserIdFromFromHeader(evt.getRequest()); + Device device = storager.queryVideoDevice(deviceId); + if (device == null) { + logger.warn("处理DeviceStatus设备状态Message时未找到设备信息"); + responseAck(evt, Response.NOT_FOUND); + return; + } + Element rootElement = getRootElement(evt); + String name = rootElement.getName(); + Element deviceIdElement = rootElement.element("DeviceID"); + String channelId = deviceIdElement.getText(); + if (name.equalsIgnoreCase("Query")) { // 区分是Response——查询响应,还是Query——查询请求 + logger.info("接收到DeviceStatus查询消息"); + FromHeader fromHeader = (FromHeader) evt.getRequest().getHeader(FromHeader.NAME); + String platformId = ((SipUri) fromHeader.getAddress().getURI()).getUser(); + if (platformId == null) { + responseAck(evt, Response.NOT_FOUND); + return; + } else { + // 回复200 OK + responseAck(evt, Response.OK); + String sn = rootElement.element("SN").getText(); + ParentPlatform parentPlatform = storager.queryParentPlatByServerGBId(platformId); + cmderFroPlatform.deviceStatusResponse(parentPlatform, sn, fromHeader.getTag()); + } + } else { + logger.info("接收到DeviceStatus应答消息"); + // 检查设备是否存在, 不存在则不回复 + if (storager.exists(deviceId)) { + // 回复200 OK + responseAck(evt, Response.OK); + JSONObject json = new JSONObject(); + XmlUtil.node2Json(rootElement, json); + if (logger.isDebugEnabled()) { + logger.debug(json.toJSONString()); + } + RequestMessage msg = new RequestMessage(); + msg.setKey(DeferredResultHolder.CALLBACK_CMD_DEVICESTATUS + deviceId + channelId); + msg.setData(json); + deferredResultHolder.invokeAllResult(msg); + + if (offLineDetector.isOnline(deviceId)) { + publisher.onlineEventPublish(device, VideoManagerConstants.EVENT_ONLINE_MESSAGE); + } else { + } + } + } + + } catch (ParseException | SipException | InvalidArgumentException | DocumentException e) { + e.printStackTrace(); + } + } + + /** + * 处理DeviceControl设备状态Message + * + * @param evt + */ + private void processMessageDeviceControl(RequestEvent evt) { + try { + String deviceId = SipUtils.getUserIdFromFromHeader(evt.getRequest()); + Device device = storager.queryVideoDevice(deviceId); + if (device == null) { + logger.warn("处理DeviceControl设备状态Message未找到设备信息"); + responseAck(evt, Response.NOT_FOUND); + return; + } + Element rootElement = getRootElement(evt); + String channelId = getText(rootElement, "DeviceID"); + //String result = getText(rootElement, "Result"); + // 回复200 OK + responseAck(evt, Response.OK); + if (rootElement.getName().equals("Response")) {//} !StringUtils.isEmpty(result)) { + // 此处是对本平台发出DeviceControl指令的应答 + JSONObject json = new JSONObject(); + XmlUtil.node2Json(rootElement, json); + if (logger.isDebugEnabled()) { + logger.debug(json.toJSONString()); + } + RequestMessage msg = new RequestMessage(); + String key = DeferredResultHolder.CALLBACK_CMD_DEVICECONTROL + deviceId + channelId; + msg.setKey(key); + msg.setData(json); + deferredResultHolder.invokeAllResult(msg); + } else { + // 此处是上级发出的DeviceControl指令 + String platformId = ((SipURI) ((HeaderAddress) evt.getRequest().getHeader(FromHeader.NAME)).getAddress().getURI()).getUser(); + String targetGBId = ((SipURI) ((HeaderAddress) evt.getRequest().getHeader(ToHeader.NAME)).getAddress().getURI()).getUser(); + // 远程启动功能 + if (!StringUtils.isEmpty(getText(rootElement, "TeleBoot"))) { + if (deviceId.equals(targetGBId)) { + // 远程启动本平台:需要在重新启动程序后先对SipStack解绑 + logger.info("执行远程启动本平台命令"); + ParentPlatform parentPlatform = storager.queryParentPlatByServerGBId(platformId); + cmderFroPlatform.unregister(parentPlatform, null, null); + + Thread restartThread = new Thread(new Runnable() { + @Override + public void run() { + try { + Thread.sleep(3000); + SipProvider up = (SipProvider) SpringBeanFactory.getBean("udpSipProvider"); + SipStackImpl stack = (SipStackImpl)up.getSipStack(); + stack.stop(); + Iterator listener = stack.getListeningPoints(); + while (listener.hasNext()) { + stack.deleteListeningPoint((ListeningPoint) listener.next()); + } + Iterator providers = stack.getSipProviders(); + while (providers.hasNext()) { + stack.deleteSipProvider((SipProvider) providers.next()); + } + VManageBootstrap.restart(); + } catch (InterruptedException ignored) { + } catch (ObjectInUseException e) { + e.printStackTrace(); + } + } + }); + + restartThread.setDaemon(false); + restartThread.start(); + } else { + // 远程启动指定设备 + } + } + // 云台/前端控制命令 + if (!StringUtils.isEmpty(getText(rootElement,"PTZCmd")) && !deviceId.equals(targetGBId)) { + String cmdString = getText(rootElement,"PTZCmd"); + Device deviceForPlatform = storager.queryVideoDeviceByPlatformIdAndChannelId(platformId, deviceId); + cmder.fronEndCmd(deviceForPlatform, deviceId, cmdString); + } + } + } catch (ParseException | SipException | InvalidArgumentException | DocumentException e) { + e.printStackTrace(); + } + } + + /** + * 处理DeviceConfig设备状态Message + * + * @param evt + */ + private void processMessageDeviceConfig(RequestEvent evt) { + try { + String deviceId = SipUtils.getUserIdFromFromHeader(evt.getRequest()); + // 查询设备是否存在 + Device device = storager.queryVideoDevice(deviceId); + if (device == null) { + logger.warn("处理DeviceConfig设备状态Message消息时未找到设备信息"); + responseAck(evt, Response.NOT_FOUND); + return; + } + Element rootElement = getRootElement(evt); + String channelId = getText(rootElement, "DeviceID"); + // 回复200 OK + responseAck(evt, Response.OK); + if (rootElement.getName().equals("Response")) { + // 此处是对本平台发出DeviceControl指令的应答 + JSONObject json = new JSONObject(); + XmlUtil.node2Json(rootElement, json); + if (logger.isDebugEnabled()) { + logger.debug(json.toJSONString()); + } + String key = DeferredResultHolder.CALLBACK_CMD_DEVICECONFIG + deviceId + channelId; + RequestMessage msg = new RequestMessage(); + msg.setKey(key); + msg.setData(json); + deferredResultHolder.invokeAllResult(msg); + } else { + // 此处是上级发出的DeviceConfig指令 + } + } catch (ParseException | SipException | InvalidArgumentException | DocumentException e) { + e.printStackTrace(); + } + } + + /** + * 处理ConfigDownload设备状态Message + * + * @param evt + */ + private void processMessageConfigDownload(RequestEvent evt) { + try { + String deviceId = SipUtils.getUserIdFromFromHeader(evt.getRequest()); + // 查询设备是否存在 + Device device = storager.queryVideoDevice(deviceId); + if (device == null) { + logger.warn("处理ConfigDownload设备状态Message时未找到设备信息"); + responseAck(evt, Response.NOT_FOUND); + return; + } + Element rootElement = getRootElement(evt); + String channelId = getText(rootElement, "DeviceID"); + String key = DeferredResultHolder.CALLBACK_CMD_CONFIGDOWNLOAD + deviceId + channelId; + // 回复200 OK + responseAck(evt, Response.OK); + if (rootElement.getName().equals("Response")) { + // 此处是对本平台发出DeviceControl指令的应答 + JSONObject json = new JSONObject(); + XmlUtil.node2Json(rootElement, json); + if (logger.isDebugEnabled()) { + logger.debug(json.toJSONString()); + } + RequestMessage msg = new RequestMessage(); + msg.setKey(key); + msg.setData(json); + deferredResultHolder.invokeAllResult(msg); + } else { + // 此处是上级发出的DeviceConfig指令 + } + } catch (ParseException | SipException | InvalidArgumentException | DocumentException e) { + e.printStackTrace(); + } + } + + /** + * 处理PresetQuery预置位列表Message + * + * @param evt + */ + private void processMessagePresetQuery(RequestEvent evt) { + try { + String deviceId = SipUtils.getUserIdFromFromHeader(evt.getRequest()); + // 查询设备是否存在 + Device device = storager.queryVideoDevice(deviceId); + if (device == null) { + logger.warn("处理PresetQuery预置位列表Message时未找到设备信息"); + responseAck(evt, Response.NOT_FOUND); + return; + } + Element rootElement = getRootElement(evt); + String channelId = getText(rootElement, "DeviceID"); + String key = DeferredResultHolder.CALLBACK_CMD_PRESETQUERY + deviceId + channelId; + // 回复200 OK + responseAck(evt, Response.OK); + if (rootElement.getName().equals("Response")) {// !StringUtils.isEmpty(result)) { + // 此处是对本平台发出DeviceControl指令的应答 + JSONObject json = new JSONObject(); + XmlUtil.node2Json(rootElement, json); + if (logger.isDebugEnabled()) { + logger.debug(json.toJSONString()); + } + RequestMessage msg = new RequestMessage(); + msg.setKey(key); + msg.setData(json); + deferredResultHolder.invokeAllResult(msg); + } else { + // 此处是上级发出的DeviceControl指令 + } + } catch (ParseException | SipException | InvalidArgumentException | DocumentException e) { + e.printStackTrace(); + } + } + + /** + * 处理DeviceInfo设备信息Message + * + * @param evt + */ + private void processMessageDeviceInfo(RequestEvent evt) { + try { + String deviceId = SipUtils.getUserIdFromFromHeader(evt.getRequest()); + // 查询设备是否存在 + Device device = storager.queryVideoDevice(deviceId); + ParentPlatform parentPlatform = storager.queryParentPlatByServerGBId(deviceId); + + Element rootElement = getRootElement(evt); + String requestName = rootElement.getName(); + Element deviceIdElement = rootElement.element("DeviceID"); + String channelId = deviceIdElement.getTextTrim(); + String key = DeferredResultHolder.CALLBACK_CMD_DEVICEINFO + deviceId + channelId; + if (device != null ) { + rootElement = getRootElement(evt, device.getCharset()); + } + if (requestName.equals("Query")) { + logger.info("接收到DeviceInfo查询消息"); + FromHeader fromHeader = (FromHeader) evt.getRequest().getHeader(FromHeader.NAME); + if (parentPlatform == null) { + responseAck(evt, Response.NOT_FOUND); + return; + } else { + // 回复200 OK + responseAck(evt, Response.OK); + String sn = rootElement.element("SN").getText(); + cmderFroPlatform.deviceInfoResponse(parentPlatform, sn, fromHeader.getTag()); + } + } else { + logger.debug("接收到DeviceInfo应答消息"); + if (device == null) { + logger.warn("处理DeviceInfo设备信息Message时未找到设备信息"); + responseAck(evt, Response.NOT_FOUND); + return; + } + + device.setName(getText(rootElement, "DeviceName")); + + device.setManufacturer(getText(rootElement, "Manufacturer")); + device.setModel(getText(rootElement, "Model")); + device.setFirmware(getText(rootElement, "Firmware")); + if (StringUtils.isEmpty(device.getStreamMode())) { + device.setStreamMode("UDP"); + } + storager.updateDevice(device); + + RequestMessage msg = new RequestMessage(); + msg.setKey(key); + msg.setData(device); + deferredResultHolder.invokeAllResult(msg); + // 回复200 OK + responseAck(evt, Response.OK); + if (offLineDetector.isOnline(deviceId)) { + publisher.onlineEventPublish(device, VideoManagerConstants.EVENT_ONLINE_MESSAGE); + } + } + } catch (DocumentException | SipException | InvalidArgumentException | ParseException e) { + e.printStackTrace(); + } + } + + /*** + * 收到catalog设备目录列表请求 处理 + * + * @param evt + */ + private void processMessageCatalogList(RequestEvent evt) { + try { + + String deviceId = SipUtils.getUserIdFromFromHeader(evt.getRequest()); + // 查询设备是否存在 + Device device = storager.queryVideoDevice(deviceId); + ParentPlatform parentPlatform = storager.queryParentPlatByServerGBId(deviceId); + + + Element rootElement = getRootElement(evt); + String name = rootElement.getName(); + Element deviceIdElement = rootElement.element("DeviceID"); + String channelId = deviceIdElement.getText(); + Element deviceListElement = rootElement.element("DeviceList"); + String key = DeferredResultHolder.CALLBACK_CMD_CATALOG + deviceId; + FromHeader fromHeader = (FromHeader) evt.getRequest().getHeader(FromHeader.NAME); + if (name.equalsIgnoreCase("Query")) { // 区分是Response——查询响应,还是Query——查询请求 + // TODO 后续将代码拆分 + if (parentPlatform == null) { + responseAck(evt, Response.NOT_FOUND); + return; + } else { + // 回复200 OK + responseAck(evt, Response.OK); + + Element snElement = rootElement.element("SN"); + String sn = snElement.getText(); + // 准备回复通道信息 + List channelReduces = storager.queryChannelListInParentPlatform(parentPlatform.getServerGBId()); + // 查询关联的直播通道 + List gbStreams = storager.queryGbStreamListInPlatform(parentPlatform.getServerGBId()); + int size = channelReduces.size() + gbStreams.size(); + // 回复级联的通道 + if (channelReduces.size() > 0) { + for (ChannelReduce channelReduce : channelReduces) { + DeviceChannel deviceChannel = storager.queryChannel(channelReduce.getDeviceId(), channelReduce.getChannelId()); + cmderFroPlatform.catalogQuery(deviceChannel, parentPlatform, sn, fromHeader.getTag(), size); + } + } + // 回复直播的通道 + if (gbStreams.size() > 0) { + for (GbStream gbStream : gbStreams) { + DeviceChannel deviceChannel = new DeviceChannel(); + deviceChannel.setChannelId(gbStream.getGbId()); + deviceChannel.setName(gbStream.getName()); + deviceChannel.setLongitude(gbStream.getLongitude()); + deviceChannel.setLatitude(gbStream.getLatitude()); + deviceChannel.setDeviceId(parentPlatform.getDeviceGBId()); + deviceChannel.setManufacture("wvp-pro"); + deviceChannel.setStatus(gbStream.isStatus()?1:0); +// deviceChannel.setParentId(parentPlatform.getDeviceGBId()); + deviceChannel.setRegisterWay(1); + deviceChannel.setCivilCode(config.getDomain()); + deviceChannel.setModel("live"); + deviceChannel.setOwner("wvp-pro"); +// deviceChannel.setAddress("test"); + deviceChannel.setParental(0); + deviceChannel.setSecrecy("0"); + deviceChannel.setSecrecy("0"); + + cmderFroPlatform.catalogQuery(deviceChannel, parentPlatform, sn, fromHeader.getTag(), size); + } + } + if (size == 0) { + // 回复无通道 + cmderFroPlatform.catalogQuery(null, parentPlatform, sn, fromHeader.getTag(), size); + } + } + + + } else { + if (device == null) { + logger.warn("收到catalog设备目录列表请求时未找到设备信息"); + responseAck(evt, Response.NOT_FOUND); + return; + } + deviceListElement = getRootElement(evt, device.getCharset()).element("DeviceList"); + Iterator deviceListIterator = deviceListElement.elementIterator(); + if (deviceListIterator != null) { + + // 遍历DeviceList + while (deviceListIterator.hasNext()) { + Element itemDevice = deviceListIterator.next(); + Element channelDeviceElement = itemDevice.element("DeviceID"); + if (channelDeviceElement == null) { + continue; + } + String channelDeviceId = channelDeviceElement.getText(); + Element channdelNameElement = itemDevice.element("Name"); + String channelName = channdelNameElement != null ? channdelNameElement.getTextTrim().toString() : ""; + Element statusElement = itemDevice.element("Status"); + String status = statusElement != null ? statusElement.getText().toString() : "ON"; + DeviceChannel deviceChannel = new DeviceChannel(); + deviceChannel.setName(channelName); + deviceChannel.setChannelId(channelDeviceId); + // ONLINE OFFLINE HIKVISION DS-7716N-E4 NVR的兼容性处理 + if (status.equals("ON") || status.equals("On") || status.equals("ONLINE")) { + deviceChannel.setStatus(1); + } + if (status.equals("OFF") || status.equals("Off") || status.equals("OFFLINE")) { + deviceChannel.setStatus(0); + } + + deviceChannel.setManufacture(getText(itemDevice, "Manufacturer")); + deviceChannel.setModel(getText(itemDevice, "Model")); + deviceChannel.setOwner(getText(itemDevice, "Owner")); + deviceChannel.setCivilCode(getText(itemDevice, "CivilCode")); + deviceChannel.setBlock(getText(itemDevice, "Block")); + deviceChannel.setAddress(getText(itemDevice, "Address")); + if (getText(itemDevice, "Parental") == null || getText(itemDevice, "Parental") == "") { + deviceChannel.setParental(0); + } else { + deviceChannel.setParental(Integer.parseInt(getText(itemDevice, "Parental"))); + } + deviceChannel.setParentId(getText(itemDevice, "ParentID")); + if (getText(itemDevice, "SafetyWay") == null || getText(itemDevice, "SafetyWay") == "") { + deviceChannel.setSafetyWay(0); + } else { + deviceChannel.setSafetyWay(Integer.parseInt(getText(itemDevice, "SafetyWay"))); + } + if (getText(itemDevice, "RegisterWay") == null || getText(itemDevice, "RegisterWay") == "") { + deviceChannel.setRegisterWay(1); + } else { + deviceChannel.setRegisterWay(Integer.parseInt(getText(itemDevice, "RegisterWay"))); + } + deviceChannel.setCertNum(getText(itemDevice, "CertNum")); + if (getText(itemDevice, "Certifiable") == null || getText(itemDevice, "Certifiable") == "") { + deviceChannel.setCertifiable(0); + } else { + deviceChannel.setCertifiable(Integer.parseInt(getText(itemDevice, "Certifiable"))); + } + if (getText(itemDevice, "ErrCode") == null || getText(itemDevice, "ErrCode") == "") { + deviceChannel.setErrCode(0); + } else { + deviceChannel.setErrCode(Integer.parseInt(getText(itemDevice, "ErrCode"))); + } + deviceChannel.setEndTime(getText(itemDevice, "EndTime")); + deviceChannel.setSecrecy(getText(itemDevice, "Secrecy")); + deviceChannel.setIpAddress(getText(itemDevice, "IPAddress")); + if (getText(itemDevice, "Port") == null || getText(itemDevice, "Port") == "") { + deviceChannel.setPort(0); + } else { + deviceChannel.setPort(Integer.parseInt(getText(itemDevice, "Port"))); + } + deviceChannel.setPassword(getText(itemDevice, "Password")); + if (NumericUtil.isDouble(getText(itemDevice, "Longitude"))) { + deviceChannel.setLongitude(Double.parseDouble(getText(itemDevice, "Longitude"))); + } else { + deviceChannel.setLongitude(0.00); + } + if (NumericUtil.isDouble(getText(itemDevice, "Latitude"))) { + deviceChannel.setLatitude(Double.parseDouble(getText(itemDevice, "Latitude"))); + } else { + deviceChannel.setLatitude(0.00); + } + if (getText(itemDevice, "PTZType") == null || getText(itemDevice, "PTZType") == "") { + deviceChannel.setPTZType(0); + } else { + deviceChannel.setPTZType(Integer.parseInt(getText(itemDevice, "PTZType"))); + } + deviceChannel.setHasAudio(true); // 默认含有音频,播放时再检查是否有音频及是否AAC + storager.updateChannel(device.getDeviceId(), deviceChannel); + } + + RequestMessage msg = new RequestMessage(); + msg.setKey(key); + msg.setData(device); + deferredResultHolder.invokeAllResult(msg); + // 回复200 OK + responseAck(evt, Response.OK); + if (offLineDetector.isOnline(deviceId)) { + publisher.onlineEventPublish(device, VideoManagerConstants.EVENT_ONLINE_MESSAGE); + } + } + } + } catch (DocumentException | SipException | InvalidArgumentException | ParseException e) { + e.printStackTrace(); + } + } + + /*** + * 收到alarm设备报警信息 处理 + * + * @param evt + */ + private void processMessageAlarm(RequestEvent evt) { + try { + String deviceId = SipUtils.getUserIdFromFromHeader(evt.getRequest()); + Device device = storager.queryVideoDevice(deviceId); + if (device == null) { + logger.warn("处理alarm设备报警信息未找到设备信息"); + responseAck(evt, Response.NOT_FOUND); + return; + } + Element rootElement = getRootElement(evt, device.getCharset()); + Element deviceIdElement = rootElement.element("DeviceID"); + String channelId = deviceIdElement.getText().toString(); + String key = DeferredResultHolder.CALLBACK_CMD_ALARM + deviceId + channelId; + // 回复200 OK + responseAck(evt, Response.OK); + + if (device.getCharset() != null) { + rootElement = getRootElement(evt, device.getCharset()); + } + + if (rootElement.getName().equals("Notify")) { // 处理报警通知 + DeviceAlarm deviceAlarm = new DeviceAlarm(); + deviceAlarm.setDeviceId(deviceId); + deviceAlarm.setChannelId(channelId); + deviceAlarm.setAlarmPriority(getText(rootElement, "AlarmPriority")); + deviceAlarm.setAlarmMethod(getText(rootElement, "AlarmMethod")); + deviceAlarm.setAlarmTime(getText(rootElement, "AlarmTime")); + if (getText(rootElement, "AlarmDescription") == null) { + deviceAlarm.setAlarmDescription(""); + } else { + deviceAlarm.setAlarmDescription(getText(rootElement, "AlarmDescription")); + } + if (NumericUtil.isDouble(getText(rootElement, "Longitude"))) { + deviceAlarm.setLongitude(Double.parseDouble(getText(rootElement, "Longitude"))); + } else { + deviceAlarm.setLongitude(0.00); + } + if (NumericUtil.isDouble(getText(rootElement, "Latitude"))) { + deviceAlarm.setLatitude(Double.parseDouble(getText(rootElement, "Latitude"))); + } else { + deviceAlarm.setLatitude(0.00); + } + + if (!StringUtils.isEmpty(deviceAlarm.getAlarmMethod())) { + if ( deviceAlarm.getAlarmMethod().equals("4")) { + MobilePosition mobilePosition = new MobilePosition(); + mobilePosition.setDeviceId(deviceAlarm.getDeviceId()); + mobilePosition.setTime(deviceAlarm.getAlarmTime()); + mobilePosition.setLongitude(deviceAlarm.getLongitude()); + mobilePosition.setLatitude(deviceAlarm.getLatitude()); + mobilePosition.setReportSource("GPS Alarm"); + BaiduPoint bp = new BaiduPoint(); + bp = GpsUtil.Wgs84ToBd09(String.valueOf(mobilePosition.getLongitude()), String.valueOf(mobilePosition.getLatitude())); + logger.info("百度坐标:" + bp.getBdLng() + ", " + bp.getBdLat()); + mobilePosition.setGeodeticSystem("BD-09"); + mobilePosition.setCnLng(bp.getBdLng()); + mobilePosition.setCnLat(bp.getBdLat()); + if (!userSetup.getSavePositionHistory()) { + storager.clearMobilePositionsByDeviceId(deviceId); + } + storager.insertMobilePosition(mobilePosition); + } + } + logger.debug("存储报警信息、报警分类"); + // 存储报警信息、报警分类 + deviceAlarmService.add(deviceAlarm); + + if (offLineDetector.isOnline(deviceId)) { + publisher.deviceAlarmEventPublish(deviceAlarm); + } + } else if (rootElement.getName().equals("Response")) { // 处理报警查询响应 + JSONObject json = new JSONObject(); + XmlUtil.node2Json(rootElement, json); + if (logger.isDebugEnabled()) { + logger.debug(json.toJSONString()); + } + RequestMessage msg = new RequestMessage(); + msg.setKey(key); + msg.setData(json); + deferredResultHolder.invokeAllResult(msg); + } + } catch (DocumentException | SipException | InvalidArgumentException | ParseException e) { + e.printStackTrace(); + } + } + + /*** + * 收到keepalive请求 处理 + * + * @param evt + */ + private void processMessageKeepAlive(RequestEvent evt) { + try { + + String deviceId = SipUtils.getUserIdFromFromHeader(evt.getRequest()); + // 查询设备是否存在 + Device device = storager.queryVideoDevice(deviceId); + + Element rootElement = getRootElement(evt); + String channelId = getText(rootElement, "DeviceID"); + + // 检查设备是否存在并在线, 不在线则设置为在线 + if (device != null ) { + // 回复200 OK + responseAck(evt, Response.OK); + publisher.onlineEventPublish(device, VideoManagerConstants.EVENT_ONLINE_KEEPLIVE); + }else{ + logger.warn("收到[ "+deviceId+" ]心跳信息, 但是设备不存在, 回复404"); + Response response = getMessageFactory().createResponse(Response.NOT_FOUND, evt.getRequest()); + ServerTransaction serverTransaction = getServerTransaction(evt); + serverTransaction.sendResponse(response); + if (serverTransaction.getDialog() != null) { + serverTransaction.getDialog().delete(); + } + } + +// if (device != null && device.getOnline() == 1) { +// +// if (offLineDetector.isOnline(deviceId)) { +// publisher.onlineEventPublish(device, VideoManagerConstants.EVENT_ONLINE_KEEPLIVE); +// } else { +// } +// }else { +//// logger.warn("收到[ "+deviceId+" ]心跳信息, 但是设备" + (device == null? "不存在":"离线") + ", 回复401"); +//// Response response = getMessageFactory().createResponse(Response.UNAUTHORIZED, evt.getRequest()); +//// getServerTransaction(evt).sendResponse(response); +// publisher.onlineEventPublish(device, VideoManagerConstants.EVENT_ONLINE_KEEPLIVE); +// +// } + } catch (ParseException | SipException | InvalidArgumentException | DocumentException e) { + e.printStackTrace(); + } + } + + /*** + * 处理RecordInfo设备录像列表Message请求 TODO 过期时间暂时写死180秒,后续与DeferredResult超时时间保持一致 + * + * @param evt + */ + private void processMessageRecordInfo(RequestEvent evt) { + try { + + String deviceId = SipUtils.getUserIdFromFromHeader(evt.getRequest()); + // 查询设备是否存在 + Device device = storager.queryVideoDevice(deviceId); + if (device == null) { + logger.warn("处理DeviceInfo设备信息Message时未找到设备信息"); + responseAck(evt, Response.NOT_FOUND); + return; + } + + // 回复200 OK + responseAck(evt, Response.OK); + String uuid = UUID.randomUUID().toString().replace("-", ""); + RecordInfo recordInfo = new RecordInfo(); + Element rootElement = getRootElement(evt); + Element deviceIdElement = rootElement.element("DeviceID"); + String channelId = deviceIdElement.getText().toString(); + String key = DeferredResultHolder.CALLBACK_CMD_RECORDINFO + deviceId + channelId; + if (device != null ) { + rootElement = getRootElement(evt, device.getCharset()); + } + recordInfo.setDeviceId(deviceId); + recordInfo.setChannelId(channelId); + recordInfo.setName(getText(rootElement, "Name")); + if (getText(rootElement, "SumNum")== null || getText(rootElement, "SumNum") =="") { + recordInfo.setSumNum(0); + } else { + recordInfo.setSumNum(Integer.parseInt(getText(rootElement, "SumNum"))); + } + String sn = getText(rootElement, "SN"); + Element recordListElement = rootElement.element("RecordList"); + if (recordListElement == null || recordInfo.getSumNum() == 0) { + logger.info("无录像数据"); + RequestMessage msg = new RequestMessage(); + msg.setKey(key); + msg.setData(recordInfo); + deferredResultHolder.invokeAllResult(msg); + } else { + Iterator recordListIterator = recordListElement.elementIterator(); + List recordList = new ArrayList(); + if (recordListIterator != null) { + RecordItem record = new RecordItem(); + logger.info("处理录像列表数据..."); + // 遍历DeviceList + while (recordListIterator.hasNext()) { + Element itemRecord = recordListIterator.next(); + Element recordElement = itemRecord.element("DeviceID"); + if (recordElement == null) { + logger.info("记录为空,下一个..."); + continue; + } + record = new RecordItem(); + record.setDeviceId(getText(itemRecord, "DeviceID")); + record.setName(getText(itemRecord, "Name")); + record.setFilePath(getText(itemRecord, "FilePath")); + record.setAddress(getText(itemRecord, "Address")); + record.setStartTime( + DateUtil.ISO8601Toyyyy_MM_dd_HH_mm_ss(getText(itemRecord, "StartTime"))); + record.setEndTime( + DateUtil.ISO8601Toyyyy_MM_dd_HH_mm_ss(getText(itemRecord, "EndTime"))); + record.setSecrecy(itemRecord.element("Secrecy") == null ? 0 + : Integer.parseInt(getText(itemRecord, "Secrecy"))); + record.setType(getText(itemRecord, "Type")); + record.setRecorderId(getText(itemRecord, "RecorderID")); + recordList.add(record); + } + recordInfo.setRecordList(recordList); + } + + // 改用单独线程统计已获取录像文件数量,避免多包并行分别统计不完整的问题 + String cacheKey = CACHE_RECORDINFO_KEY + deviceId + sn; + redis.set(cacheKey + "_" + uuid, recordList, 90); + if (!threadNameList.contains(cacheKey)) { + threadNameList.add(cacheKey); + CheckForAllRecordsThread chk = new CheckForAllRecordsThread(cacheKey, recordInfo); + chk.setName(cacheKey); + chk.setDeferredResultHolder(deferredResultHolder); + chk.setRedis(redis); + chk.setLogger(logger); + chk.start(); + if (logger.isDebugEnabled()) { + logger.debug("Start Thread " + cacheKey + "."); + } + } else { + if (logger.isDebugEnabled()) { + logger.debug("Thread " + cacheKey + " already started."); + } + } + + // 存在录像且如果当前录像明细个数小于总条数,说明拆包返回,需要组装,暂不返回 + // if (recordInfo.getSumNum() > 0 && recordList.size() > 0 && recordList.size() < recordInfo.getSumNum()) { + // // 为防止连续请求该设备的录像数据,返回数据错乱,特增加sn进行区分 + // String cacheKey = CACHE_RECORDINFO_KEY + deviceId + sn; + + // redis.set(cacheKey + "_" + uuid, recordList, 90); + // List cacheKeys = redis.scan(cacheKey + "_*"); + // List totalRecordList = new ArrayList(); + // for (int i = 0; i < cacheKeys.size(); i++) { + // totalRecordList.addAll((List) redis.get(cacheKeys.get(i).toString())); + // } + // if (totalRecordList.size() < recordInfo.getSumNum()) { + // logger.info("已获取" + totalRecordList.size() + "项录像数据,共" + recordInfo.getSumNum() + "项"); + // return; + // } + // logger.info("录像数据已全部获取,共" + recordInfo.getSumNum() + "项"); + // recordInfo.setRecordList(totalRecordList); + // for (int i = 0; i < cacheKeys.size(); i++) { + // redis.del(cacheKeys.get(i).toString()); + // } + // } + // // 自然顺序排序, 元素进行升序排列 + // recordInfo.getRecordList().sort(Comparator.naturalOrder()); + } + // 走到这里,有以下可能:1、没有录像信息,第一次收到recordinfo的消息即返回响应数据,无redis操作 + // 2、有录像数据,且第一次即收到完整数据,返回响应数据,无redis操作 + // 3、有录像数据,在超时时间内收到多次包组装后数量足够,返回数据 + + // RequestMessage msg = new RequestMessage(); + // msg.setDeviceId(deviceId); + // msg.setType(DeferredResultHolder.CALLBACK_CMD_RECORDINFO); + // msg.setData(recordInfo); + // deferredResultHolder.invokeResult(msg); + // logger.info("处理完成,返回结果"); + } catch (DocumentException | SipException | InvalidArgumentException | ParseException e) { + e.printStackTrace(); + } + } + + /** + * 收到MediaStatus消息处理 + * + * @param evt + */ + private void processMessageMediaStatus(RequestEvent evt){ + try { + + String deviceId = SipUtils.getUserIdFromFromHeader(evt.getRequest()); + // 查询设备是否存在 + Device device = storager.queryVideoDevice(deviceId); + if (device == null) { + logger.warn("处理DeviceInfo设备信息Message时未找到设备信息"); + responseAck(evt, Response.NOT_FOUND); + return; + } + + // 回复200 OK + responseAck(evt, Response.OK); + Element rootElement = getRootElement(evt); + String channelId = getText(rootElement, "DeviceID"); + String NotifyType =getText(rootElement, "NotifyType"); + if (NotifyType.equals("121")){ + logger.info("媒体播放完毕,通知关流"); + StreamInfo streamInfo = redisCatchStorage.queryPlaybackByDevice(deviceId, "*"); + if (streamInfo != null) { + redisCatchStorage.stopPlayback(streamInfo); + cmder.streamByeCmd(streamInfo.getDeviceID(), streamInfo.getChannelId()); + } + } + } catch (ParseException | SipException | InvalidArgumentException | DocumentException e) { + e.printStackTrace(); + } + } + + /** + * 处理AudioBroadcast语音广播Message + * + * @param evt + */ + private void processMessageBroadcast(RequestEvent evt) { + try { + + String deviceId = SipUtils.getUserIdFromFromHeader(evt.getRequest()); + // 查询设备是否存在 + Device device = storager.queryVideoDevice(deviceId); + if (device == null) { + logger.warn("处理DeviceInfo设备信息Message时未找到设备信息"); + responseAck(evt, Response.NOT_FOUND); + return; + } + + Element rootElement = getRootElement(evt); + String channelId = getText(rootElement, "DeviceID"); + String key = DeferredResultHolder.CALLBACK_CMD_BROADCAST + deviceId + channelId; + // 回复200 OK + responseAck(evt, Response.OK); + if (rootElement.getName().equals("Response")) { + // 此处是对本平台发出Broadcast指令的应答 + JSONObject json = new JSONObject(); + XmlUtil.node2Json(rootElement, json); + if (logger.isDebugEnabled()) { + logger.debug(json.toJSONString()); + } + RequestMessage msg = new RequestMessage(); + msg.setKey(key); + msg.setData(json); + deferredResultHolder.invokeAllResult(msg); + } else { + // 此处是上级发出的Broadcast指令 + } + } catch (ParseException | SipException | InvalidArgumentException | DocumentException e) { + e.printStackTrace(); + } + } +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/NotifyRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/NotifyRequestProcessor.java similarity index 55% rename from src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/NotifyRequestProcessor.java rename to src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/NotifyRequestProcessor.java index 4c177697c..de97c1266 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/NotifyRequestProcessor.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/NotifyRequestProcessor.java @@ -1,67 +1,78 @@ -package com.genersoft.iot.vmp.gb28181.transmit.request.impl; - -import java.io.ByteArrayInputStream; -import java.text.ParseException; -import java.util.Iterator; - -import javax.sip.InvalidArgumentException; -import javax.sip.RequestEvent; -import javax.sip.ServerTransaction; -import javax.sip.SipException; -import javax.sip.message.Request; -import javax.sip.message.Response; +package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl; import com.genersoft.iot.vmp.common.VideoManagerConstants; import com.genersoft.iot.vmp.conf.UserSetup; -import com.genersoft.iot.vmp.gb28181.bean.BaiduPoint; -import com.genersoft.iot.vmp.gb28181.bean.Device; -import com.genersoft.iot.vmp.gb28181.bean.DeviceAlarm; -import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; -import com.genersoft.iot.vmp.gb28181.bean.MobilePosition; +import com.genersoft.iot.vmp.gb28181.bean.*; import com.genersoft.iot.vmp.gb28181.event.DeviceOffLineDetector; import com.genersoft.iot.vmp.gb28181.event.EventPublisher; +import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver; import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; -import com.genersoft.iot.vmp.gb28181.transmit.request.SIPRequestAbstractProcessor; +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.NumericUtil; +import com.genersoft.iot.vmp.gb28181.utils.SipUtils; import com.genersoft.iot.vmp.gb28181.utils.XmlUtil; import com.genersoft.iot.vmp.storager.IRedisCatchStorage; import com.genersoft.iot.vmp.storager.IVideoManagerStorager; import com.genersoft.iot.vmp.utils.GpsUtil; -import com.genersoft.iot.vmp.utils.SpringBeanFactory; import com.genersoft.iot.vmp.utils.redis.RedisUtil; - -import org.dom4j.Document; import org.dom4j.DocumentException; import org.dom4j.Element; -import org.dom4j.io.SAXReader; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; +import javax.sip.InvalidArgumentException; +import javax.sip.RequestEvent; +import javax.sip.SipException; +import javax.sip.header.FromHeader; +import javax.sip.message.Response; +import java.text.ParseException; +import java.util.Iterator; + /** - * @Description: Notify请求处理器 + * @description: Notify请求处理器 * @author: lawrencehj * @date: 2021年1月27日 */ +@Component +public class NotifyRequestProcessor extends SIPRequestProcessorParent implements InitializingBean, ISIPRequestProcessor { -public class NotifyRequestProcessor extends SIPRequestAbstractProcessor { - - private UserSetup userSetup = (UserSetup) SpringBeanFactory.getBean("userSetup"); - private final static Logger logger = LoggerFactory.getLogger(MessageRequestProcessor.class); + private final static Logger logger = LoggerFactory.getLogger(NotifyRequestProcessor.class); + @Autowired + private UserSetup userSetup; + + @Autowired private IVideoManagerStorager storager; + @Autowired private IRedisCatchStorage redisCatchStorage; + @Autowired private EventPublisher publisher; + @Autowired private DeviceOffLineDetector offLineDetector; private static final String NOTIFY_CATALOG = "Catalog"; private static final String NOTIFY_ALARM = "Alarm"; private static final String NOTIFY_MOBILE_POSITION = "MobilePosition"; + private String method = "NOTIFY"; + + @Autowired + private SIPProcessorObserver sipProcessorObserver; + + @Override + public void afterPropertiesSet() throws Exception { + // 添加消息处理的订阅 + sipProcessorObserver.addRequestProcessor(method, this); + } @Override public void process(RequestEvent evt) { @@ -80,7 +91,7 @@ public class NotifyRequestProcessor extends SIPRequestAbstractProcessor { processNotifyMobilePosition(evt); } else { logger.info("接收到消息:" + cmd); - response200Ok(evt); + responseAck(evt, Response.OK); } } catch (DocumentException | SipException | InvalidArgumentException | ParseException e) { e.printStackTrace(); @@ -135,7 +146,7 @@ public class NotifyRequestProcessor extends SIPRequestAbstractProcessor { storager.clearMobilePositionsByDeviceId(deviceId); } storager.insertMobilePosition(mobilePosition); - response200Ok(evt); + responseAck(evt, Response.OK); } catch (DocumentException | SipException | InvalidArgumentException | ParseException e) { e.printStackTrace(); } @@ -199,7 +210,7 @@ public class NotifyRequestProcessor extends SIPRequestAbstractProcessor { // TODO: 需要实现存储报警信息、报警分类 // 回复200 OK - response200Ok(evt); + responseAck(evt, Response.OK); if (offLineDetector.isOnline(deviceId)) { publisher.deviceAlarmEventPublish(deviceAlarm); } @@ -215,10 +226,16 @@ public class NotifyRequestProcessor extends SIPRequestAbstractProcessor { */ private void processNotifyCatalogList(RequestEvent evt) { try { + FromHeader fromHeader = (FromHeader) evt.getRequest().getHeader(FromHeader.NAME); + String deviceId = SipUtils.getUserIdFromFromHeader(fromHeader); + Element rootElement = getRootElement(evt); Element deviceIdElement = rootElement.element("DeviceID"); - String deviceId = deviceIdElement.getText(); + String channelId = deviceIdElement.getText(); Device device = storager.queryVideoDevice(deviceId); + if (device == null) { + return; + } if (device != null ) { rootElement = getRootElement(evt, device.getCharset()); } @@ -228,9 +245,7 @@ public class NotifyRequestProcessor extends SIPRequestAbstractProcessor { } Iterator deviceListIterator = deviceListElement.elementIterator(); if (deviceListIterator != null) { - if (device == null) { - return; - } + // 遍历DeviceList while (deviceListIterator.hasNext()) { Element itemDevice = deviceListIterator.next(); @@ -238,87 +253,52 @@ public class NotifyRequestProcessor extends SIPRequestAbstractProcessor { if (channelDeviceElement == null) { continue; } - String channelDeviceId = channelDeviceElement.getTextTrim(); - Element channdelNameElement = itemDevice.element("Name"); - String channelName = channdelNameElement != null ? channdelNameElement.getTextTrim().toString() : ""; - Element statusElement = itemDevice.element("Status"); - String status = statusElement != null ? statusElement.getTextTrim().toString() : "ON"; - DeviceChannel deviceChannel = new DeviceChannel(); - deviceChannel.setName(channelName); - deviceChannel.setChannelId(channelDeviceId); - // ONLINE OFFLINE HIKVISION DS-7716N-E4 NVR的兼容性处理 - if (status.equals("ON") || status.equals("On") || status.equals("ONLINE")) { - deviceChannel.setStatus(1); - } - if (status.equals("OFF") || status.equals("Off") || status.equals("OFFLINE")) { - deviceChannel.setStatus(0); + Element eventElement = itemDevice.element("Event"); + switch (eventElement.getText().toUpperCase()) { + case "ON" : // 上线 + logger.info("收到来自设备【{}】的通道上线【{}】通知", device.getDeviceId(), channelId); + storager.deviceChannelOnline(deviceId, channelId); + // 回复200 OK + responseAck(evt, Response.OK); + break; + case "OFF" : // 离线 + logger.info("收到来自设备【{}】的通道离线【{}】通知", device.getDeviceId(), channelId); + storager.deviceChannelOffline(deviceId, channelId); + // 回复200 OK + responseAck(evt, Response.OK); + break; + case "VLOST" : // 视频丢失 + logger.info("收到来自设备【{}】的通道视频丢失【{}】通知", device.getDeviceId(), channelId); + storager.deviceChannelOffline(deviceId, channelId); + // 回复200 OK + responseAck(evt, Response.OK); + break; + case "DEFECT" : // 故障 + // 回复200 OK + responseAck(evt, Response.OK); + break; + case "ADD" : // 增加 + logger.info("收到来自设备【{}】的增加通道【{}】通知", device.getDeviceId(), channelId); + DeviceChannel deviceChannel = channelContentHander(itemDevice, channelId); + storager.updateChannel(deviceId, deviceChannel); + responseAck(evt, Response.OK); + break; + case "DEL" : // 删除 + logger.info("收到来自设备【{}】的删除通道【{}】通知", device.getDeviceId(), channelId); + storager.delChannel(deviceId, channelId); + responseAck(evt, Response.OK); + break; + case "UPDATE" : // 更新 + logger.info("收到来自设备【{}】的更新通道【{}】通知", device.getDeviceId(), channelId); + DeviceChannel channel = channelContentHander(itemDevice, channelId); + storager.updateChannel(deviceId, channel); + responseAck(evt, Response.OK); + break; + default: + responseAck(evt, Response.BAD_REQUEST, "event not found"); + } - deviceChannel.setManufacture(XmlUtil.getText(itemDevice, "Manufacturer")); - deviceChannel.setModel(XmlUtil.getText(itemDevice, "Model")); - deviceChannel.setOwner(XmlUtil.getText(itemDevice, "Owner")); - deviceChannel.setCivilCode(XmlUtil.getText(itemDevice, "CivilCode")); - deviceChannel.setBlock(XmlUtil.getText(itemDevice, "Block")); - deviceChannel.setAddress(XmlUtil.getText(itemDevice, "Address")); - if (XmlUtil.getText(itemDevice, "Parental") == null - || XmlUtil.getText(itemDevice, "Parental") == "") { - deviceChannel.setParental(0); - } else { - deviceChannel.setParental(Integer.parseInt(XmlUtil.getText(itemDevice, "Parental"))); - } - deviceChannel.setParentId(XmlUtil.getText(itemDevice, "ParentID")); - if (XmlUtil.getText(itemDevice, "SafetyWay") == null - || XmlUtil.getText(itemDevice, "SafetyWay") == "") { - deviceChannel.setSafetyWay(0); - } else { - deviceChannel.setSafetyWay(Integer.parseInt(XmlUtil.getText(itemDevice, "SafetyWay"))); - } - if (XmlUtil.getText(itemDevice, "RegisterWay") == null - || XmlUtil.getText(itemDevice, "RegisterWay") == "") { - deviceChannel.setRegisterWay(1); - } else { - deviceChannel.setRegisterWay(Integer.parseInt(XmlUtil.getText(itemDevice, "RegisterWay"))); - } - deviceChannel.setCertNum(XmlUtil.getText(itemDevice, "CertNum")); - if (XmlUtil.getText(itemDevice, "Certifiable") == null - || XmlUtil.getText(itemDevice, "Certifiable") == "") { - deviceChannel.setCertifiable(0); - } else { - deviceChannel.setCertifiable(Integer.parseInt(XmlUtil.getText(itemDevice, "Certifiable"))); - } - if (XmlUtil.getText(itemDevice, "ErrCode") == null - || XmlUtil.getText(itemDevice, "ErrCode") == "") { - deviceChannel.setErrCode(0); - } else { - deviceChannel.setErrCode(Integer.parseInt(XmlUtil.getText(itemDevice, "ErrCode"))); - } - deviceChannel.setEndTime(XmlUtil.getText(itemDevice, "EndTime")); - deviceChannel.setSecrecy(XmlUtil.getText(itemDevice, "Secrecy")); - deviceChannel.setIpAddress(XmlUtil.getText(itemDevice, "IPAddress")); - if (XmlUtil.getText(itemDevice, "Port") == null || XmlUtil.getText(itemDevice, "Port") == "") { - deviceChannel.setPort(0); - } else { - deviceChannel.setPort(Integer.parseInt(XmlUtil.getText(itemDevice, "Port"))); - } - deviceChannel.setPassword(XmlUtil.getText(itemDevice, "Password")); - if (NumericUtil.isDouble(XmlUtil.getText(itemDevice, "Longitude"))) { - deviceChannel.setLongitude(Double.parseDouble(XmlUtil.getText(itemDevice, "Longitude"))); - } else { - deviceChannel.setLongitude(0.00); - } - if (NumericUtil.isDouble(XmlUtil.getText(itemDevice, "Latitude"))) { - deviceChannel.setLatitude(Double.parseDouble(XmlUtil.getText(itemDevice, "Latitude"))); - } else { - deviceChannel.setLatitude(0.00); - } - if (XmlUtil.getText(itemDevice, "PTZType") == null - || XmlUtil.getText(itemDevice, "PTZType") == "") { - deviceChannel.setPTZType(0); - } else { - deviceChannel.setPTZType(Integer.parseInt(XmlUtil.getText(itemDevice, "PTZType"))); - } - deviceChannel.setHasAudio(true); // 默认含有音频,播放时再检查是否有音频及是否AAC - storager.updateChannel(device.getDeviceId(), deviceChannel); } // RequestMessage msg = new RequestMessage(); @@ -326,8 +306,7 @@ public class NotifyRequestProcessor extends SIPRequestAbstractProcessor { // msg.setType(DeferredResultHolder.CALLBACK_CMD_CATALOG); // msg.setData(device); // deferredResultHolder.invokeResult(msg); - // 回复200 OK - response200Ok(evt); + if (offLineDetector.isOnline(deviceId)) { publisher.onlineEventPublish(device, VideoManagerConstants.EVENT_ONLINE_MESSAGE); } @@ -337,32 +316,91 @@ public class NotifyRequestProcessor extends SIPRequestAbstractProcessor { } } - /*** - * 回复200 OK - * - * @param evt - * @throws SipException - * @throws InvalidArgumentException - * @throws ParseException - */ - private void response200Ok(RequestEvent evt) throws SipException, InvalidArgumentException, ParseException { - Response response = getMessageFactory().createResponse(Response.OK, evt.getRequest()); - ServerTransaction serverTransaction = getServerTransaction(evt); - serverTransaction.sendResponse(response); - if (serverTransaction.getDialog() != null) serverTransaction.getDialog().delete(); - } - private Element getRootElement(RequestEvent evt) throws DocumentException { - return getRootElement(evt, "gb2312"); - } - private Element getRootElement(RequestEvent evt, String charset) throws DocumentException { - if (charset == null) charset = "gb2312"; - Request request = evt.getRequest(); - SAXReader reader = new SAXReader(); - reader.setEncoding(charset); - Document xml = reader.read(new ByteArrayInputStream(request.getRawContent())); - return xml.getRootElement(); + public DeviceChannel channelContentHander(Element itemDevice, String channelId){ + Element channdelNameElement = itemDevice.element("Name"); + String channelName = channdelNameElement != null ? channdelNameElement.getTextTrim().toString() : ""; + Element statusElement = itemDevice.element("Status"); + String status = statusElement != null ? statusElement.getTextTrim().toString() : "ON"; + DeviceChannel deviceChannel = new DeviceChannel(); + deviceChannel.setName(channelName); + deviceChannel.setChannelId(channelId); + // ONLINE OFFLINE HIKVISION DS-7716N-E4 NVR的兼容性处理 + if (status.equals("ON") || status.equals("On") || status.equals("ONLINE")) { + deviceChannel.setStatus(1); + } + if (status.equals("OFF") || status.equals("Off") || status.equals("OFFLINE")) { + deviceChannel.setStatus(0); + } + + deviceChannel.setManufacture(XmlUtil.getText(itemDevice, "Manufacturer")); + deviceChannel.setModel(XmlUtil.getText(itemDevice, "Model")); + deviceChannel.setOwner(XmlUtil.getText(itemDevice, "Owner")); + deviceChannel.setCivilCode(XmlUtil.getText(itemDevice, "CivilCode")); + deviceChannel.setBlock(XmlUtil.getText(itemDevice, "Block")); + deviceChannel.setAddress(XmlUtil.getText(itemDevice, "Address")); + if (XmlUtil.getText(itemDevice, "Parental") == null + || XmlUtil.getText(itemDevice, "Parental") == "") { + deviceChannel.setParental(0); + } else { + deviceChannel.setParental(Integer.parseInt(XmlUtil.getText(itemDevice, "Parental"))); + } + deviceChannel.setParentId(XmlUtil.getText(itemDevice, "ParentID")); + if (XmlUtil.getText(itemDevice, "SafetyWay") == null + || XmlUtil.getText(itemDevice, "SafetyWay") == "") { + deviceChannel.setSafetyWay(0); + } else { + deviceChannel.setSafetyWay(Integer.parseInt(XmlUtil.getText(itemDevice, "SafetyWay"))); + } + if (XmlUtil.getText(itemDevice, "RegisterWay") == null + || XmlUtil.getText(itemDevice, "RegisterWay") == "") { + deviceChannel.setRegisterWay(1); + } else { + deviceChannel.setRegisterWay(Integer.parseInt(XmlUtil.getText(itemDevice, "RegisterWay"))); + } + deviceChannel.setCertNum(XmlUtil.getText(itemDevice, "CertNum")); + if (XmlUtil.getText(itemDevice, "Certifiable") == null + || XmlUtil.getText(itemDevice, "Certifiable") == "") { + deviceChannel.setCertifiable(0); + } else { + deviceChannel.setCertifiable(Integer.parseInt(XmlUtil.getText(itemDevice, "Certifiable"))); + } + if (XmlUtil.getText(itemDevice, "ErrCode") == null + || XmlUtil.getText(itemDevice, "ErrCode") == "") { + deviceChannel.setErrCode(0); + } else { + deviceChannel.setErrCode(Integer.parseInt(XmlUtil.getText(itemDevice, "ErrCode"))); + } + deviceChannel.setEndTime(XmlUtil.getText(itemDevice, "EndTime")); + deviceChannel.setSecrecy(XmlUtil.getText(itemDevice, "Secrecy")); + deviceChannel.setIpAddress(XmlUtil.getText(itemDevice, "IPAddress")); + if (XmlUtil.getText(itemDevice, "Port") == null || XmlUtil.getText(itemDevice, "Port") == "") { + deviceChannel.setPort(0); + } else { + deviceChannel.setPort(Integer.parseInt(XmlUtil.getText(itemDevice, "Port"))); + } + deviceChannel.setPassword(XmlUtil.getText(itemDevice, "Password")); + if (NumericUtil.isDouble(XmlUtil.getText(itemDevice, "Longitude"))) { + deviceChannel.setLongitude(Double.parseDouble(XmlUtil.getText(itemDevice, "Longitude"))); + } else { + deviceChannel.setLongitude(0.00); + } + if (NumericUtil.isDouble(XmlUtil.getText(itemDevice, "Latitude"))) { + deviceChannel.setLatitude(Double.parseDouble(XmlUtil.getText(itemDevice, "Latitude"))); + } else { + deviceChannel.setLatitude(0.00); + } + if (XmlUtil.getText(itemDevice, "PTZType") == null + || XmlUtil.getText(itemDevice, "PTZType") == "") { + deviceChannel.setPTZType(0); + } else { + deviceChannel.setPTZType(Integer.parseInt(XmlUtil.getText(itemDevice, "PTZType"))); + } + deviceChannel.setHasAudio(true); // 默认含有音频,播放时再检查是否有音频及是否AAC + return deviceChannel; } + + public void setCmder(SIPCommander cmder) { } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/RegisterRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/RegisterRequestProcessor.java similarity index 86% rename from src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/RegisterRequestProcessor.java rename to src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/RegisterRequestProcessor.java index c70988aa1..10e99cb7d 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/RegisterRequestProcessor.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/RegisterRequestProcessor.java @@ -1,201 +1,199 @@ -package com.genersoft.iot.vmp.gb28181.transmit.request.impl; - -import java.security.NoSuchAlgorithmException; -import java.text.ParseException; -import java.util.Calendar; -import java.util.Locale; - -import javax.sip.InvalidArgumentException; -import javax.sip.RequestEvent; -import javax.sip.ServerTransaction; -import javax.sip.SipException; -import javax.sip.header.AuthorizationHeader; -import javax.sip.header.ContactHeader; -import javax.sip.header.ExpiresHeader; -import javax.sip.header.FromHeader; -import javax.sip.header.ViaHeader; -import javax.sip.message.Request; -import javax.sip.message.Response; - -import com.genersoft.iot.vmp.gb28181.bean.WvpSipDate; -import gov.nist.javax.sip.RequestEventExt; -import gov.nist.javax.sip.header.SIPDateHeader; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.util.StringUtils; - -import com.genersoft.iot.vmp.common.VideoManagerConstants; -import com.genersoft.iot.vmp.conf.SipConfig; -import com.genersoft.iot.vmp.gb28181.auth.DigestServerAuthenticationHelper; -import com.genersoft.iot.vmp.gb28181.auth.RegisterLogicHandler; -import com.genersoft.iot.vmp.gb28181.bean.Device; -import com.genersoft.iot.vmp.gb28181.event.EventPublisher; -import com.genersoft.iot.vmp.gb28181.transmit.request.SIPRequestAbstractProcessor; -import com.genersoft.iot.vmp.storager.IVideoManagerStorager; - -import gov.nist.javax.sip.address.AddressImpl; -import gov.nist.javax.sip.address.SipUri; -import gov.nist.javax.sip.header.Expires; - -/** - * @Description:收到注册请求 处理 - * @author: swwheihei - * @date: 2020年5月3日 下午4:47:25 - */ -public class RegisterRequestProcessor extends SIPRequestAbstractProcessor { - - private Logger logger = LoggerFactory.getLogger(RegisterRequestProcessor.class); - - private SipConfig sipConfig; - - private RegisterLogicHandler handler; - - private IVideoManagerStorager storager; - - private EventPublisher publisher; - - /** - * 收到注册请求 处理 - * @param evt - */ - @Override - public void process(RequestEvent evt) { - try { - RequestEventExt evtExt = (RequestEventExt)evt; - String requestAddress = evtExt.getRemoteIpAddress() + ":" + evtExt.getRemotePort(); - logger.info("[{}] 收到注册请求,开始处理", requestAddress); - Request request = evt.getRequest(); - - Response response = null; - boolean passwordCorrect = false; - // 注册标志 0:未携带授权头或者密码错误 1:注册成功 2:注销成功 - int registerFlag = 0; - FromHeader fromHeader = (FromHeader) request.getHeader(FromHeader.NAME); - AddressImpl address = (AddressImpl) fromHeader.getAddress(); - SipUri uri = (SipUri) address.getURI(); - String deviceId = uri.getUser(); - Device device = storager.queryVideoDevice(deviceId); - AuthorizationHeader authorhead = (AuthorizationHeader) request.getHeader(AuthorizationHeader.NAME); - // 校验密码是否正确 - if (authorhead != null) { - passwordCorrect = new DigestServerAuthenticationHelper().doAuthenticatePlainTextPassword(request, - sipConfig.getPassword()); - } - if (StringUtils.isEmpty(sipConfig.getPassword())){ - passwordCorrect = true; - } - - // 未携带授权头或者密码错误 回复401 - if (authorhead == null ) { - - logger.info("[{}] 未携带授权头 回复401", requestAddress); - response = getMessageFactory().createResponse(Response.UNAUTHORIZED, request); - new DigestServerAuthenticationHelper().generateChallenge(getHeaderFactory(), response, sipConfig.getDomain()); - }else { - if (!passwordCorrect){ - // 注册失败 - response = getMessageFactory().createResponse(Response.FORBIDDEN, request); - response.setReasonPhrase("wrong password"); - logger.info("[{}] 密码/SIP服务器ID错误, 回复403", requestAddress); - }else { - // 携带授权头并且密码正确 - response = getMessageFactory().createResponse(Response.OK, request); - // 添加date头 - SIPDateHeader dateHeader = new SIPDateHeader(); - // 使用自己修改的 - WvpSipDate wvpSipDate = new WvpSipDate(Calendar.getInstance(Locale.ENGLISH).getTimeInMillis()); - dateHeader.setDate(wvpSipDate); - response.addHeader(dateHeader); - - ExpiresHeader expiresHeader = (ExpiresHeader) request.getHeader(Expires.NAME); - if (expiresHeader == null) { - response = getMessageFactory().createResponse(Response.BAD_REQUEST, request); - ServerTransaction serverTransaction = getServerTransaction(evt); - serverTransaction.sendResponse(response); - if (serverTransaction.getDialog() != null) serverTransaction.getDialog().delete(); - return; - } - // 添加Contact头 - response.addHeader(request.getHeader(ContactHeader.NAME)); - // 添加Expires头 - response.addHeader(request.getExpires()); - - // 获取到通信地址等信息 - ViaHeader viaHeader = (ViaHeader) request.getHeader(ViaHeader.NAME); - String received = viaHeader.getReceived(); - int rPort = viaHeader.getRPort(); - // 解析本地地址替代 - if (StringUtils.isEmpty(received) || rPort == -1) { - received = viaHeader.getHost(); - rPort = viaHeader.getPort(); - } - // - - if (device == null) { - device = new Device(); - device.setStreamMode("UDP"); - device.setCharset("gb2312"); - device.setDeviceId(deviceId); - device.setFirsRegister(true); - } - device.setIp(received); - device.setPort(rPort); - device.setHostAddress(received.concat(":").concat(String.valueOf(rPort))); - // 注销成功 - if (expiresHeader.getExpires() == 0) { - registerFlag = 2; - } - // 注册成功 - else { - device.setExpires(expiresHeader.getExpires()); - registerFlag = 1; - // 判断TCP还是UDP - boolean isTcp = false; - ViaHeader reqViaHeader = (ViaHeader) request.getHeader(ViaHeader.NAME); - String transport = reqViaHeader.getTransport(); - if (transport.equals("TCP")) { - isTcp = true; - } - device.setTransport(isTcp ? "TCP" : "UDP"); - } - } - } - - ServerTransaction serverTransaction = getServerTransaction(evt); - serverTransaction.sendResponse(response); - if (serverTransaction.getDialog() != null) serverTransaction.getDialog().delete(); - // 注册成功 - // 保存到redis - // 下发catelog查询目录 - if (registerFlag == 1 ) { - logger.info("[{}] 注册成功! deviceId:" + device.getDeviceId(), requestAddress); - publisher.onlineEventPublish(device, VideoManagerConstants.EVENT_ONLINE_REGISTER); - // 重新注册更新设备和通道,以免设备替换或更新后信息无法更新 - handler.onRegister(device); - } else if (registerFlag == 2) { - logger.info("[{}] 注销成功! deviceId:" + device.getDeviceId(), requestAddress); - publisher.outlineEventPublish(device.getDeviceId(), VideoManagerConstants.EVENT_OUTLINE_UNREGISTER); - } - } catch (SipException | InvalidArgumentException | NoSuchAlgorithmException | ParseException e) { - e.printStackTrace(); - } - - } - - public void setSipConfig(SipConfig sipConfig) { - this.sipConfig = sipConfig; - } - - public void setHandler(RegisterLogicHandler handler) { - this.handler = handler; - } - - public void setVideoManagerStorager(IVideoManagerStorager storager) { - this.storager = storager; - } - - public void setPublisher(EventPublisher publisher) { - this.publisher = publisher; - } - -} +package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl; + +import com.genersoft.iot.vmp.common.VideoManagerConstants; +import com.genersoft.iot.vmp.conf.SipConfig; +import com.genersoft.iot.vmp.gb28181.auth.DigestServerAuthenticationHelper; +import com.genersoft.iot.vmp.gb28181.auth.RegisterLogicHandler; +import com.genersoft.iot.vmp.gb28181.bean.Device; +import com.genersoft.iot.vmp.gb28181.bean.WvpSipDate; +import com.genersoft.iot.vmp.gb28181.event.EventPublisher; +import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver; +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.storager.IVideoManagerStorager; +import gov.nist.javax.sip.RequestEventExt; +import gov.nist.javax.sip.address.AddressImpl; +import gov.nist.javax.sip.address.SipUri; +import gov.nist.javax.sip.header.Expires; +import gov.nist.javax.sip.header.SIPDateHeader; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.util.StringUtils; + +import javax.sip.InvalidArgumentException; +import javax.sip.RequestEvent; +import javax.sip.ServerTransaction; +import javax.sip.SipException; +import javax.sip.header.*; +import javax.sip.message.Request; +import javax.sip.message.Response; +import java.security.NoSuchAlgorithmException; +import java.text.ParseException; +import java.util.Calendar; +import java.util.Locale; + +/** + * @description:收到注册请求 处理 + * @author: swwheihei + * @date: 2020年5月3日 下午4:47:25 + */ +@Component +public class RegisterRequestProcessor extends SIPRequestProcessorParent implements InitializingBean, ISIPRequestProcessor { + + private Logger logger = LoggerFactory.getLogger(RegisterRequestProcessor.class); + + public String method = "REGISTER"; + + @Autowired + private SipConfig sipConfig; + + @Autowired + private RegisterLogicHandler handler; + + @Autowired + private IVideoManagerStorager storager; + + @Autowired + private EventPublisher publisher; + + @Autowired + private SIPProcessorObserver sipProcessorObserver; + + @Override + public void afterPropertiesSet() throws Exception { + // 添加消息处理的订阅 + sipProcessorObserver.addRequestProcessor(method, this); + } + + /** + * 收到注册请求 处理 + * @param evt + */ + @Override + public void process(RequestEvent evt) { + try { + RequestEventExt evtExt = (RequestEventExt)evt; + String requestAddress = evtExt.getRemoteIpAddress() + ":" + evtExt.getRemotePort(); + logger.info("[{}] 收到注册请求,开始处理", requestAddress); + Request request = evt.getRequest(); + + Response response = null; + boolean passwordCorrect = false; + // 注册标志 0:未携带授权头或者密码错误 1:注册成功 2:注销成功 + int registerFlag = 0; + FromHeader fromHeader = (FromHeader) request.getHeader(FromHeader.NAME); + AddressImpl address = (AddressImpl) fromHeader.getAddress(); + SipUri uri = (SipUri) address.getURI(); + String deviceId = uri.getUser(); + Device device = storager.queryVideoDevice(deviceId); + AuthorizationHeader authorhead = (AuthorizationHeader) request.getHeader(AuthorizationHeader.NAME); + // 校验密码是否正确 + if (authorhead != null) { + passwordCorrect = new DigestServerAuthenticationHelper().doAuthenticatePlainTextPassword(request, + sipConfig.getPassword()); + } + if (StringUtils.isEmpty(sipConfig.getPassword())){ + passwordCorrect = true; + } + + // 未携带授权头或者密码错误 回复401 + if (authorhead == null ) { + + logger.info("[{}] 未携带授权头 回复401", requestAddress); + response = getMessageFactory().createResponse(Response.UNAUTHORIZED, request); + new DigestServerAuthenticationHelper().generateChallenge(getHeaderFactory(), response, sipConfig.getDomain()); + }else { + if (!passwordCorrect){ + // 注册失败 + response = getMessageFactory().createResponse(Response.FORBIDDEN, request); + response.setReasonPhrase("wrong password"); + logger.info("[{}] 密码/SIP服务器ID错误, 回复403", requestAddress); + }else { + // 携带授权头并且密码正确 + response = getMessageFactory().createResponse(Response.OK, request); + // 添加date头 + SIPDateHeader dateHeader = new SIPDateHeader(); + // 使用自己修改的 + WvpSipDate wvpSipDate = new WvpSipDate(Calendar.getInstance(Locale.ENGLISH).getTimeInMillis()); + dateHeader.setDate(wvpSipDate); + response.addHeader(dateHeader); + + ExpiresHeader expiresHeader = (ExpiresHeader) request.getHeader(Expires.NAME); + if (expiresHeader == null) { + response = getMessageFactory().createResponse(Response.BAD_REQUEST, request); + ServerTransaction serverTransaction = getServerTransaction(evt); + serverTransaction.sendResponse(response); + if (serverTransaction.getDialog() != null) serverTransaction.getDialog().delete(); + return; + } + // 添加Contact头 + response.addHeader(request.getHeader(ContactHeader.NAME)); + // 添加Expires头 + response.addHeader(request.getExpires()); + + // 获取到通信地址等信息 + ViaHeader viaHeader = (ViaHeader) request.getHeader(ViaHeader.NAME); + String received = viaHeader.getReceived(); + int rPort = viaHeader.getRPort(); + // 解析本地地址替代 + if (StringUtils.isEmpty(received) || rPort == -1) { + received = viaHeader.getHost(); + rPort = viaHeader.getPort(); + } + // + + if (device == null) { + device = new Device(); + device.setStreamMode("UDP"); + device.setCharset("gb2312"); + device.setDeviceId(deviceId); + device.setFirsRegister(true); + } + device.setIp(received); + device.setPort(rPort); + device.setHostAddress(received.concat(":").concat(String.valueOf(rPort))); + // 注销成功 + if (expiresHeader.getExpires() == 0) { + registerFlag = 2; + } + // 注册成功 + else { + device.setExpires(expiresHeader.getExpires()); + registerFlag = 1; + // 判断TCP还是UDP + boolean isTcp = false; + ViaHeader reqViaHeader = (ViaHeader) request.getHeader(ViaHeader.NAME); + String transport = reqViaHeader.getTransport(); + if (transport.equals("TCP")) { + isTcp = true; + } + device.setTransport(isTcp ? "TCP" : "UDP"); + } + } + } + + ServerTransaction serverTransaction = getServerTransaction(evt); + serverTransaction.sendResponse(response); + if (serverTransaction.getDialog() != null) serverTransaction.getDialog().delete(); + // 注册成功 + // 保存到redis + // 下发catelog查询目录 + if (registerFlag == 1 ) { + logger.info("[{}] 注册成功! deviceId:" + device.getDeviceId(), requestAddress); + publisher.onlineEventPublish(device, VideoManagerConstants.EVENT_ONLINE_REGISTER); + // 重新注册更新设备和通道,以免设备替换或更新后信息无法更新 + handler.onRegister(device); + } else if (registerFlag == 2) { + logger.info("[{}] 注销成功! deviceId:" + device.getDeviceId(), requestAddress); + publisher.outlineEventPublish(device.getDeviceId(), VideoManagerConstants.EVENT_OUTLINE_UNREGISTER); + } + } catch (SipException | InvalidArgumentException | NoSuchAlgorithmException | ParseException e) { + e.printStackTrace(); + } + + } + +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/SubscribeRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/SubscribeRequestProcessor.java similarity index 61% rename from src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/SubscribeRequestProcessor.java rename to src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/SubscribeRequestProcessor.java index 6d617638c..ba835dbe9 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/SubscribeRequestProcessor.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/SubscribeRequestProcessor.java @@ -1,62 +1,77 @@ -package com.genersoft.iot.vmp.gb28181.transmit.request.impl; - -import java.text.ParseException; - -import javax.sip.InvalidArgumentException; -import javax.sip.RequestEvent; -import javax.sip.ServerTransaction; -import javax.sip.SipException; -import javax.sip.header.ExpiresHeader; -import javax.sip.message.Request; -import javax.sip.message.Response; - -import com.genersoft.iot.vmp.gb28181.transmit.request.SIPRequestAbstractProcessor; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * @Description:SUBSCRIBE请求处理器 - * @author: swwheihei - * @date: 2020年5月3日 下午5:31:20 - */ -public class SubscribeRequestProcessor extends SIPRequestAbstractProcessor { - - private Logger logger = LoggerFactory.getLogger(SubscribeRequestProcessor.class); - - /** - * 处理SUBSCRIBE请求 - * - * @param evt - */ - @Override - public void process(RequestEvent evt) { - Request request = evt.getRequest(); - - try { - Response response = null; - response = getMessageFactory().createResponse(200, request); - if (response != null) { - ExpiresHeader expireHeader = getHeaderFactory().createExpiresHeader(30); - response.setExpires(expireHeader); - } - logger.info("response : " + response.toString()); - ServerTransaction transaction = getServerTransaction(evt); - if (transaction != null) { - transaction.sendResponse(response); - transaction.getDialog().delete(); - transaction.terminate(); - } else { - logger.info("processRequest serverTransactionId is null."); - } - - } catch (ParseException e) { - e.printStackTrace(); - } catch (SipException e) { - e.printStackTrace(); - } catch (InvalidArgumentException e) { - e.printStackTrace(); - } - - } - -} +package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl; + +import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver; +import com.genersoft.iot.vmp.gb28181.transmit.event.request.ISIPRequestProcessor; +import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import javax.sip.InvalidArgumentException; +import javax.sip.RequestEvent; +import javax.sip.ServerTransaction; +import javax.sip.SipException; +import javax.sip.header.ExpiresHeader; +import javax.sip.message.Request; +import javax.sip.message.Response; +import java.text.ParseException; + +/** + * @description:SUBSCRIBE请求处理器 + * @author: swwheihei + * @date: 2020年5月3日 下午5:31:20 + */ +@Component +public class SubscribeRequestProcessor extends SIPRequestProcessorParent implements InitializingBean, ISIPRequestProcessor { + + private Logger logger = LoggerFactory.getLogger(SubscribeRequestProcessor.class); + private String method = "SUBSCRIBE"; + + @Autowired + private SIPProcessorObserver sipProcessorObserver; + + @Override + public void afterPropertiesSet() throws Exception { + // 添加消息处理的订阅 + sipProcessorObserver.addRequestProcessor(method, this); + } + + /** + * 处理SUBSCRIBE请求 + * + * @param evt + */ + @Override + public void process(RequestEvent evt) { + Request request = evt.getRequest(); + + try { + Response response = null; + response = getMessageFactory().createResponse(200, request); + if (response != null) { + ExpiresHeader expireHeader = getHeaderFactory().createExpiresHeader(30); + response.setExpires(expireHeader); + } + logger.info("response : " + response.toString()); + ServerTransaction transaction = getServerTransaction(evt); + if (transaction != null) { + transaction.sendResponse(response); + transaction.getDialog().delete(); + transaction.terminate(); + } else { + logger.info("processRequest serverTransactionId is null."); + } + + } catch (ParseException e) { + e.printStackTrace(); + } catch (SipException e) { + e.printStackTrace(); + } catch (InvalidArgumentException e) { + e.printStackTrace(); + } + + } + +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/IMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/IMessageHandler.java new file mode 100644 index 000000000..7eba0d52a --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/IMessageHandler.java @@ -0,0 +1,23 @@ +package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message; + +import com.genersoft.iot.vmp.gb28181.bean.Device; +import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; +import org.dom4j.Element; + +import javax.sip.RequestEvent; + +public interface IMessageHandler { + /** + * 处理来自设备的信息 + * @param evt + * @param device + */ + void handForDevice(RequestEvent evt, Device device, Element element); + + /** + * 处理来自平台的信息 + * @param evt + * @param parentPlatform + */ + void handForPlatform(RequestEvent evt, ParentPlatform parentPlatform, Element element); +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/MessageHandlerAbstract.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/MessageHandlerAbstract.java new file mode 100644 index 000000000..efc8259cf --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/MessageHandlerAbstract.java @@ -0,0 +1,43 @@ +package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message; + +import com.genersoft.iot.vmp.gb28181.bean.Device; +import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; +import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent; +import org.dom4j.Element; +import org.springframework.beans.factory.annotation.Autowired; + +import javax.sip.RequestEvent; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import static com.genersoft.iot.vmp.gb28181.utils.XmlUtil.getText; + +public abstract class MessageHandlerAbstract extends SIPRequestProcessorParent implements IMessageHandler{ + + public static Map messageHandlerMap = new ConcurrentHashMap<>(); + + @Autowired + public MessageRequestProcessor messageRequestProcessor; + + public void addHandler(String cmdType, IMessageHandler messageHandler) { + messageHandlerMap.put(cmdType, messageHandler); + } + + @Override + public void handForDevice(RequestEvent evt, Device device, Element element) { + String cmd = getText(element, "CmdType"); + IMessageHandler messageHandler = messageHandlerMap.get(cmd); + if (messageHandler != null) { + messageHandler.handForDevice(evt, device, element); + } + } + + @Override + public void handForPlatform(RequestEvent evt, ParentPlatform parentPlatform, Element element) { + String cmd = getText(element, "CmdType"); + IMessageHandler messageHandler = messageHandlerMap.get(cmd); + if (messageHandler != null) { + messageHandler.handForPlatform(evt, parentPlatform, element); + } + } +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/MessageRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/MessageRequestProcessor.java new file mode 100644 index 000000000..241ee68f5 --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/MessageRequestProcessor.java @@ -0,0 +1,91 @@ +package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message; + +import com.genersoft.iot.vmp.gb28181.bean.Device; +import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; +import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver; +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.storager.IVideoManagerStorager; +import org.dom4j.DocumentException; +import org.dom4j.Element; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import javax.sip.InvalidArgumentException; +import javax.sip.RequestEvent; +import javax.sip.SipException; +import javax.sip.message.Response; +import java.text.ParseException; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +@Component +public class MessageRequestProcessor extends SIPRequestProcessorParent implements InitializingBean, ISIPRequestProcessor { + + private final static Logger logger = LoggerFactory.getLogger(MessageRequestProcessor.class); + + private final String method = "MESSAGE"; + + private static Map messageHandlerMap = new ConcurrentHashMap<>(); + + @Autowired + private SIPProcessorObserver sipProcessorObserver; + + @Autowired + private IVideoManagerStorager storage; + + @Override + public void afterPropertiesSet() throws Exception { + // 添加消息处理的订阅 + sipProcessorObserver.addRequestProcessor(method, this); + } + + public void addHandler(String name, IMessageHandler handler) { + messageHandlerMap.put(name, handler); + } + + @Override + public void process(RequestEvent evt) { + logger.debug("接收到消息:" + evt.getRequest()); + String deviceId = SipUtils.getUserIdFromFromHeader(evt.getRequest()); + // 查询设备是否存在 + Device device = storage.queryVideoDevice(deviceId); + // 查询上级平台是否存在 + ParentPlatform parentPlatform = storage.queryParentPlatByServerGBId(deviceId); + try { + if (device == null && parentPlatform == null) { + // 不存在则回复404 + responseAck(evt, Response.NOT_FOUND, "device id not found"); + }else { + Element rootElement = getRootElement(evt); + String name = rootElement.getName(); + IMessageHandler messageHandler = messageHandlerMap.get(name); + if (messageHandler != null) { + if (device != null) { + messageHandler.handForDevice(evt, device, rootElement); + }else { // 由于上面已经判断都为null则直接返回,所以这里device和parentPlatform必有一个不为null + messageHandler.handForPlatform(evt, parentPlatform, rootElement); + } + }else { + // 不支持的message + // 不存在则回复415 + responseAck(evt, Response.UNSUPPORTED_MEDIA_TYPE, "Unsupported message type, must Control/Notify/Query/Response"); + } + } + } catch (SipException e) { + logger.warn("SIP 回复错误", e); + } catch (InvalidArgumentException e) { + logger.warn("参数无效", e); + } catch (ParseException e) { + logger.warn("SIP回复时解析异常", e); + } catch (DocumentException e) { + logger.warn("解析XML消息内容异常", e); + } + } + + +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/control/ControlMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/control/ControlMessageHandler.java new file mode 100644 index 000000000..b533082a0 --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/control/ControlMessageHandler.java @@ -0,0 +1,21 @@ +package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.control; + +import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.MessageHandlerAbstract; +import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.MessageRequestProcessor; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class ControlMessageHandler extends MessageHandlerAbstract implements InitializingBean { + + private final String messageType = "Control"; + + @Autowired + private MessageRequestProcessor messageRequestProcessor; + + @Override + public void afterPropertiesSet() throws Exception { + messageRequestProcessor.addHandler(messageType, this); + } +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/NotifyMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/NotifyMessageHandler.java new file mode 100644 index 000000000..56c020bec --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/NotifyMessageHandler.java @@ -0,0 +1,16 @@ +package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.notify; + +import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.MessageHandlerAbstract; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.stereotype.Component; + +@Component +public class NotifyMessageHandler extends MessageHandlerAbstract implements InitializingBean { + + private final String messageType = "Notify"; + + @Override + public void afterPropertiesSet() throws Exception { + messageRequestProcessor.addHandler(messageType, this); + } +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/AlarmNotifyMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/AlarmNotifyMessageHandler.java new file mode 100644 index 000000000..511083c0d --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/AlarmNotifyMessageHandler.java @@ -0,0 +1,114 @@ +package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.notify.cmd; + +import com.genersoft.iot.vmp.conf.UserSetup; +import com.genersoft.iot.vmp.gb28181.bean.*; +import com.genersoft.iot.vmp.gb28181.event.DeviceOffLineDetector; +import com.genersoft.iot.vmp.gb28181.event.EventPublisher; +import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent; +import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler; +import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.notify.NotifyMessageHandler; +import com.genersoft.iot.vmp.gb28181.utils.NumericUtil; +import com.genersoft.iot.vmp.service.IDeviceAlarmService; +import com.genersoft.iot.vmp.storager.IVideoManagerStorager; +import com.genersoft.iot.vmp.utils.GpsUtil; +import org.dom4j.Element; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.util.StringUtils; + +import javax.sip.RequestEvent; + +import static com.genersoft.iot.vmp.gb28181.utils.XmlUtil.getText; + +@Component +public class AlarmNotifyMessageHandler extends SIPRequestProcessorParent implements InitializingBean, IMessageHandler { + + private Logger logger = LoggerFactory.getLogger(AlarmNotifyMessageHandler.class); + private final String cmdType = "Alarm"; + + @Autowired + private NotifyMessageHandler notifyMessageHandler; + + @Autowired + private EventPublisher publisher; + + @Autowired + private UserSetup userSetup; + + @Autowired + private IVideoManagerStorager storager; + + @Autowired + private IDeviceAlarmService deviceAlarmService; + + @Autowired + private DeviceOffLineDetector offLineDetector; + + @Override + public void afterPropertiesSet() throws Exception { + notifyMessageHandler.addHandler(cmdType, this); + } + + @Override + public void handForDevice(RequestEvent evt, Device device, Element rootElement) { + Element deviceIdElement = rootElement.element("DeviceID"); + String channelId = deviceIdElement.getText().toString(); + DeviceAlarm deviceAlarm = new DeviceAlarm(); + deviceAlarm.setDeviceId(device.getDeviceId()); + deviceAlarm.setChannelId(channelId); + deviceAlarm.setAlarmPriority(getText(rootElement, "AlarmPriority")); + deviceAlarm.setAlarmMethod(getText(rootElement, "AlarmMethod")); + deviceAlarm.setAlarmTime(getText(rootElement, "AlarmTime")); + if (getText(rootElement, "AlarmDescription") == null) { + deviceAlarm.setAlarmDescription(""); + } else { + deviceAlarm.setAlarmDescription(getText(rootElement, "AlarmDescription")); + } + if (NumericUtil.isDouble(getText(rootElement, "Longitude"))) { + deviceAlarm.setLongitude(Double.parseDouble(getText(rootElement, "Longitude"))); + } else { + deviceAlarm.setLongitude(0.00); + } + if (NumericUtil.isDouble(getText(rootElement, "Latitude"))) { + deviceAlarm.setLatitude(Double.parseDouble(getText(rootElement, "Latitude"))); + } else { + deviceAlarm.setLatitude(0.00); + } + + if (!StringUtils.isEmpty(deviceAlarm.getAlarmMethod())) { + if ( deviceAlarm.getAlarmMethod().equals("4")) { + MobilePosition mobilePosition = new MobilePosition(); + mobilePosition.setDeviceId(deviceAlarm.getDeviceId()); + mobilePosition.setTime(deviceAlarm.getAlarmTime()); + mobilePosition.setLongitude(deviceAlarm.getLongitude()); + mobilePosition.setLatitude(deviceAlarm.getLatitude()); + mobilePosition.setReportSource("GPS Alarm"); + BaiduPoint bp = new BaiduPoint(); + bp = GpsUtil.Wgs84ToBd09(String.valueOf(mobilePosition.getLongitude()), String.valueOf(mobilePosition.getLatitude())); + logger.info("百度坐标:" + bp.getBdLng() + ", " + bp.getBdLat()); + mobilePosition.setGeodeticSystem("BD-09"); + mobilePosition.setCnLng(bp.getBdLng()); + mobilePosition.setCnLat(bp.getBdLat()); + if (!userSetup.getSavePositionHistory()) { + storager.clearMobilePositionsByDeviceId(device.getDeviceId()); + } + storager.insertMobilePosition(mobilePosition); + } + } + logger.debug("存储报警信息、报警分类"); + // 存储报警信息、报警分类 + deviceAlarmService.add(deviceAlarm); + + if (offLineDetector.isOnline(device.getDeviceId())) { + publisher.deviceAlarmEventPublish(deviceAlarm); + } + } + + @Override + public void handForPlatform(RequestEvent evt, ParentPlatform parentPlatform, Element element) { + + } +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/CatalogNotifyMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/CatalogNotifyMessageHandler.java new file mode 100644 index 000000000..497f421b5 --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/CatalogNotifyMessageHandler.java @@ -0,0 +1,120 @@ +package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.notify.cmd; + +import com.genersoft.iot.vmp.conf.SipConfig; +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.ParentPlatform; +import com.genersoft.iot.vmp.gb28181.event.EventPublisher; +import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; +import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform; +import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent; +import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler; +import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.notify.NotifyMessageHandler; +import com.genersoft.iot.vmp.storager.IVideoManagerStorager; +import com.genersoft.iot.vmp.vmanager.gb28181.platform.bean.ChannelReduce; +import org.dom4j.Element; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import javax.sip.InvalidArgumentException; +import javax.sip.RequestEvent; +import javax.sip.SipException; +import javax.sip.header.FromHeader; +import javax.sip.message.Response; +import java.text.ParseException; +import java.util.List; + +@Component +public class CatalogNotifyMessageHandler extends SIPRequestProcessorParent implements InitializingBean, IMessageHandler { + + private Logger logger = LoggerFactory.getLogger(CatalogNotifyMessageHandler.class); + private final String cmdType = "Catalog"; + + @Autowired + private NotifyMessageHandler notifyMessageHandler; + + @Autowired + private IVideoManagerStorager storager; + + @Autowired + private SIPCommanderFroPlatform cmderFroPlatform; + + @Autowired + private SipConfig config; + + @Autowired + private EventPublisher publisher; + + @Override + public void afterPropertiesSet() throws Exception { + notifyMessageHandler.addHandler(cmdType, this); + } + + @Override + public void handForDevice(RequestEvent evt, Device device, Element element) { + + } + + @Override + public void handForPlatform(RequestEvent evt, ParentPlatform parentPlatform, Element rootElement) { + + String key = DeferredResultHolder.CALLBACK_CMD_CATALOG + parentPlatform.getServerGBId(); + FromHeader fromHeader = (FromHeader) evt.getRequest().getHeader(FromHeader.NAME); + try { + // 回复200 OK + responseAck(evt, Response.OK); + Element snElement = rootElement.element("SN"); + String sn = snElement.getText(); + // 准备回复通道信息 + List channelReduces = storager.queryChannelListInParentPlatform(parentPlatform.getServerGBId()); + // 查询关联的直播通道 + List gbStreams = storager.queryGbStreamListInPlatform(parentPlatform.getServerGBId()); + int size = channelReduces.size() + gbStreams.size(); + // 回复级联的通道 + if (channelReduces.size() > 0) { + for (ChannelReduce channelReduce : channelReduces) { + DeviceChannel deviceChannel = storager.queryChannel(channelReduce.getDeviceId(), channelReduce.getChannelId()); + cmderFroPlatform.catalogQuery(deviceChannel, parentPlatform, sn, fromHeader.getTag(), size); + } + } + // 回复直播的通道 + if (gbStreams.size() > 0) { + for (GbStream gbStream : gbStreams) { + DeviceChannel deviceChannel = new DeviceChannel(); + deviceChannel.setChannelId(gbStream.getGbId()); + deviceChannel.setName(gbStream.getName()); + deviceChannel.setLongitude(gbStream.getLongitude()); + deviceChannel.setLatitude(gbStream.getLatitude()); + deviceChannel.setDeviceId(parentPlatform.getDeviceGBId()); + deviceChannel.setManufacture("wvp-pro"); + deviceChannel.setStatus(gbStream.isStatus()?1:0); + // deviceChannel.setParentId(parentPlatform.getDeviceGBId()); + deviceChannel.setRegisterWay(1); + deviceChannel.setCivilCode(config.getDomain()); + deviceChannel.setModel("live"); + deviceChannel.setOwner("wvp-pro"); + deviceChannel.setParental(0); + deviceChannel.setSecrecy("0"); + deviceChannel.setSecrecy("0"); + + cmderFroPlatform.catalogQuery(deviceChannel, parentPlatform, sn, fromHeader.getTag(), size); + } + } + if (size == 0) { + // 回复无通道 + cmderFroPlatform.catalogQuery(null, parentPlatform, sn, fromHeader.getTag(), size); + } + } catch (SipException e) { + e.printStackTrace(); + } catch (InvalidArgumentException e) { + e.printStackTrace(); + } catch (ParseException e) { + e.printStackTrace(); + } + + } +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/KeepaliveNotifyMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/KeepaliveNotifyMessageHandler.java new file mode 100644 index 000000000..05e8bd714 --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/KeepaliveNotifyMessageHandler.java @@ -0,0 +1,63 @@ +package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.notify.cmd; + +import com.genersoft.iot.vmp.common.VideoManagerConstants; +import com.genersoft.iot.vmp.gb28181.bean.Device; +import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; +import com.genersoft.iot.vmp.gb28181.event.EventPublisher; +import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent; +import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler; +import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.notify.NotifyMessageHandler; +import org.dom4j.Element; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import javax.sip.InvalidArgumentException; +import javax.sip.RequestEvent; +import javax.sip.SipException; +import javax.sip.message.Response; +import java.text.ParseException; + +@Component +public class KeepaliveNotifyMessageHandler extends SIPRequestProcessorParent implements InitializingBean, IMessageHandler { + + private Logger logger = LoggerFactory.getLogger(KeepaliveNotifyMessageHandler.class); + private final String cmdType = "Keepalive"; + + @Autowired + private NotifyMessageHandler notifyMessageHandler; + + @Autowired + private EventPublisher publisher; + + @Override + public void afterPropertiesSet() throws Exception { + notifyMessageHandler.addHandler(cmdType, this); + } + + @Override + public void handForDevice(RequestEvent evt, Device device, Element element) { + // 检查设备是否存在并在线, 不在线则设置为在线 + try { + if (device != null ) { + // 回复200 OK + responseAck(evt, Response.OK); + publisher.onlineEventPublish(device, VideoManagerConstants.EVENT_ONLINE_KEEPLIVE); + } + } catch (SipException e) { + e.printStackTrace(); + } catch (InvalidArgumentException e) { + e.printStackTrace(); + } catch (ParseException e) { + e.printStackTrace(); + } + } + + @Override + public void handForPlatform(RequestEvent evt, ParentPlatform parentPlatform, Element element) { + // 不会收到上级平台的心跳信息 + + } +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/MediaStatusNotifyMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/MediaStatusNotifyMessageHandler.java new file mode 100644 index 000000000..c61b72790 --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/MediaStatusNotifyMessageHandler.java @@ -0,0 +1,74 @@ +package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.notify.cmd; + +import com.genersoft.iot.vmp.common.StreamInfo; +import com.genersoft.iot.vmp.gb28181.bean.Device; +import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; +import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; +import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent; +import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler; +import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.notify.NotifyMessageHandler; +import com.genersoft.iot.vmp.storager.IRedisCatchStorage; +import org.dom4j.Element; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import javax.sip.InvalidArgumentException; +import javax.sip.RequestEvent; +import javax.sip.SipException; +import javax.sip.message.Response; +import java.text.ParseException; + +import static com.genersoft.iot.vmp.gb28181.utils.XmlUtil.getText; + +@Component +public class MediaStatusNotifyMessageHandler extends SIPRequestProcessorParent implements InitializingBean, IMessageHandler { + + private Logger logger = LoggerFactory.getLogger(MediaStatusNotifyMessageHandler.class); + private final String cmdType = "MediaStatus"; + + @Autowired + private NotifyMessageHandler notifyMessageHandler; + + @Autowired + private SIPCommander cmder; + + @Autowired + private IRedisCatchStorage redisCatchStorage; + + @Override + public void afterPropertiesSet() throws Exception { + notifyMessageHandler.addHandler(cmdType, this); + } + + @Override + public void handForDevice(RequestEvent evt, Device device, Element rootElement) { + + // 回复200 OK + try { + responseAck(evt, Response.OK); + } catch (SipException e) { + e.printStackTrace(); + } catch (InvalidArgumentException e) { + e.printStackTrace(); + } catch (ParseException e) { + e.printStackTrace(); + } + String NotifyType =getText(rootElement, "NotifyType"); + if (NotifyType.equals("121")){ + logger.info("媒体播放完毕,通知关流"); + StreamInfo streamInfo = redisCatchStorage.queryPlaybackByDevice(device.getDeviceId(), "*"); + if (streamInfo != null) { + redisCatchStorage.stopPlayback(streamInfo); + cmder.streamByeCmd(streamInfo.getDeviceID(), streamInfo.getChannelId()); + } + } + } + + @Override + public void handForPlatform(RequestEvent evt, ParentPlatform parentPlatform, Element element) { + + } +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/MobilePositionNotifyMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/MobilePositionNotifyMessageHandler.java new file mode 100644 index 000000000..ab7e5f633 --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/MobilePositionNotifyMessageHandler.java @@ -0,0 +1,103 @@ +package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.notify.cmd; + +import com.genersoft.iot.vmp.conf.UserSetup; +import com.genersoft.iot.vmp.gb28181.bean.BaiduPoint; +import com.genersoft.iot.vmp.gb28181.bean.Device; +import com.genersoft.iot.vmp.gb28181.bean.MobilePosition; +import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; +import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent; +import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler; +import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.notify.NotifyMessageHandler; +import com.genersoft.iot.vmp.gb28181.utils.NumericUtil; +import com.genersoft.iot.vmp.storager.IVideoManagerStorager; +import com.genersoft.iot.vmp.utils.GpsUtil; +import org.dom4j.DocumentException; +import org.dom4j.Element; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.util.StringUtils; + +import javax.sip.InvalidArgumentException; +import javax.sip.RequestEvent; +import javax.sip.SipException; +import javax.sip.message.Response; +import java.text.ParseException; + +import static com.genersoft.iot.vmp.gb28181.utils.XmlUtil.getText; + +@Component +public class MobilePositionNotifyMessageHandler extends SIPRequestProcessorParent implements InitializingBean, IMessageHandler { + + private Logger logger = LoggerFactory.getLogger(MobilePositionNotifyMessageHandler.class); + private final String cmdType = "MobilePosition"; + + @Autowired + private NotifyMessageHandler notifyMessageHandler; + + @Autowired + private UserSetup userSetup; + + @Autowired + private IVideoManagerStorager storager; + + @Override + public void afterPropertiesSet() throws Exception { + notifyMessageHandler.addHandler(cmdType, this); + } + + @Override + public void handForDevice(RequestEvent evt, Device device, Element rootElement) { + + try { + rootElement = getRootElement(evt, device.getCharset()); + + MobilePosition mobilePosition = new MobilePosition(); + if (!StringUtils.isEmpty(device.getName())) { + mobilePosition.setDeviceName(device.getName()); + } + mobilePosition.setDeviceId(device.getDeviceId()); + mobilePosition.setChannelId(getText(rootElement, "DeviceID")); + mobilePosition.setTime(getText(rootElement, "Time")); + mobilePosition.setLongitude(Double.parseDouble(getText(rootElement, "Longitude"))); + mobilePosition.setLatitude(Double.parseDouble(getText(rootElement, "Latitude"))); + if (NumericUtil.isDouble(getText(rootElement, "Speed"))) { + mobilePosition.setSpeed(Double.parseDouble(getText(rootElement, "Speed"))); + } else { + mobilePosition.setSpeed(0.0); + } + if (NumericUtil.isDouble(getText(rootElement, "Direction"))) { + mobilePosition.setDirection(Double.parseDouble(getText(rootElement, "Direction"))); + } else { + mobilePosition.setDirection(0.0); + } + if (NumericUtil.isDouble(getText(rootElement, "Altitude"))) { + mobilePosition.setAltitude(Double.parseDouble(getText(rootElement, "Altitude"))); + } else { + mobilePosition.setAltitude(0.0); + } + mobilePosition.setReportSource("Mobile Position"); + BaiduPoint bp = new BaiduPoint(); + bp = GpsUtil.Wgs84ToBd09(String.valueOf(mobilePosition.getLongitude()), String.valueOf(mobilePosition.getLatitude())); + logger.info("百度坐标:" + bp.getBdLng() + ", " + bp.getBdLat()); + mobilePosition.setGeodeticSystem("BD-09"); + mobilePosition.setCnLng(bp.getBdLng()); + mobilePosition.setCnLat(bp.getBdLat()); + if (!userSetup.getSavePositionHistory()) { + storager.clearMobilePositionsByDeviceId(device.getDeviceId()); + } + storager.insertMobilePosition(mobilePosition); + //回复 200 OK + responseAck(evt, Response.OK); + } catch (DocumentException | SipException | InvalidArgumentException | ParseException e) { + e.printStackTrace(); + } + } + + @Override + public void handForPlatform(RequestEvent evt, ParentPlatform parentPlatform, Element element) { + + } +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/QueryMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/QueryMessageHandler.java new file mode 100644 index 000000000..ab111b550 --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/QueryMessageHandler.java @@ -0,0 +1,21 @@ +package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.query; + +import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.MessageHandlerAbstract; +import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.MessageRequestProcessor; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class QueryMessageHandler extends MessageHandlerAbstract implements InitializingBean { + + private final String messageType = "Query"; + + @Autowired + private MessageRequestProcessor messageRequestProcessor; + + @Override + public void afterPropertiesSet() throws Exception { + messageRequestProcessor.addHandler(messageType, this); + } +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/CatalogQueryMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/CatalogQueryMessageHandler.java new file mode 100644 index 000000000..98ed2dc4d --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/CatalogQueryMessageHandler.java @@ -0,0 +1,120 @@ +package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.query.cmd; + +import com.genersoft.iot.vmp.conf.SipConfig; +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.ParentPlatform; +import com.genersoft.iot.vmp.gb28181.event.EventPublisher; +import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; +import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform; +import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent; +import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler; +import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.query.QueryMessageHandler; +import com.genersoft.iot.vmp.storager.IVideoManagerStorager; +import com.genersoft.iot.vmp.vmanager.gb28181.platform.bean.ChannelReduce; +import org.dom4j.Element; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import javax.sip.InvalidArgumentException; +import javax.sip.RequestEvent; +import javax.sip.SipException; +import javax.sip.header.FromHeader; +import javax.sip.message.Response; +import java.text.ParseException; +import java.util.List; + +@Component +public class CatalogQueryMessageHandler extends SIPRequestProcessorParent implements InitializingBean, IMessageHandler { + + private Logger logger = LoggerFactory.getLogger(CatalogQueryMessageHandler.class); + private final String cmdType = "Catalog"; + + @Autowired + private QueryMessageHandler queryMessageHandler; + + @Autowired + private IVideoManagerStorager storager; + + @Autowired + private SIPCommanderFroPlatform cmderFroPlatform; + + @Autowired + private SipConfig config; + + @Autowired + private EventPublisher publisher; + + @Override + public void afterPropertiesSet() throws Exception { + queryMessageHandler.addHandler(cmdType, this); + } + + @Override + public void handForDevice(RequestEvent evt, Device device, Element element) { + + } + + @Override + public void handForPlatform(RequestEvent evt, ParentPlatform parentPlatform, Element rootElement) { + + String key = DeferredResultHolder.CALLBACK_CMD_CATALOG + parentPlatform.getServerGBId(); + FromHeader fromHeader = (FromHeader) evt.getRequest().getHeader(FromHeader.NAME); + try { + // 回复200 OK + responseAck(evt, Response.OK); + Element snElement = rootElement.element("SN"); + String sn = snElement.getText(); + // 准备回复通道信息 + List channelReduces = storager.queryChannelListInParentPlatform(parentPlatform.getServerGBId()); + // 查询关联的直播通道 + List gbStreams = storager.queryGbStreamListInPlatform(parentPlatform.getServerGBId()); + int size = channelReduces.size() + gbStreams.size(); + // 回复级联的通道 + if (channelReduces.size() > 0) { + for (ChannelReduce channelReduce : channelReduces) { + DeviceChannel deviceChannel = storager.queryChannel(channelReduce.getDeviceId(), channelReduce.getChannelId()); + cmderFroPlatform.catalogQuery(deviceChannel, parentPlatform, sn, fromHeader.getTag(), size); + } + } + // 回复直播的通道 + if (gbStreams.size() > 0) { + for (GbStream gbStream : gbStreams) { + DeviceChannel deviceChannel = new DeviceChannel(); + deviceChannel.setChannelId(gbStream.getGbId()); + deviceChannel.setName(gbStream.getName()); + deviceChannel.setLongitude(gbStream.getLongitude()); + deviceChannel.setLatitude(gbStream.getLatitude()); + deviceChannel.setDeviceId(parentPlatform.getDeviceGBId()); + deviceChannel.setManufacture("wvp-pro"); + deviceChannel.setStatus(gbStream.isStatus()?1:0); + // deviceChannel.setParentId(parentPlatform.getDeviceGBId()); + deviceChannel.setRegisterWay(1); + deviceChannel.setCivilCode(config.getDomain()); + deviceChannel.setModel("live"); + deviceChannel.setOwner("wvp-pro"); + deviceChannel.setParental(0); + deviceChannel.setSecrecy("0"); + deviceChannel.setSecrecy("0"); + + cmderFroPlatform.catalogQuery(deviceChannel, parentPlatform, sn, fromHeader.getTag(), size); + } + } + if (size == 0) { + // 回复无通道 + cmderFroPlatform.catalogQuery(null, parentPlatform, sn, fromHeader.getTag(), size); + } + } catch (SipException e) { + e.printStackTrace(); + } catch (InvalidArgumentException e) { + e.printStackTrace(); + } catch (ParseException e) { + e.printStackTrace(); + } + + } +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/DeviceControlQueryMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/DeviceControlQueryMessageHandler.java new file mode 100644 index 000000000..1c4a166b2 --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/DeviceControlQueryMessageHandler.java @@ -0,0 +1,111 @@ +package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.query.cmd; + +import com.genersoft.iot.vmp.VManageBootstrap; +import com.genersoft.iot.vmp.gb28181.bean.Device; +import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; +import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; +import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform; +import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent; +import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler; +import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.query.QueryMessageHandler; +import com.genersoft.iot.vmp.storager.IVideoManagerStorager; +import com.genersoft.iot.vmp.utils.SpringBeanFactory; +import gov.nist.javax.sip.SipStackImpl; +import org.dom4j.Element; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.util.StringUtils; + +import javax.sip.ListeningPoint; +import javax.sip.ObjectInUseException; +import javax.sip.RequestEvent; +import javax.sip.SipProvider; +import javax.sip.address.SipURI; +import javax.sip.header.HeaderAddress; +import javax.sip.header.ToHeader; +import java.util.Iterator; + +import static com.genersoft.iot.vmp.gb28181.utils.XmlUtil.getText; + +@Component +public class DeviceControlQueryMessageHandler extends SIPRequestProcessorParent implements InitializingBean, IMessageHandler { + + private Logger logger = LoggerFactory.getLogger(DeviceControlQueryMessageHandler.class); + private final String cmdType = "DeviceControl"; + + @Autowired + private QueryMessageHandler queryMessageHandler; + + @Autowired + private IVideoManagerStorager storager; + + @Autowired + private SIPCommander cmder; + + @Autowired + private SIPCommanderFroPlatform cmderFroPlatform; + + @Override + public void afterPropertiesSet() throws Exception { + queryMessageHandler.addHandler(cmdType, this); + } + + @Override + public void handForDevice(RequestEvent evt, Device device, Element element) { + + } + + @Override + public void handForPlatform(RequestEvent evt, ParentPlatform parentPlatform, Element rootElement) { + + // 此处是上级发出的DeviceControl指令 + String targetGBId = ((SipURI) ((HeaderAddress) evt.getRequest().getHeader(ToHeader.NAME)).getAddress().getURI()).getUser(); + String channelId = getText(rootElement, "DeviceID"); + // 远程启动功能 + if (!StringUtils.isEmpty(getText(rootElement, "TeleBoot"))) { + if (parentPlatform.getServerGBId().equals(targetGBId)) { + // 远程启动本平台:需要在重新启动程序后先对SipStack解绑 + logger.info("执行远程启动本平台命令"); + cmderFroPlatform.unregister(parentPlatform, null, null); + + Thread restartThread = new Thread(new Runnable() { + @Override + public void run() { + try { + Thread.sleep(3000); + SipProvider up = (SipProvider) SpringBeanFactory.getBean("udpSipProvider"); + SipStackImpl stack = (SipStackImpl)up.getSipStack(); + stack.stop(); + Iterator listener = stack.getListeningPoints(); + while (listener.hasNext()) { + stack.deleteListeningPoint((ListeningPoint) listener.next()); + } + Iterator providers = stack.getSipProviders(); + while (providers.hasNext()) { + stack.deleteSipProvider((SipProvider) providers.next()); + } + VManageBootstrap.restart(); + } catch (InterruptedException ignored) { + } catch (ObjectInUseException e) { + e.printStackTrace(); + } + } + }); + + restartThread.setDaemon(false); + restartThread.start(); + } else { + // 远程启动指定设备 + } + } + // 云台/前端控制命令 + if (!StringUtils.isEmpty(getText(rootElement,"PTZCmd")) && !parentPlatform.getServerGBId().equals(targetGBId)) { + String cmdString = getText(rootElement,"PTZCmd"); + Device deviceForPlatform = storager.queryVideoDeviceByPlatformIdAndChannelId(parentPlatform.getServerGBId(), channelId); + cmder.fronEndCmd(deviceForPlatform, channelId, cmdString); + } + } +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/DeviceInfoQueryMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/DeviceInfoQueryMessageHandler.java new file mode 100644 index 000000000..8234cb152 --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/DeviceInfoQueryMessageHandler.java @@ -0,0 +1,62 @@ +package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.query.cmd; + +import com.genersoft.iot.vmp.gb28181.bean.Device; +import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; +import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform; +import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent; +import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler; +import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.query.QueryMessageHandler; +import org.dom4j.Element; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import javax.sip.InvalidArgumentException; +import javax.sip.RequestEvent; +import javax.sip.SipException; +import javax.sip.header.FromHeader; +import javax.sip.message.Response; +import java.text.ParseException; + +@Component +public class DeviceInfoQueryMessageHandler extends SIPRequestProcessorParent implements InitializingBean, IMessageHandler { + + private Logger logger = LoggerFactory.getLogger(DeviceInfoQueryMessageHandler.class); + private final String cmdType = "DeviceInfo"; + + @Autowired + private QueryMessageHandler queryMessageHandler; + + @Autowired + private SIPCommanderFroPlatform cmderFroPlatform; + + @Override + public void afterPropertiesSet() throws Exception { + queryMessageHandler.addHandler(cmdType, this); + } + + @Override + public void handForDevice(RequestEvent evt, Device device, Element rootElement) { + + } + + @Override + public void handForPlatform(RequestEvent evt, ParentPlatform parentPlatform, Element rootElement) { + logger.info("接收到DeviceInfo查询消息"); + FromHeader fromHeader = (FromHeader) evt.getRequest().getHeader(FromHeader.NAME); + try { + // 回复200 OK + responseAck(evt, Response.OK); + } catch (SipException e) { + e.printStackTrace(); + } catch (InvalidArgumentException e) { + e.printStackTrace(); + } catch (ParseException e) { + e.printStackTrace(); + } + String sn = rootElement.element("SN").getText(); + cmderFroPlatform.deviceInfoResponse(parentPlatform, sn, fromHeader.getTag()); + } +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/DeviceStatusQueryMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/DeviceStatusQueryMessageHandler.java new file mode 100644 index 000000000..c56151cd2 --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/DeviceStatusQueryMessageHandler.java @@ -0,0 +1,75 @@ +package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.query.cmd; + +import com.genersoft.iot.vmp.conf.SipConfig; +import com.genersoft.iot.vmp.gb28181.bean.Device; +import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; +import com.genersoft.iot.vmp.gb28181.event.EventPublisher; +import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform; +import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent; +import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler; +import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.query.QueryMessageHandler; +import com.genersoft.iot.vmp.storager.IVideoManagerStorager; +import org.dom4j.Element; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import javax.sip.InvalidArgumentException; +import javax.sip.RequestEvent; +import javax.sip.SipException; +import javax.sip.header.FromHeader; +import javax.sip.message.Response; +import java.text.ParseException; + +@Component +public class DeviceStatusQueryMessageHandler extends SIPRequestProcessorParent implements InitializingBean, IMessageHandler { + + private Logger logger = LoggerFactory.getLogger(DeviceStatusQueryMessageHandler.class); + private final String cmdType = "DeviceStatus"; + + @Autowired + private QueryMessageHandler queryMessageHandler; + + @Autowired + private IVideoManagerStorager storager; + + @Autowired + private SIPCommanderFroPlatform cmderFroPlatform; + + @Autowired + private SipConfig config; + + @Autowired + private EventPublisher publisher; + + @Override + public void afterPropertiesSet() throws Exception { + queryMessageHandler.addHandler(cmdType, this); + } + + @Override + public void handForDevice(RequestEvent evt, Device device, Element element) { + + } + + @Override + public void handForPlatform(RequestEvent evt, ParentPlatform parentPlatform, Element rootElement) { + + logger.info("接收到DeviceStatus查询消息"); + FromHeader fromHeader = (FromHeader) evt.getRequest().getHeader(FromHeader.NAME); + // 回复200 OK + try { + responseAck(evt, Response.OK); + } catch (SipException e) { + e.printStackTrace(); + } catch (InvalidArgumentException e) { + e.printStackTrace(); + } catch (ParseException e) { + e.printStackTrace(); + } + String sn = rootElement.element("SN").getText(); + cmderFroPlatform.deviceStatusResponse(parentPlatform, sn, fromHeader.getTag()); + } +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/ResponseMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/ResponseMessageHandler.java new file mode 100644 index 000000000..13c8ac760 --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/ResponseMessageHandler.java @@ -0,0 +1,21 @@ +package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response; + +import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.MessageHandlerAbstract; +import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.MessageRequestProcessor; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class ResponseMessageHandler extends MessageHandlerAbstract implements InitializingBean { + + private final String messageType = "Response"; + + @Autowired + private MessageRequestProcessor messageRequestProcessor; + + @Override + public void afterPropertiesSet() throws Exception { + messageRequestProcessor.addHandler(messageType, this); + } +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/AlarmResponseMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/AlarmResponseMessageHandler.java new file mode 100644 index 000000000..8492bd969 --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/AlarmResponseMessageHandler.java @@ -0,0 +1,58 @@ +package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.cmd; + +import com.alibaba.fastjson.JSONObject; +import com.genersoft.iot.vmp.gb28181.bean.Device; +import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; +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.event.request.SIPRequestProcessorParent; +import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler; +import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.ResponseMessageHandler; +import com.genersoft.iot.vmp.gb28181.utils.XmlUtil; +import org.dom4j.Element; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import javax.sip.RequestEvent; + +@Component +public class AlarmResponseMessageHandler extends SIPRequestProcessorParent implements InitializingBean, IMessageHandler { + + private Logger logger = LoggerFactory.getLogger(AlarmResponseMessageHandler.class); + private final String cmdType = "Alarm"; + + @Autowired + private ResponseMessageHandler responseMessageHandler; + + @Autowired + private DeferredResultHolder deferredResultHolder; + + @Override + public void afterPropertiesSet() throws Exception { + responseMessageHandler.addHandler(cmdType, this); + } + + @Override + public void handForDevice(RequestEvent evt, Device device, Element rootElement) { + Element deviceIdElement = rootElement.element("DeviceID"); + String channelId = deviceIdElement.getText().toString(); + String key = DeferredResultHolder.CALLBACK_CMD_ALARM + device.getDeviceId() + channelId; + JSONObject json = new JSONObject(); + XmlUtil.node2Json(rootElement, json); + if (logger.isDebugEnabled()) { + logger.debug(json.toJSONString()); + } + RequestMessage msg = new RequestMessage(); + msg.setKey(key); + msg.setData(json); + deferredResultHolder.invokeAllResult(msg); + } + + @Override + public void handForPlatform(RequestEvent evt, ParentPlatform parentPlatform, Element element) { + + } +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/BroadcastResponseMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/BroadcastResponseMessageHandler.java new file mode 100644 index 000000000..ac946551b --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/BroadcastResponseMessageHandler.java @@ -0,0 +1,72 @@ +package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.cmd; + +import com.alibaba.fastjson.JSONObject; +import com.genersoft.iot.vmp.gb28181.bean.Device; +import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; +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.event.request.SIPRequestProcessorParent; +import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler; +import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.ResponseMessageHandler; +import com.genersoft.iot.vmp.gb28181.utils.XmlUtil; +import org.dom4j.Element; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import javax.sip.InvalidArgumentException; +import javax.sip.RequestEvent; +import javax.sip.SipException; +import javax.sip.message.Response; +import java.text.ParseException; + +import static com.genersoft.iot.vmp.gb28181.utils.XmlUtil.getText; + +@Component +public class BroadcastResponseMessageHandler extends SIPRequestProcessorParent implements InitializingBean, IMessageHandler { + + private Logger logger = LoggerFactory.getLogger(BroadcastResponseMessageHandler.class); + private final String cmdType = "Broadcast"; + + @Autowired + private ResponseMessageHandler responseMessageHandler; + + @Autowired + private DeferredResultHolder deferredResultHolder; + + @Override + public void afterPropertiesSet() throws Exception { + responseMessageHandler.addHandler(cmdType, this); + } + + @Override + public void handForDevice(RequestEvent evt, Device device, Element rootElement) { + try { + String channelId = getText(rootElement, "DeviceID"); + String key = DeferredResultHolder.CALLBACK_CMD_BROADCAST + device.getDeviceId() + channelId; + // 回复200 OK + responseAck(evt, Response.OK); + // 此处是对本平台发出Broadcast指令的应答 + JSONObject json = new JSONObject(); + XmlUtil.node2Json(rootElement, json); + if (logger.isDebugEnabled()) { + logger.debug(json.toJSONString()); + } + RequestMessage msg = new RequestMessage(); + msg.setKey(key); + msg.setData(json); + deferredResultHolder.invokeAllResult(msg); + + + } catch (ParseException | SipException | InvalidArgumentException e) { + e.printStackTrace(); + } + } + + @Override + public void handForPlatform(RequestEvent evt, ParentPlatform parentPlatform, Element element) { + + } +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/CatalogResponseMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/CatalogResponseMessageHandler.java new file mode 100644 index 000000000..7349a7ac0 --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/CatalogResponseMessageHandler.java @@ -0,0 +1,182 @@ +package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.cmd; + +import com.genersoft.iot.vmp.common.VideoManagerConstants; +import com.genersoft.iot.vmp.conf.SipConfig; +import com.genersoft.iot.vmp.gb28181.bean.Device; +import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; +import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; +import com.genersoft.iot.vmp.gb28181.event.DeviceOffLineDetector; +import com.genersoft.iot.vmp.gb28181.event.EventPublisher; +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.event.request.SIPRequestProcessorParent; +import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler; +import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.ResponseMessageHandler; +import com.genersoft.iot.vmp.gb28181.utils.NumericUtil; +import com.genersoft.iot.vmp.storager.IVideoManagerStorager; +import org.dom4j.DocumentException; +import org.dom4j.Element; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import javax.sip.InvalidArgumentException; +import javax.sip.RequestEvent; +import javax.sip.SipException; +import javax.sip.message.Response; +import java.text.ParseException; +import java.util.Iterator; + +import static com.genersoft.iot.vmp.gb28181.utils.XmlUtil.getText; + +@Component +public class CatalogResponseMessageHandler extends SIPRequestProcessorParent implements InitializingBean, IMessageHandler { + + private Logger logger = LoggerFactory.getLogger(CatalogResponseMessageHandler.class); + private final String cmdType = "Catalog"; + + @Autowired + private ResponseMessageHandler responseMessageHandler; + + @Autowired + private IVideoManagerStorager storager; + + @Autowired + private DeferredResultHolder deferredResultHolder; + + @Autowired + private DeviceOffLineDetector offLineDetector; + + @Autowired + private SipConfig config; + + @Autowired + private EventPublisher publisher; + + @Override + public void afterPropertiesSet() throws Exception { + responseMessageHandler.addHandler(cmdType, this); + } + + @Override + public void handForDevice(RequestEvent evt, Device device, Element element) { + String key = DeferredResultHolder.CALLBACK_CMD_CATALOG + device.getDeviceId(); + Element rootElement = null; + try { + rootElement = getRootElement(evt, device.getCharset()); + Element deviceListElement = rootElement.element("DeviceList"); + Iterator deviceListIterator = deviceListElement.elementIterator(); + if (deviceListIterator != null) { + + // 遍历DeviceList + while (deviceListIterator.hasNext()) { + Element itemDevice = deviceListIterator.next(); + Element channelDeviceElement = itemDevice.element("DeviceID"); + if (channelDeviceElement == null) { + continue; + } + String channelDeviceId = channelDeviceElement.getText(); + Element channdelNameElement = itemDevice.element("Name"); + String channelName = channdelNameElement != null ? channdelNameElement.getTextTrim().toString() : ""; + Element statusElement = itemDevice.element("Status"); + String status = statusElement != null ? statusElement.getText().toString() : "ON"; + DeviceChannel deviceChannel = new DeviceChannel(); + deviceChannel.setName(channelName); + deviceChannel.setChannelId(channelDeviceId); + // ONLINE OFFLINE HIKVISION DS-7716N-E4 NVR的兼容性处理 + if (status.equals("ON") || status.equals("On") || status.equals("ONLINE")) { + deviceChannel.setStatus(1); + } + if (status.equals("OFF") || status.equals("Off") || status.equals("OFFLINE")) { + deviceChannel.setStatus(0); + } + + deviceChannel.setManufacture(getText(itemDevice, "Manufacturer")); + deviceChannel.setModel(getText(itemDevice, "Model")); + deviceChannel.setOwner(getText(itemDevice, "Owner")); + deviceChannel.setCivilCode(getText(itemDevice, "CivilCode")); + deviceChannel.setBlock(getText(itemDevice, "Block")); + deviceChannel.setAddress(getText(itemDevice, "Address")); + if (getText(itemDevice, "Parental") == null || getText(itemDevice, "Parental") == "") { + deviceChannel.setParental(0); + } else { + deviceChannel.setParental(Integer.parseInt(getText(itemDevice, "Parental"))); + } + deviceChannel.setParentId(getText(itemDevice, "ParentID")); + if (getText(itemDevice, "SafetyWay") == null || getText(itemDevice, "SafetyWay") == "") { + deviceChannel.setSafetyWay(0); + } else { + deviceChannel.setSafetyWay(Integer.parseInt(getText(itemDevice, "SafetyWay"))); + } + if (getText(itemDevice, "RegisterWay") == null || getText(itemDevice, "RegisterWay") == "") { + deviceChannel.setRegisterWay(1); + } else { + deviceChannel.setRegisterWay(Integer.parseInt(getText(itemDevice, "RegisterWay"))); + } + deviceChannel.setCertNum(getText(itemDevice, "CertNum")); + if (getText(itemDevice, "Certifiable") == null || getText(itemDevice, "Certifiable") == "") { + deviceChannel.setCertifiable(0); + } else { + deviceChannel.setCertifiable(Integer.parseInt(getText(itemDevice, "Certifiable"))); + } + if (getText(itemDevice, "ErrCode") == null || getText(itemDevice, "ErrCode") == "") { + deviceChannel.setErrCode(0); + } else { + deviceChannel.setErrCode(Integer.parseInt(getText(itemDevice, "ErrCode"))); + } + deviceChannel.setEndTime(getText(itemDevice, "EndTime")); + deviceChannel.setSecrecy(getText(itemDevice, "Secrecy")); + deviceChannel.setIpAddress(getText(itemDevice, "IPAddress")); + if (getText(itemDevice, "Port") == null || getText(itemDevice, "Port") == "") { + deviceChannel.setPort(0); + } else { + deviceChannel.setPort(Integer.parseInt(getText(itemDevice, "Port"))); + } + deviceChannel.setPassword(getText(itemDevice, "Password")); + if (NumericUtil.isDouble(getText(itemDevice, "Longitude"))) { + deviceChannel.setLongitude(Double.parseDouble(getText(itemDevice, "Longitude"))); + } else { + deviceChannel.setLongitude(0.00); + } + if (NumericUtil.isDouble(getText(itemDevice, "Latitude"))) { + deviceChannel.setLatitude(Double.parseDouble(getText(itemDevice, "Latitude"))); + } else { + deviceChannel.setLatitude(0.00); + } + if (getText(itemDevice, "PTZType") == null || getText(itemDevice, "PTZType") == "") { + deviceChannel.setPTZType(0); + } else { + deviceChannel.setPTZType(Integer.parseInt(getText(itemDevice, "PTZType"))); + } + deviceChannel.setHasAudio(true); // 默认含有音频,播放时再检查是否有音频及是否AAC + storager.updateChannel(device.getDeviceId(), deviceChannel); + } + + RequestMessage msg = new RequestMessage(); + msg.setKey(key); + msg.setData(device); + deferredResultHolder.invokeAllResult(msg); + // 回复200 OK + responseAck(evt, Response.OK); + if (offLineDetector.isOnline(device.getDeviceId())) { + publisher.onlineEventPublish(device, VideoManagerConstants.EVENT_ONLINE_MESSAGE); + } + } + } catch (DocumentException e) { + e.printStackTrace(); + } catch (InvalidArgumentException e) { + e.printStackTrace(); + } catch (ParseException e) { + e.printStackTrace(); + } catch (SipException e) { + e.printStackTrace(); + } + } + + @Override + public void handForPlatform(RequestEvent evt, ParentPlatform parentPlatform, Element rootElement) { + + } +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/ConfigDownloadResponseMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/ConfigDownloadResponseMessageHandler.java new file mode 100644 index 000000000..d1a2893f5 --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/ConfigDownloadResponseMessageHandler.java @@ -0,0 +1,81 @@ +package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.cmd; + +import com.alibaba.fastjson.JSONObject; +import com.genersoft.iot.vmp.gb28181.bean.Device; +import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; +import com.genersoft.iot.vmp.gb28181.event.EventPublisher; +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.event.request.SIPRequestProcessorParent; +import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler; +import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.ResponseMessageHandler; +import com.genersoft.iot.vmp.gb28181.utils.XmlUtil; +import org.dom4j.Element; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import javax.sip.InvalidArgumentException; +import javax.sip.RequestEvent; +import javax.sip.SipException; +import javax.sip.message.Response; +import java.text.ParseException; + +import static com.genersoft.iot.vmp.gb28181.utils.XmlUtil.getText; + +@Component +public class ConfigDownloadResponseMessageHandler extends SIPRequestProcessorParent implements InitializingBean, IMessageHandler { + + private Logger logger = LoggerFactory.getLogger(ConfigDownloadResponseMessageHandler.class); + private final String cmdType = "ConfigDownload"; + + @Autowired + private ResponseMessageHandler responseMessageHandler; + + @Autowired + private EventPublisher publisher; + + @Autowired + private DeferredResultHolder deferredResultHolder; + + @Override + public void afterPropertiesSet() throws Exception { + responseMessageHandler.addHandler(cmdType, this); + } + + + @Override + public void handForDevice(RequestEvent evt, Device device, Element element) { + String channelId = getText(element, "DeviceID"); + String key = DeferredResultHolder.CALLBACK_CMD_CONFIGDOWNLOAD + device.getDeviceId() + channelId; + try { + // 回复200 OK + responseAck(evt, Response.OK); + // 此处是对本平台发出DeviceControl指令的应答 + JSONObject json = new JSONObject(); + XmlUtil.node2Json(element, json); + if (logger.isDebugEnabled()) { + logger.debug(json.toJSONString()); + } + RequestMessage msg = new RequestMessage(); + msg.setKey(key); + msg.setData(json); + deferredResultHolder.invokeAllResult(msg); + } catch (SipException e) { + e.printStackTrace(); + } catch (InvalidArgumentException e) { + e.printStackTrace(); + } catch (ParseException e) { + e.printStackTrace(); + } + + } + + @Override + public void handForPlatform(RequestEvent evt, ParentPlatform parentPlatform, Element element) { + // 不会收到上级平台的心跳信息 + + } +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/DeviceConfigResponseMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/DeviceConfigResponseMessageHandler.java new file mode 100644 index 000000000..68ffe394c --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/DeviceConfigResponseMessageHandler.java @@ -0,0 +1,58 @@ +package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.cmd; + +import com.alibaba.fastjson.JSONObject; +import com.genersoft.iot.vmp.gb28181.bean.Device; +import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; +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.event.request.SIPRequestProcessorParent; +import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler; +import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.ResponseMessageHandler; +import com.genersoft.iot.vmp.gb28181.utils.XmlUtil; +import org.dom4j.Element; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import javax.sip.RequestEvent; + +import static com.genersoft.iot.vmp.gb28181.utils.XmlUtil.getText; + +@Component +public class DeviceConfigResponseMessageHandler extends SIPRequestProcessorParent implements InitializingBean, IMessageHandler { + + private Logger logger = LoggerFactory.getLogger(DeviceConfigResponseMessageHandler.class); + private final String cmdType = "DeviceConfig"; + + @Autowired + private ResponseMessageHandler responseMessageHandler; + + @Autowired + private DeferredResultHolder deferredResultHolder; + + @Override + public void afterPropertiesSet() throws Exception { + responseMessageHandler.addHandler(cmdType, this); + } + + @Override + public void handForDevice(RequestEvent evt, Device device, Element element) { + JSONObject json = new JSONObject(); + XmlUtil.node2Json(element, json); + String channelId = getText(element, "DeviceID"); + if (logger.isDebugEnabled()) { + logger.debug(json.toJSONString()); + } + String key = DeferredResultHolder.CALLBACK_CMD_DEVICECONFIG + device.getDeviceId() + channelId; + RequestMessage msg = new RequestMessage(); + msg.setKey(key); + msg.setData(json); + deferredResultHolder.invokeAllResult(msg); + } + + @Override + public void handForPlatform(RequestEvent evt, ParentPlatform parentPlatform, Element rootElement) { + } +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/DeviceControlResponseMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/DeviceControlResponseMessageHandler.java new file mode 100644 index 000000000..69f664bbf --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/DeviceControlResponseMessageHandler.java @@ -0,0 +1,59 @@ +package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.cmd; + +import com.alibaba.fastjson.JSONObject; +import com.genersoft.iot.vmp.gb28181.bean.Device; +import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; +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.event.request.SIPRequestProcessorParent; +import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler; +import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.ResponseMessageHandler; +import com.genersoft.iot.vmp.gb28181.utils.XmlUtil; +import org.dom4j.Element; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import javax.sip.RequestEvent; + +import static com.genersoft.iot.vmp.gb28181.utils.XmlUtil.getText; + +@Component +public class DeviceControlResponseMessageHandler extends SIPRequestProcessorParent implements InitializingBean, IMessageHandler { + + private Logger logger = LoggerFactory.getLogger(DeviceControlResponseMessageHandler.class); + private final String cmdType = "DeviceControl"; + + @Autowired + private ResponseMessageHandler responseMessageHandler; + + @Autowired + private DeferredResultHolder deferredResultHolder; + + @Override + public void afterPropertiesSet() throws Exception { + responseMessageHandler.addHandler(cmdType, this); + } + + @Override + public void handForDevice(RequestEvent evt, Device device, Element element) { + // 此处是对本平台发出DeviceControl指令的应答 + JSONObject json = new JSONObject(); + String channelId = getText(element, "DeviceID"); + XmlUtil.node2Json(element, json); + if (logger.isDebugEnabled()) { + logger.debug(json.toJSONString()); + } + RequestMessage msg = new RequestMessage(); + String key = DeferredResultHolder.CALLBACK_CMD_DEVICECONTROL + device.getDeviceId() + channelId; + msg.setKey(key); + msg.setData(json); + deferredResultHolder.invokeAllResult(msg); + } + + @Override + public void handForPlatform(RequestEvent evt, ParentPlatform parentPlatform, Element rootElement) { + } +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/DeviceInfoResponseMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/DeviceInfoResponseMessageHandler.java new file mode 100644 index 000000000..78fc93616 --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/DeviceInfoResponseMessageHandler.java @@ -0,0 +1,103 @@ +package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.cmd; + +import com.genersoft.iot.vmp.common.VideoManagerConstants; +import com.genersoft.iot.vmp.conf.SipConfig; +import com.genersoft.iot.vmp.gb28181.bean.Device; +import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; +import com.genersoft.iot.vmp.gb28181.event.DeviceOffLineDetector; +import com.genersoft.iot.vmp.gb28181.event.EventPublisher; +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.event.request.SIPRequestProcessorParent; +import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler; +import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.ResponseMessageHandler; +import com.genersoft.iot.vmp.storager.IVideoManagerStorager; +import org.dom4j.DocumentException; +import org.dom4j.Element; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.util.StringUtils; + +import javax.sip.InvalidArgumentException; +import javax.sip.RequestEvent; +import javax.sip.SipException; +import javax.sip.message.Response; +import java.text.ParseException; + +import static com.genersoft.iot.vmp.gb28181.utils.XmlUtil.getText; + +@Component +public class DeviceInfoResponseMessageHandler extends SIPRequestProcessorParent implements InitializingBean, IMessageHandler { + + private Logger logger = LoggerFactory.getLogger(DeviceInfoResponseMessageHandler.class); + private final String cmdType = "DeviceInfo"; + + @Autowired + private ResponseMessageHandler responseMessageHandler; + + @Autowired + private IVideoManagerStorager storager; + + @Autowired + private DeferredResultHolder deferredResultHolder; + + @Autowired + private DeviceOffLineDetector offLineDetector; + + @Autowired + private SipConfig config; + + @Autowired + private EventPublisher publisher; + + @Override + public void afterPropertiesSet() throws Exception { + responseMessageHandler.addHandler(cmdType, this); + } + + @Override + public void handForDevice(RequestEvent evt, Device device, Element rootElement) { + logger.debug("接收到DeviceInfo应答消息"); + try { + rootElement = getRootElement(evt, device.getCharset()); + Element deviceIdElement = rootElement.element("DeviceID"); + String channelId = deviceIdElement.getTextTrim(); + String key = DeferredResultHolder.CALLBACK_CMD_DEVICEINFO + device.getDeviceId() + channelId; + device.setName(getText(rootElement, "DeviceName")); + + device.setManufacturer(getText(rootElement, "Manufacturer")); + device.setModel(getText(rootElement, "Model")); + device.setFirmware(getText(rootElement, "Firmware")); + if (StringUtils.isEmpty(device.getStreamMode())) { + device.setStreamMode("UDP"); + } + storager.updateDevice(device); + + RequestMessage msg = new RequestMessage(); + msg.setKey(key); + msg.setData(device); + deferredResultHolder.invokeAllResult(msg); + // 回复200 OK + responseAck(evt, Response.OK); + if (offLineDetector.isOnline(device.getDeviceId())) { + publisher.onlineEventPublish(device, VideoManagerConstants.EVENT_ONLINE_MESSAGE); + } + } catch (DocumentException e) { + e.printStackTrace(); + } catch (InvalidArgumentException e) { + e.printStackTrace(); + } catch (ParseException e) { + e.printStackTrace(); + } catch (SipException e) { + e.printStackTrace(); + } + } + + @Override + public void handForPlatform(RequestEvent evt, ParentPlatform parentPlatform, Element rootElement) { + + } +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/DeviceStatusResponseMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/DeviceStatusResponseMessageHandler.java new file mode 100644 index 000000000..1a7ab6436 --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/DeviceStatusResponseMessageHandler.java @@ -0,0 +1,89 @@ +package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.cmd; + +import com.alibaba.fastjson.JSONObject; +import com.genersoft.iot.vmp.common.VideoManagerConstants; +import com.genersoft.iot.vmp.gb28181.bean.Device; +import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; +import com.genersoft.iot.vmp.gb28181.event.DeviceOffLineDetector; +import com.genersoft.iot.vmp.gb28181.event.EventPublisher; +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.event.request.SIPRequestProcessorParent; +import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler; +import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.ResponseMessageHandler; +import com.genersoft.iot.vmp.gb28181.utils.XmlUtil; +import org.dom4j.Element; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import javax.sip.InvalidArgumentException; +import javax.sip.RequestEvent; +import javax.sip.SipException; +import javax.sip.message.Response; +import java.text.ParseException; + +@Component +public class DeviceStatusResponseMessageHandler extends SIPRequestProcessorParent implements InitializingBean, IMessageHandler { + + private Logger logger = LoggerFactory.getLogger(DeviceStatusResponseMessageHandler.class); + private final String cmdType = "DeviceStatus"; + + @Autowired + private ResponseMessageHandler responseMessageHandler; + + @Autowired + private DeviceOffLineDetector offLineDetector; + + @Autowired + private DeferredResultHolder deferredResultHolder; + + @Autowired + private EventPublisher publisher; + + @Override + public void afterPropertiesSet() throws Exception { + responseMessageHandler.addHandler(cmdType, this); + } + + @Override + public void handForDevice(RequestEvent evt, Device device, Element element) { + logger.info("接收到DeviceStatus应答消息"); + // 检查设备是否存在, 不存在则不回复 + // 回复200 OK + try { + responseAck(evt, Response.OK); + } catch (SipException e) { + e.printStackTrace(); + } catch (InvalidArgumentException e) { + e.printStackTrace(); + } catch (ParseException e) { + e.printStackTrace(); + } + Element deviceIdElement = element.element("DeviceID"); + String channelId = deviceIdElement.getText(); + JSONObject json = new JSONObject(); + XmlUtil.node2Json(element, json); + if (logger.isDebugEnabled()) { + logger.debug(json.toJSONString()); + } + RequestMessage msg = new RequestMessage(); + msg.setKey(DeferredResultHolder.CALLBACK_CMD_DEVICESTATUS + device.getDeviceId() + channelId); + msg.setData(json); + deferredResultHolder.invokeAllResult(msg); + + if (offLineDetector.isOnline(device.getDeviceId())) { + publisher.onlineEventPublish(device, VideoManagerConstants.EVENT_ONLINE_MESSAGE); + } else { + + } + } + + @Override + public void handForPlatform(RequestEvent evt, ParentPlatform parentPlatform, Element rootElement) { + + + } +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/MobilePositionResponseMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/MobilePositionResponseMessageHandler.java new file mode 100644 index 000000000..b456386f1 --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/MobilePositionResponseMessageHandler.java @@ -0,0 +1,103 @@ +package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.cmd; + +import com.genersoft.iot.vmp.conf.UserSetup; +import com.genersoft.iot.vmp.gb28181.bean.BaiduPoint; +import com.genersoft.iot.vmp.gb28181.bean.Device; +import com.genersoft.iot.vmp.gb28181.bean.MobilePosition; +import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; +import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent; +import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler; +import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.ResponseMessageHandler; +import com.genersoft.iot.vmp.gb28181.utils.NumericUtil; +import com.genersoft.iot.vmp.storager.IVideoManagerStorager; +import com.genersoft.iot.vmp.utils.GpsUtil; +import org.dom4j.DocumentException; +import org.dom4j.Element; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.util.StringUtils; + +import javax.sip.InvalidArgumentException; +import javax.sip.RequestEvent; +import javax.sip.SipException; +import javax.sip.message.Response; +import java.text.ParseException; + +import static com.genersoft.iot.vmp.gb28181.utils.XmlUtil.getText; + +@Component +public class MobilePositionResponseMessageHandler extends SIPRequestProcessorParent implements InitializingBean, IMessageHandler { + + private Logger logger = LoggerFactory.getLogger(MobilePositionResponseMessageHandler.class); + private final String cmdType = "MobilePosition"; + + @Autowired + private ResponseMessageHandler responseMessageHandler; + + @Autowired + private UserSetup userSetup; + + @Autowired + private IVideoManagerStorager storager; + + @Override + public void afterPropertiesSet() throws Exception { + responseMessageHandler.addHandler(cmdType, this); + } + + @Override + public void handForDevice(RequestEvent evt, Device device, Element rootElement) { + + try { + rootElement = getRootElement(evt, device.getCharset()); + + MobilePosition mobilePosition = new MobilePosition(); + if (!StringUtils.isEmpty(device.getName())) { + mobilePosition.setDeviceName(device.getName()); + } + mobilePosition.setDeviceId(device.getDeviceId()); + mobilePosition.setChannelId(getText(rootElement, "DeviceID")); + mobilePosition.setTime(getText(rootElement, "Time")); + mobilePosition.setLongitude(Double.parseDouble(getText(rootElement, "Longitude"))); + mobilePosition.setLatitude(Double.parseDouble(getText(rootElement, "Latitude"))); + if (NumericUtil.isDouble(getText(rootElement, "Speed"))) { + mobilePosition.setSpeed(Double.parseDouble(getText(rootElement, "Speed"))); + } else { + mobilePosition.setSpeed(0.0); + } + if (NumericUtil.isDouble(getText(rootElement, "Direction"))) { + mobilePosition.setDirection(Double.parseDouble(getText(rootElement, "Direction"))); + } else { + mobilePosition.setDirection(0.0); + } + if (NumericUtil.isDouble(getText(rootElement, "Altitude"))) { + mobilePosition.setAltitude(Double.parseDouble(getText(rootElement, "Altitude"))); + } else { + mobilePosition.setAltitude(0.0); + } + mobilePosition.setReportSource("Mobile Position"); + BaiduPoint bp = new BaiduPoint(); + bp = GpsUtil.Wgs84ToBd09(String.valueOf(mobilePosition.getLongitude()), String.valueOf(mobilePosition.getLatitude())); + logger.info("百度坐标:" + bp.getBdLng() + ", " + bp.getBdLat()); + mobilePosition.setGeodeticSystem("BD-09"); + mobilePosition.setCnLng(bp.getBdLng()); + mobilePosition.setCnLat(bp.getBdLat()); + if (!userSetup.getSavePositionHistory()) { + storager.clearMobilePositionsByDeviceId(device.getDeviceId()); + } + storager.insertMobilePosition(mobilePosition); + //回复 200 OK + responseAck(evt, Response.OK); + } catch (DocumentException | SipException | InvalidArgumentException | ParseException e) { + e.printStackTrace(); + } + } + + @Override + public void handForPlatform(RequestEvent evt, ParentPlatform parentPlatform, Element element) { + + } +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/RecordInfoResponseMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/RecordInfoResponseMessageHandler.java new file mode 100644 index 000000000..f1919da4d --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/RecordInfoResponseMessageHandler.java @@ -0,0 +1,153 @@ +package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.cmd; + +import com.genersoft.iot.vmp.gb28181.bean.Device; +import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; +import com.genersoft.iot.vmp.gb28181.bean.RecordInfo; +import com.genersoft.iot.vmp.gb28181.bean.RecordItem; +import com.genersoft.iot.vmp.gb28181.transmit.callback.CheckForAllRecordsThread; +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.event.request.SIPRequestProcessorParent; +import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler; +import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.ResponseMessageHandler; +import com.genersoft.iot.vmp.gb28181.utils.DateUtil; +import com.genersoft.iot.vmp.utils.redis.RedisUtil; +import org.dom4j.DocumentException; +import org.dom4j.Element; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import javax.sip.InvalidArgumentException; +import javax.sip.RequestEvent; +import javax.sip.SipException; +import javax.sip.message.Response; +import java.text.ParseException; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.UUID; + +import static com.genersoft.iot.vmp.gb28181.utils.XmlUtil.getText; + +@Component +public class RecordInfoResponseMessageHandler extends SIPRequestProcessorParent implements InitializingBean, IMessageHandler { + + private Logger logger = LoggerFactory.getLogger(RecordInfoResponseMessageHandler.class); + public static volatile List threadNameList = new ArrayList(); + private final String cmdType = "RecordInfo"; + private final static String CACHE_RECORDINFO_KEY = "CACHE_RECORDINFO_"; + + @Autowired + private ResponseMessageHandler responseMessageHandler; + + @Autowired + private RedisUtil redis; + + @Autowired + private DeferredResultHolder deferredResultHolder; + + @Override + public void afterPropertiesSet() throws Exception { + responseMessageHandler.addHandler(cmdType, this); + } + + @Override + public void handForDevice(RequestEvent evt, Device device, Element rootElement) { + + // 回复200 OK + try { + responseAck(evt, Response.OK); + + rootElement = getRootElement(evt, device.getCharset()); + String uuid = UUID.randomUUID().toString().replace("-", ""); + RecordInfo recordInfo = new RecordInfo(); + Element deviceIdElement = rootElement.element("DeviceID"); + String channelId = deviceIdElement.getText(); + String key = DeferredResultHolder.CALLBACK_CMD_RECORDINFO + device.getDeviceId() + channelId; + recordInfo.setDeviceId(device.getDeviceId()); + recordInfo.setChannelId(channelId); + recordInfo.setName(getText(rootElement, "Name")); + if (getText(rootElement, "SumNum") == null || getText(rootElement, "SumNum") == "") { + recordInfo.setSumNum(0); + } else { + recordInfo.setSumNum(Integer.parseInt(getText(rootElement, "SumNum"))); + } + String sn = getText(rootElement, "SN"); + Element recordListElement = rootElement.element("RecordList"); + if (recordListElement == null || recordInfo.getSumNum() == 0) { + logger.info("无录像数据"); + RequestMessage msg = new RequestMessage(); + msg.setKey(key); + msg.setData(recordInfo); + deferredResultHolder.invokeAllResult(msg); + } else { + Iterator recordListIterator = recordListElement.elementIterator(); + List recordList = new ArrayList(); + if (recordListIterator != null) { + RecordItem record = new RecordItem(); + logger.info("处理录像列表数据..."); + // 遍历DeviceList + while (recordListIterator.hasNext()) { + Element itemRecord = recordListIterator.next(); + Element recordElement = itemRecord.element("DeviceID"); + if (recordElement == null) { + logger.info("记录为空,下一个..."); + continue; + } + record = new RecordItem(); + record.setDeviceId(getText(itemRecord, "DeviceID")); + record.setName(getText(itemRecord, "Name")); + record.setFilePath(getText(itemRecord, "FilePath")); + record.setAddress(getText(itemRecord, "Address")); + record.setStartTime( + DateUtil.ISO8601Toyyyy_MM_dd_HH_mm_ss(getText(itemRecord, "StartTime"))); + record.setEndTime( + DateUtil.ISO8601Toyyyy_MM_dd_HH_mm_ss(getText(itemRecord, "EndTime"))); + record.setSecrecy(itemRecord.element("Secrecy") == null ? 0 + : Integer.parseInt(getText(itemRecord, "Secrecy"))); + record.setType(getText(itemRecord, "Type")); + record.setRecorderId(getText(itemRecord, "RecorderID")); + recordList.add(record); + } + recordInfo.setRecordList(recordList); + } + + // 改用单独线程统计已获取录像文件数量,避免多包并行分别统计不完整的问题 + String cacheKey = CACHE_RECORDINFO_KEY + device.getDeviceId() + sn; + redis.set(cacheKey + "_" + uuid, recordList, 90); + if (!threadNameList.contains(cacheKey)) { + threadNameList.add(cacheKey); + CheckForAllRecordsThread chk = new CheckForAllRecordsThread(cacheKey, recordInfo); + chk.setName(cacheKey); + chk.setDeferredResultHolder(deferredResultHolder); + chk.setRedis(redis); + chk.setLogger(logger); + chk.start(); + if (logger.isDebugEnabled()) { + logger.debug("Start Thread " + cacheKey + "."); + } + } else { + if (logger.isDebugEnabled()) { + logger.debug("Thread " + cacheKey + " already started."); + } + } + } + } catch (SipException e) { + e.printStackTrace(); + } catch (InvalidArgumentException e) { + e.printStackTrace(); + } catch (ParseException e) { + e.printStackTrace(); + } catch (DocumentException e) { + e.printStackTrace(); + } + } + + @Override + public void handForPlatform(RequestEvent evt, ParentPlatform parentPlatform, Element element) { + + } +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/response/ISIPResponseProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/response/ISIPResponseProcessor.java new file mode 100644 index 000000000..50fb20211 --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/response/ISIPResponseProcessor.java @@ -0,0 +1,15 @@ +package com.genersoft.iot.vmp.gb28181.transmit.event.response; + +import javax.sip.ResponseEvent; + +/** + * @description:处理接收IPCamera发来的SIP协议响应消息 + * @author: swwheihei + * @date: 2020年5月3日 下午4:42:22 + */ +public interface ISIPResponseProcessor { + + void process(ResponseEvent evt); + + +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/response/SIPResponseProcessorAbstract.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/response/SIPResponseProcessorAbstract.java new file mode 100644 index 000000000..9f2a10b07 --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/response/SIPResponseProcessorAbstract.java @@ -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 { + + +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/response/impl/ByeResponseProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/response/impl/ByeResponseProcessor.java new file mode 100644 index 000000000..d44c1a9d1 --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/response/impl/ByeResponseProcessor.java @@ -0,0 +1,49 @@ +package com.genersoft.iot.vmp.gb28181.transmit.event.response.impl; + +import com.genersoft.iot.vmp.conf.SipConfig; +import com.genersoft.iot.vmp.gb28181.SipLayer; +import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver; +import com.genersoft.iot.vmp.gb28181.transmit.event.response.SIPResponseProcessorAbstract; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import javax.sip.ResponseEvent; + +/** + * @description: BYE请求响应器 + * @author: swwheihei + * @date: 2020年5月3日 下午5:32:05 + */ +@Component +public class ByeResponseProcessor extends SIPResponseProcessorAbstract { + + private String method = "BYE"; + + @Autowired + private SipLayer sipLayer; + + @Autowired + private SipConfig config; + + + @Autowired + private SIPProcessorObserver sipProcessorObserver; + + @Override + public void afterPropertiesSet() throws Exception { + // 添加消息处理的订阅 + sipProcessorObserver.addResponseProcessor(method, this); + } + /** + * 处理BYE响应 + * + * @param evt + */ + @Override + public void process(ResponseEvent evt) { + // TODO Auto-generated method stub + System.out.println("收到bye"); + } + + +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/response/impl/CancelResponseProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/response/impl/CancelResponseProcessor.java new file mode 100644 index 000000000..80d7e2b2c --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/response/impl/CancelResponseProcessor.java @@ -0,0 +1,47 @@ +package com.genersoft.iot.vmp.gb28181.transmit.event.response.impl; + +import com.genersoft.iot.vmp.conf.SipConfig; +import com.genersoft.iot.vmp.gb28181.SipLayer; +import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver; +import com.genersoft.iot.vmp.gb28181.transmit.event.response.SIPResponseProcessorAbstract; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import javax.sip.ResponseEvent; + +/** + * @description: CANCEL响应处理器 + * @author: panlinlin + * @date: 2021年11月5日 16:35 + */ +@Component +public class CancelResponseProcessor extends SIPResponseProcessorAbstract { + + private String method = "CANCEL"; + + @Autowired + private SipLayer sipLayer; + + @Autowired + private SipConfig config; + + @Autowired + private SIPProcessorObserver sipProcessorObserver; + + @Override + public void afterPropertiesSet() throws Exception { + // 添加消息处理的订阅 + sipProcessorObserver.addResponseProcessor(method, this); + } + /** + * 处理CANCEL响应 + * + * @param evt + */ + @Override + public void process(ResponseEvent evt) { + // TODO Auto-generated method stub + + } + +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/response/impl/InviteResponseProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/response/impl/InviteResponseProcessor.java similarity index 61% rename from src/main/java/com/genersoft/iot/vmp/gb28181/transmit/response/impl/InviteResponseProcessor.java rename to src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/response/impl/InviteResponseProcessor.java index c807c04c5..5446a902a 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/response/impl/InviteResponseProcessor.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/response/impl/InviteResponseProcessor.java @@ -1,75 +1,97 @@ -package com.genersoft.iot.vmp.gb28181.transmit.response.impl; - -import java.text.ParseException; - -import javax.sip.*; -import javax.sip.address.SipURI; -import javax.sip.header.CSeqHeader; -import javax.sip.message.Request; -import javax.sip.message.Response; - -import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager; -import gov.nist.javax.sip.ResponseEventExt; -import gov.nist.javax.sip.stack.SIPDialog; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -import com.genersoft.iot.vmp.conf.SipConfig; -import com.genersoft.iot.vmp.gb28181.SipLayer; -import com.genersoft.iot.vmp.gb28181.transmit.response.ISIPResponseProcessor; - - -/** - * @Description:处理INVITE响应 - * @author: swwheihei - * @date: 2020年5月3日 下午4:43:52 - */ -@Component -public class InviteResponseProcessor implements ISIPResponseProcessor { - - private final static Logger logger = LoggerFactory.getLogger(InviteResponseProcessor.class); - - @Autowired - private VideoStreamSessionManager streamSession; - - /** - * 处理invite响应 - * - * @param evt 响应消息 - * @throws ParseException - */ - @Override - public void process(ResponseEvent evt, SipLayer layer, SipConfig config) throws ParseException { - try { - Response response = evt.getResponse(); - int statusCode = response.getStatusCode(); - // trying不会回复 - if (statusCode == Response.TRYING) { - } - // 成功响应 - // 下发ack - if (statusCode == Response.OK) { - ResponseEventExt event = (ResponseEventExt)evt; - SIPDialog dialog = (SIPDialog)evt.getDialog(); - CSeqHeader cseq = (CSeqHeader) response.getHeader(CSeqHeader.NAME); - Request reqAck = dialog.createAck(cseq.getSeqNumber()); - SipURI requestURI = (SipURI) reqAck.getRequestURI(); - requestURI.setHost(event.getRemoteIpAddress()); - requestURI.setPort(event.getRemotePort()); - reqAck.setRequestURI(requestURI); - logger.info("向 " + event.getRemoteIpAddress() + ":" + event.getRemotePort() + "回复ack"); - SipURI sipURI = (SipURI)dialog.getRemoteParty().getURI(); - String deviceId = requestURI.getUser(); - String channelId = sipURI.getUser(); - - dialog.sendAck(reqAck); - - } - } catch (InvalidArgumentException | SipException e) { - e.printStackTrace(); - } - } - -} +package com.genersoft.iot.vmp.gb28181.transmit.event.response.impl; + +import com.genersoft.iot.vmp.conf.SipConfig; +import com.genersoft.iot.vmp.gb28181.SipLayer; +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 gov.nist.javax.sip.ResponseEventExt; +import gov.nist.javax.sip.stack.SIPDialog; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import javax.sip.InvalidArgumentException; +import javax.sip.ResponseEvent; +import javax.sip.SipException; +import javax.sip.address.SipURI; +import javax.sip.header.CSeqHeader; +import javax.sip.message.Request; +import javax.sip.message.Response; +import java.text.ParseException; + + +/** + * @description: 处理INVITE响应 + * @author: panlinlin + * @date: 2021年11月5日 16:40 + */ +@Component +public class InviteResponseProcessor extends SIPResponseProcessorAbstract { + + private final static Logger logger = LoggerFactory.getLogger(InviteResponseProcessor.class); + private String method = "INVITE"; + + @Autowired + private SipLayer sipLayer; + + @Autowired + private SipConfig config; + + + @Autowired + private SIPProcessorObserver sipProcessorObserver; + + @Override + public void afterPropertiesSet() throws Exception { + // 添加消息处理的订阅 + sipProcessorObserver.addResponseProcessor(method, this); + } + + @Autowired + private VideoStreamSessionManager streamSession; + + /** + * 处理invite响应 + * + * @param evt 响应消息 + * @throws ParseException + */ + @Override + public void process(ResponseEvent evt ){ + try { + Response response = evt.getResponse(); + int statusCode = response.getStatusCode(); + // trying不会回复 + if (statusCode == Response.TRYING) { + } + // 成功响应 + // 下发ack + if (statusCode == Response.OK) { + ResponseEventExt event = (ResponseEventExt)evt; + SIPDialog dialog = (SIPDialog)evt.getDialog(); + CSeqHeader cseq = (CSeqHeader) response.getHeader(CSeqHeader.NAME); + Request reqAck = dialog.createAck(cseq.getSeqNumber()); + SipURI requestURI = (SipURI) reqAck.getRequestURI(); + try { + requestURI.setHost(event.getRemoteIpAddress()); + } catch (ParseException e) { + e.printStackTrace(); + } + requestURI.setPort(event.getRemotePort()); + reqAck.setRequestURI(requestURI); + logger.info("向 " + event.getRemoteIpAddress() + ":" + event.getRemotePort() + "回复ack"); + SipURI sipURI = (SipURI)dialog.getRemoteParty().getURI(); + String deviceId = requestURI.getUser(); + String channelId = sipURI.getUser(); + + dialog.sendAck(reqAck); + + } + } catch (InvalidArgumentException | SipException e) { + e.printStackTrace(); + } + } + +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/response/impl/RegisterResponseProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/response/impl/RegisterResponseProcessor.java similarity index 83% rename from src/main/java/com/genersoft/iot/vmp/gb28181/transmit/response/impl/RegisterResponseProcessor.java rename to src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/response/impl/RegisterResponseProcessor.java index f8a59bbac..a5dced37c 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/response/impl/RegisterResponseProcessor.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/response/impl/RegisterResponseProcessor.java @@ -1,11 +1,10 @@ -package com.genersoft.iot.vmp.gb28181.transmit.response.impl; +package com.genersoft.iot.vmp.gb28181.transmit.event.response.impl; -import com.genersoft.iot.vmp.conf.SipConfig; -import com.genersoft.iot.vmp.gb28181.SipLayer; import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; import com.genersoft.iot.vmp.gb28181.bean.ParentPlatformCatch; +import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver; import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform; -import com.genersoft.iot.vmp.gb28181.transmit.response.ISIPResponseProcessor; +import com.genersoft.iot.vmp.gb28181.transmit.event.response.SIPResponseProcessorAbstract; import com.genersoft.iot.vmp.storager.IRedisCatchStorage; import com.genersoft.iot.vmp.storager.IVideoManagerStorager; import org.slf4j.Logger; @@ -19,14 +18,15 @@ import javax.sip.header.WWWAuthenticateHeader; import javax.sip.message.Response; /** - * @Description:Register响应处理器 + * @description:Register响应处理器 * @author: swwheihei * @date: 2020年5月3日 下午5:32:23 */ @Component -public class RegisterResponseProcessor implements ISIPResponseProcessor { +public class RegisterResponseProcessor extends SIPResponseProcessorAbstract { private Logger logger = LoggerFactory.getLogger(RegisterResponseProcessor.class); + private String method = "REGISTER"; @Autowired private ISIPCommanderForPlatform sipCommanderForPlatform; @@ -37,18 +37,22 @@ public class RegisterResponseProcessor implements ISIPResponseProcessor { @Autowired private IRedisCatchStorage redisCatchStorage; - public RegisterResponseProcessor() { + @Autowired + private SIPProcessorObserver sipProcessorObserver; + + @Override + public void afterPropertiesSet() throws Exception { + // 添加消息处理的订阅 + sipProcessorObserver.addResponseProcessor(method, this); } /** * 处理Register响应 * - * @param evt - * @param layer - * @param config + * @param evt 事件 */ @Override - public void process(ResponseEvent evt, SipLayer layer, SipConfig config) { + public void process(ResponseEvent evt) { Response response = evt.getResponse(); CallIdHeader callIdHeader = (CallIdHeader) response.getHeader(CallIdHeader.NAME); String callId = callIdHeader.getCallId(); diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/timeout/ITimeoutProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/timeout/ITimeoutProcessor.java new file mode 100644 index 000000000..e0bb1f895 --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/timeout/ITimeoutProcessor.java @@ -0,0 +1,7 @@ +package com.genersoft.iot.vmp.gb28181.transmit.event.timeout; + +import javax.sip.TimeoutEvent; + +public interface ITimeoutProcessor { + void process(TimeoutEvent event); +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/timeout/impl/TimeoutProcessorImpl.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/timeout/impl/TimeoutProcessorImpl.java new file mode 100644 index 000000000..416500440 --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/timeout/impl/TimeoutProcessorImpl.java @@ -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 timeoutEventEventResult = new SipSubscribe.EventResult<>(event); + errorSubscribe.response(timeoutEventEventResult); + } +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/ISIPRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/ISIPRequestProcessor.java deleted file mode 100644 index 82e2f1d7e..000000000 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/ISIPRequestProcessor.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.genersoft.iot.vmp.gb28181.transmit.request; - -/** - * @Description:处理接收IPCamera发来的SIP协议请求消息 - * @author: swwheihei - * @date: 2020年5月3日 下午4:42:22 - */ -public interface ISIPRequestProcessor { - - public void process(); - -} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/SIPRequestAbstractProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/SIPRequestAbstractProcessor.java deleted file mode 100644 index 12290d2a6..000000000 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/SIPRequestAbstractProcessor.java +++ /dev/null @@ -1,131 +0,0 @@ -package com.genersoft.iot.vmp.gb28181.transmit.request; - -import javax.sip.PeerUnavailableException; -import javax.sip.RequestEvent; -import javax.sip.ServerTransaction; -import javax.sip.SipFactory; -import javax.sip.SipProvider; -import javax.sip.TransactionAlreadyExistsException; -import javax.sip.TransactionUnavailableException; -import javax.sip.address.AddressFactory; -import javax.sip.header.HeaderFactory; -import javax.sip.header.ViaHeader; -import javax.sip.message.MessageFactory; -import javax.sip.message.Request; - -import gov.nist.javax.sip.SipStackImpl; -import gov.nist.javax.sip.message.SIPRequest; -import gov.nist.javax.sip.stack.SIPServerTransaction; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * @Description:处理接收IPCamera发来的SIP协议请求消息 - * @author: songww - * @date: 2020年5月3日 下午4:42:22 - */ -public abstract class SIPRequestAbstractProcessor implements ISIPRequestProcessor { - - private final static Logger logger = LoggerFactory.getLogger(SIPRequestAbstractProcessor.class); - - protected RequestEvent evt; - - private SipProvider tcpSipProvider; - - private SipProvider udpSipProvider; - - @Override - public void process() { - this.process(evt); - } - - public abstract void process(RequestEvent evt); - - public ServerTransaction getServerTransaction(RequestEvent evt) { - Request request = evt.getRequest(); - ServerTransaction serverTransaction = evt.getServerTransaction(); - // 判断TCP还是UDP - boolean isTcp = false; - ViaHeader reqViaHeader = (ViaHeader) request.getHeader(ViaHeader.NAME); - String transport = reqViaHeader.getTransport(); - if (transport.equals("TCP")) { - isTcp = true; - } - - if (serverTransaction == null) { - try { - if (isTcp) { - SipStackImpl stack = (SipStackImpl)tcpSipProvider.getSipStack(); - serverTransaction = (SIPServerTransaction) stack.findTransaction((SIPRequest)request, true); - if (serverTransaction == null) { - serverTransaction = tcpSipProvider.getNewServerTransaction(request); - } - } else { - SipStackImpl stack = (SipStackImpl)udpSipProvider.getSipStack(); - serverTransaction = (SIPServerTransaction) stack.findTransaction((SIPRequest)request, true); - if (serverTransaction == null) { - serverTransaction = udpSipProvider.getNewServerTransaction(request); - } - } - } catch (TransactionAlreadyExistsException e) { - logger.error(e.getMessage()); - } catch (TransactionUnavailableException e) { - logger.error(e.getMessage()); - } - } - return serverTransaction; - } - - public AddressFactory getAddressFactory() { - try { - return SipFactory.getInstance().createAddressFactory(); - } catch (PeerUnavailableException e) { - e.printStackTrace(); - } - return null; - } - - public HeaderFactory getHeaderFactory() { - try { - return SipFactory.getInstance().createHeaderFactory(); - } catch (PeerUnavailableException e) { - e.printStackTrace(); - } - return null; - } - - public MessageFactory getMessageFactory() { - try { - return SipFactory.getInstance().createMessageFactory(); - } catch (PeerUnavailableException e) { - e.printStackTrace(); - } - return null; - } - - public RequestEvent getRequestEvent() { - return evt; - } - - public void setRequestEvent(RequestEvent evt) { - this.evt = evt; - } - - public SipProvider getTcpSipProvider() { - return tcpSipProvider; - } - - public void setTcpSipProvider(SipProvider tcpSipProvider) { - this.tcpSipProvider = tcpSipProvider; - } - - public SipProvider getUdpSipProvider() { - return udpSipProvider; - } - - public void setUdpSipProvider(SipProvider udpSipProvider) { - this.udpSipProvider = udpSipProvider; - } - - -} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/CancelRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/CancelRequestProcessor.java deleted file mode 100644 index 1b5b886da..000000000 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/CancelRequestProcessor.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.genersoft.iot.vmp.gb28181.transmit.request.impl; - -import javax.sip.RequestEvent; - -import com.genersoft.iot.vmp.gb28181.transmit.request.SIPRequestAbstractProcessor; - -/** - * @Description:CANCEL请求处理器 - * @author: swwheihei - * @date: 2020年5月3日 下午5:32:23 - */ -public class CancelRequestProcessor extends SIPRequestAbstractProcessor { - - /** - * 处理CANCEL请求 - * - * @param evt - * @param layer - * @param transaction - * @param config - */ - @Override - public void process(RequestEvent evt) { - // TODO 优先级99 Cancel Request消息实现,此消息一般为级联消息,上级给下级发送请求取消指令 - - } - -} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/OtherRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/OtherRequestProcessor.java deleted file mode 100644 index 65ed0c4d9..000000000 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/OtherRequestProcessor.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.genersoft.iot.vmp.gb28181.transmit.request.impl; - -import javax.sip.RequestEvent; - -import com.genersoft.iot.vmp.gb28181.transmit.request.SIPRequestAbstractProcessor; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * @Description:暂不支持的消息请求处理器 - * @author: swwheihei - * @date: 2020年5月3日 下午5:32:59 - */ -public class OtherRequestProcessor extends SIPRequestAbstractProcessor { - - private Logger logger = LoggerFactory.getLogger(OtherRequestProcessor.class); - - /** - *

Title: process

- *

Description:

- * @param evt - * @param layer - * @param transaction - * @param config - */ - @Override - public void process(RequestEvent evt) { - logger.info("Unsupported the method: " + evt.getRequest().getMethod()); - } - -} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/response/ISIPResponseProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/response/ISIPResponseProcessor.java deleted file mode 100644 index fee80ebad..000000000 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/response/ISIPResponseProcessor.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.genersoft.iot.vmp.gb28181.transmit.response; - -import java.text.ParseException; - -import javax.sip.ResponseEvent; - -import com.genersoft.iot.vmp.conf.SipConfig; -import com.genersoft.iot.vmp.gb28181.SipLayer; - -/** - * @Description:处理接收IPCamera发来的SIP协议响应消息 - * @author: swwheihei - * @date: 2020年5月3日 下午4:42:22 - */ -public interface ISIPResponseProcessor { - - public void process(ResponseEvent evt, SipLayer layer, SipConfig config) throws ParseException; - -} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/response/impl/ByeResponseProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/response/impl/ByeResponseProcessor.java deleted file mode 100644 index c35431c28..000000000 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/response/impl/ByeResponseProcessor.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.genersoft.iot.vmp.gb28181.transmit.response.impl; - -import javax.sip.ResponseEvent; - -import org.springframework.stereotype.Component; - -import com.genersoft.iot.vmp.conf.SipConfig; -import com.genersoft.iot.vmp.gb28181.SipLayer; -import com.genersoft.iot.vmp.gb28181.transmit.response.ISIPResponseProcessor; - -/** - * @Description: BYE请求响应器 - * @author: swwheihei - * @date: 2020年5月3日 下午5:32:05 - */ -@Component -public class ByeResponseProcessor implements ISIPResponseProcessor { - - /** - * 处理BYE响应 - * - * @param evt - * @param layer - * @param config - */ - @Override - public void process(ResponseEvent evt, SipLayer layer, SipConfig config) { - // TODO Auto-generated method stub - } - -} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/response/impl/CancelResponseProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/response/impl/CancelResponseProcessor.java deleted file mode 100644 index c6fd9b394..000000000 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/response/impl/CancelResponseProcessor.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.genersoft.iot.vmp.gb28181.transmit.response.impl; - -import javax.sip.ResponseEvent; - -import org.springframework.stereotype.Component; - -import com.genersoft.iot.vmp.conf.SipConfig; -import com.genersoft.iot.vmp.gb28181.SipLayer; -import com.genersoft.iot.vmp.gb28181.transmit.response.ISIPResponseProcessor; - -/** - * @Description:CANCEL响应处理器 - * @author: swwheihei - * @date: 2020年5月3日 下午5:32:23 - */ -@Component -public class CancelResponseProcessor implements ISIPResponseProcessor { - - /** - * 处理CANCEL响应 - * - * @param evt - * @param layer - * @param transaction - * @param config - */ - @Override - public void process(ResponseEvent evt, SipLayer layer, SipConfig config) { - // TODO Auto-generated method stub - - } - -} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/response/impl/OtherResponseProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/response/impl/OtherResponseProcessor.java deleted file mode 100644 index 16314409d..000000000 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/response/impl/OtherResponseProcessor.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.genersoft.iot.vmp.gb28181.transmit.response.impl; - -import javax.sip.ResponseEvent; - -import org.springframework.stereotype.Component; - -import com.genersoft.iot.vmp.conf.SipConfig; -import com.genersoft.iot.vmp.gb28181.SipLayer; -import com.genersoft.iot.vmp.gb28181.transmit.response.ISIPResponseProcessor; - -/** - * @Description:暂不支持的消息响应处理器 - * @author: swwheihei - * @date: 2020年5月3日 下午5:32:59 - */ -@Component -public class OtherResponseProcessor implements ISIPResponseProcessor { - - /** - *

Title: process

- *

Description:

- * @param evt - * @param layer - * @param config - */ - @Override - public void process(ResponseEvent evt, SipLayer layer, SipConfig config) { - // TODO Auto-generated method stub - - } - -} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/utils/DateUtil.java b/src/main/java/com/genersoft/iot/vmp/gb28181/utils/DateUtil.java index 195b7e368..604c08353 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/utils/DateUtil.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/utils/DateUtil.java @@ -6,7 +6,7 @@ import java.util.Date; import java.util.Locale; /** - * @Description:时间工具类,主要处理ISO 8601格式转换 + * @description:时间工具类,主要处理ISO 8601格式转换 * @author: swwheihei * @date: 2020年5月8日 下午3:24:42 */ diff --git a/src/main/java/com/genersoft/iot/vmp/utils/SipUtils.java b/src/main/java/com/genersoft/iot/vmp/gb28181/utils/SipUtils.java similarity index 72% rename from src/main/java/com/genersoft/iot/vmp/utils/SipUtils.java rename to src/main/java/com/genersoft/iot/vmp/gb28181/utils/SipUtils.java index b889be212..9dd027152 100644 --- a/src/main/java/com/genersoft/iot/vmp/utils/SipUtils.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/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 @@ import javax.sip.message.Request; /** * @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(); } + } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/utils/XmlUtil.java b/src/main/java/com/genersoft/iot/vmp/gb28181/utils/XmlUtil.java index 4220d8161..079a78bb5 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/utils/XmlUtil.java +++ b/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; @@ -19,6 +11,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 class XmlUtil { } } } + 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(); + } } diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java index 0de3cb85b..f74dcfa76 100644 --- a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java +++ b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java @@ -31,7 +31,7 @@ import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; import javax.servlet.http.HttpServletRequest; /** - * @Description:针对 ZLMediaServer的hook事件监听 + * @description:针对 ZLMediaServer的hook事件监听 * @author: swwheihei * @date: 2020年5月8日 上午10:46:48 */ diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookSubscribe.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookSubscribe.java index be69df1fc..c47c394ea 100644 --- a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookSubscribe.java +++ b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookSubscribe.java @@ -8,7 +8,7 @@ import java.util.*; import java.util.concurrent.ConcurrentHashMap; /** - * @Description:针对 ZLMediaServer的hook事件订阅 + * @description:针对 ZLMediaServer的hook事件订阅 * @author: pan * @date: 2020年12月2日 21:17:32 */ diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRESTfulUtils.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRESTfulUtils.java index b7e996772..2c95216ac 100644 --- a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRESTfulUtils.java +++ b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRESTfulUtils.java @@ -55,6 +55,9 @@ public class ZLMRESTfulUtils { if (responseStr != null) { responseJSON = JSON.parseObject(responseStr); } + }else { + response.close(); + Objects.requireNonNull(response.body()).close(); } } catch (ConnectException e) { logger.error(String.format("连接ZLM失败: %s, %s", e.getCause().getMessage(), e.getMessage())); @@ -74,6 +77,10 @@ public class ZLMRESTfulUtils { } catch (IOException e) { logger.error(String.format("[ %s ]请求失败: %s", url, e.getMessage())); } + + }else { + response.close(); + Objects.requireNonNull(response.body()).close(); } } diff --git a/src/main/java/com/genersoft/iot/vmp/service/IDeviceService.java b/src/main/java/com/genersoft/iot/vmp/service/IDeviceService.java new file mode 100644 index 000000000..0cb841364 --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/service/IDeviceService.java @@ -0,0 +1,24 @@ +package com.genersoft.iot.vmp.service; + +import com.genersoft.iot.vmp.gb28181.bean.Device; + +/** + * 设备相关业务处理 + */ +public interface IDeviceService { + + /** + * 添加目录订阅 + * @param device 设备信息 + * @return + */ + boolean addCatalogSubscribe(Device device); + + /** + * 移除目录订阅 + * @param device 设备信息 + * @return + */ + boolean removeCatalogSubscribe(Device device); + +} diff --git a/src/main/java/com/genersoft/iot/vmp/service/bean/CatalogSubscribeTask.java b/src/main/java/com/genersoft/iot/vmp/service/bean/CatalogSubscribeTask.java new file mode 100644 index 000000000..eb179d7e0 --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/service/bean/CatalogSubscribeTask.java @@ -0,0 +1,48 @@ +package com.genersoft.iot.vmp.service.bean; + +import com.genersoft.iot.vmp.gb28181.bean.Device; +import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander; +import com.genersoft.iot.vmp.gb28181.utils.XmlUtil; +import org.dom4j.DocumentException; +import org.dom4j.Element; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.sip.ResponseEvent; + +public class CatalogSubscribeTask implements Runnable{ + private final Logger logger = LoggerFactory.getLogger(CatalogSubscribeTask.class); + private Device device; + private ISIPCommander sipCommander; + + public CatalogSubscribeTask(Device device, ISIPCommander sipCommander) { + this.device = device; + this.sipCommander = sipCommander; + } + + @Override + public void run() { + sipCommander.catalogSubscribe(device, eventResult -> { + ResponseEvent event = (ResponseEvent) eventResult.event; + Element rootElement = null; + try { + rootElement = XmlUtil.getRootElement(event.getResponse().getRawContent(), "gb2312"); + } catch (DocumentException e) { + e.printStackTrace(); + } + Element resultElement = rootElement.element("Result"); + String result = resultElement.getText(); + if (result.toUpperCase().equals("OK")){ + // 成功 + logger.info("目录订阅成功: {}", device.getDeviceId()); + }else { + // 失败 + logger.info("目录订阅失败: {}-{}", device.getDeviceId(), result); + } + + },eventResult -> { + // 失败 + logger.warn("目录订阅失败: {}-信令发送失败", device.getDeviceId()); + }); + } +} diff --git a/src/main/java/com/genersoft/iot/vmp/service/impl/DeviceServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/service/impl/DeviceServiceImpl.java new file mode 100644 index 000000000..595f38c88 --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/service/impl/DeviceServiceImpl.java @@ -0,0 +1,61 @@ +package com.genersoft.iot.vmp.service.impl; + +import com.genersoft.iot.vmp.conf.DynamicTask; +import com.genersoft.iot.vmp.gb28181.bean.Device; +import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander; +import com.genersoft.iot.vmp.service.IDeviceService; +import com.genersoft.iot.vmp.service.bean.CatalogSubscribeTask; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class DeviceServiceImpl implements IDeviceService { + + private final static Logger logger = LoggerFactory.getLogger(DeviceServiceImpl.class); + + @Autowired + private DynamicTask dynamicTask; +; + + @Autowired + private ISIPCommander sipCommander; + + @Override + public boolean addCatalogSubscribe(Device device) { + if (device == null || device.getSubscribeCycleForCatalog() < 0) { + return false; + } + // 添加目录订阅 + CatalogSubscribeTask catalogSubscribeTask = new CatalogSubscribeTask(device, sipCommander); + catalogSubscribeTask.run(); + // 提前开始刷新订阅 + String cron = getCron(device.getSubscribeCycleForCatalog() - 60); + dynamicTask.startCron(device.getDeviceId(), catalogSubscribeTask, cron); + return true; + } + + @Override + public boolean removeCatalogSubscribe(Device device) { + if (device == null || device.getSubscribeCycleForCatalog() < 0) { + return false; + } + dynamicTask.stopCron(device.getDeviceId()); + return true; + } + + public String getCron(int time) { + if (time <= 59) { + return "0/" + time +" * * * * ?"; + }else if (time <= 60* 59) { + int minute = time/(60); + return "0 0/" + minute +" * * * ?"; + }else if (time <= 60* 60* 59) { + int hour = time/(60*60); + return "0 0 0/" + hour +" * * ?"; + }else { + return "0 0/10 * * * ?"; + } + } +} diff --git a/src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorager.java b/src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorager.java index 266c94554..931530aef 100644 --- a/src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorager.java +++ b/src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorager.java @@ -1,7 +1,5 @@ package com.genersoft.iot.vmp.storager; -import java.util.List; - import com.genersoft.iot.vmp.gb28181.bean.*; import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem; @@ -9,8 +7,10 @@ import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem; import com.genersoft.iot.vmp.vmanager.gb28181.platform.bean.ChannelReduce; import com.github.pagehelper.PageInfo; +import java.util.List; + /** - * @Description:视频设备数据存储接口 + * @description:视频设备数据存储接口 * @author: swwheihei * @date: 2020年5月6日 下午2:14:31 */ @@ -97,6 +97,13 @@ public interface IVideoManagerStorager { */ public DeviceChannel queryChannel(String deviceId, String channelId); + /** + * 删除通道 + * @param deviceId 设备ID + * @param channelId 通道ID + */ + public int delChannel(String deviceId, String channelId); + /** * 获取多个设备 * @param page 当前页数 @@ -373,7 +380,30 @@ public interface IVideoManagerStorager { */ void updateMediaServer(MediaServerItem mediaServerItem); + /** + * 根据媒体ID获取启用/不启用的代理列表 + * @param id 媒体ID + * @param b 启用/不启用 + * @return + */ List getStreamProxyListForEnableInMediaServer(String id, boolean b); - Device queryVideoDeviceByChannelId(String platformGbId); + /** + * 根据通道ID获取其所在设备 + * @param channelId 通道ID + * @return + */ + Device queryVideoDeviceByChannelId(String channelId); + + /** + * 通道上线 + * @param channelId 通道ID + */ + void deviceChannelOnline(String deviceId, String channelId); + + /** + * 通道离线 + * @param channelId 通道ID + */ + void deviceChannelOffline(String deviceId, String channelId); } diff --git a/src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceChannelMapper.java b/src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceChannelMapper.java index f7b89a980..eef7a155a 100644 --- a/src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceChannelMapper.java +++ b/src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceChannelMapper.java @@ -74,6 +74,9 @@ public interface DeviceChannelMapper { @Delete("DELETE FROM device_channel WHERE deviceId=#{deviceId}") int cleanChannelsByDeviceId(String deviceId); + @Delete("DELETE FROM device_channel WHERE deviceId=#{deviceId} AND channelId=#{channelId}") + int del(String deviceId, String channelId); + @Update(value = {"UPDATE device_channel SET streamId=null WHERE deviceId=#{deviceId} AND channelId=#{channelId}"}) void stopPlay(String deviceId, String channelId); @@ -104,5 +107,11 @@ public interface DeviceChannelMapper { List queryChannelListInAll(String query, Boolean online, Boolean hasSubChannel, String platformId, Boolean inPlatform); @Select("SELECT * FROM device_channel WHERE channelId=#{channelId}") - List queryChannelByChannelId(String channelId); + List queryChannelByChannelId( String channelId); + + @Update(value = {"UPDATE device_channel SET status=0 WHERE deviceId=#{deviceId} AND channelId=#{channelId}"}) + void offline(String deviceId, String channelId); + + @Update(value = {"UPDATE device_channel SET status=1 WHERE deviceId=#{deviceId} AND channelId=#{channelId}"}) + void online(String deviceId, String channelId); } diff --git a/src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceMapper.java b/src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceMapper.java index 68ad28df5..ed2d8c89b 100644 --- a/src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceMapper.java +++ b/src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceMapper.java @@ -33,6 +33,7 @@ public interface DeviceMapper { "createTime," + "updateTime," + "charset," + + "subscribeCycleForCatalog," + "online" + ") VALUES (" + "#{deviceId}," + @@ -51,6 +52,7 @@ public interface DeviceMapper { "#{createTime}," + "#{updateTime}," + "#{charset}," + + "#{subscribeCycleForCatalog}," + "#{online}" + ")") int add(Device device); @@ -72,6 +74,7 @@ public interface DeviceMapper { ", keepaliveTime='${keepaliveTime}'" + ", expires=${expires}" + ", charset='${charset}'" + + ", subscribeCycleForCatalog=#{subscribeCycleForCatalog}" + "WHERE deviceId='${deviceId}'"+ " "}) int update(Device device); diff --git a/src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStoragerImpl.java b/src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStoragerImpl.java index 89c1d6c14..0e24942df 100644 --- a/src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStoragerImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStoragerImpl.java @@ -1,14 +1,12 @@ package com.genersoft.iot.vmp.storager.impl; -import java.text.SimpleDateFormat; -import java.util.*; - import com.genersoft.iot.vmp.gb28181.bean.*; import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager; import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem; import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem; import com.genersoft.iot.vmp.storager.IRedisCatchStorage; +import com.genersoft.iot.vmp.storager.IVideoManagerStorager; import com.genersoft.iot.vmp.storager.dao.*; import com.genersoft.iot.vmp.vmanager.gb28181.platform.bean.ChannelReduce; import com.github.pagehelper.PageHelper; @@ -18,14 +16,18 @@ import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.datasource.DataSourceTransactionManager; import org.springframework.stereotype.Component; - -import com.genersoft.iot.vmp.storager.IVideoManagerStorager; import org.springframework.transaction.TransactionDefinition; import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.annotation.Transactional; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + /** - * @Description:视频设备数据存储-jdbc实现 + * @description:视频设备数据存储-jdbc实现 * @author: swwheihei * @date: 2020年5月6日 下午2:31:42 */ @@ -137,6 +139,16 @@ public class VideoManagerStoragerImpl implements IVideoManagerStorager { } } + @Override + public void deviceChannelOnline(String deviceId, String channelId) { + deviceChannelMapper.online(deviceId, channelId); + } + + @Override + public void deviceChannelOffline(String deviceId, String channelId) { + deviceChannelMapper.offline(deviceId, channelId); + } + @Override public void startPlay(String deviceId, String channelId, String streamId) { deviceChannelMapper.startPlay(deviceId, channelId, streamId); @@ -184,6 +196,11 @@ public class VideoManagerStoragerImpl implements IVideoManagerStorager { } + @Override + public int delChannel(String deviceId, String channelId) { + return deviceChannelMapper.del(deviceId, channelId); + } + /** * 获取多个设备 * @@ -624,8 +641,9 @@ public class VideoManagerStoragerImpl implements IVideoManagerStorager { return streamProxyMapper.selectForEnableInMediaServer(id, enable); } + @Override - public Device queryVideoDeviceByChannelId(String channelId) { + public Device queryVideoDeviceByChannelId( String channelId) { Device result = null; List channelList = deviceChannelMapper.queryChannelByChannelId(channelId); if (channelList.size() == 1) { diff --git a/src/main/java/com/genersoft/iot/vmp/utils/SpringBeanFactory.java b/src/main/java/com/genersoft/iot/vmp/utils/SpringBeanFactory.java index ccbe94d69..3d2b2ba05 100644 --- a/src/main/java/com/genersoft/iot/vmp/utils/SpringBeanFactory.java +++ b/src/main/java/com/genersoft/iot/vmp/utils/SpringBeanFactory.java @@ -6,7 +6,7 @@ import org.springframework.context.ApplicationContextAware; import org.springframework.stereotype.Component; /** - * @Description:spring bean获取工厂,获取spring中的已初始化的bean + * @description:spring bean获取工厂,获取spring中的已初始化的bean * @author: swwheihei * @date: 2019年6月25日 下午4:51:52 * diff --git a/src/main/java/com/genersoft/iot/vmp/utils/redis/FastJsonRedisSerializer.java b/src/main/java/com/genersoft/iot/vmp/utils/redis/FastJsonRedisSerializer.java index 411f96228..05d7f811f 100644 --- a/src/main/java/com/genersoft/iot/vmp/utils/redis/FastJsonRedisSerializer.java +++ b/src/main/java/com/genersoft/iot/vmp/utils/redis/FastJsonRedisSerializer.java @@ -9,7 +9,7 @@ import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.serializer.SerializerFeature; /** - * @Description:使用fastjson实现redis的序列化 + * @description:使用fastjson实现redis的序列化 * @author: swwheihei * @date: 2020年5月6日 下午8:40:11 */ diff --git a/src/main/java/com/genersoft/iot/vmp/utils/redis/JedisUtil.java b/src/main/java/com/genersoft/iot/vmp/utils/redis/JedisUtil.java index 54e5422f2..1fb1d17e1 100644 --- a/src/main/java/com/genersoft/iot/vmp/utils/redis/JedisUtil.java +++ b/src/main/java/com/genersoft/iot/vmp/utils/redis/JedisUtil.java @@ -8,7 +8,7 @@ import redis.clients.jedis.JedisPool; import java.util.Set; /** - * @Description:Jedis工具类 + * @description:Jedis工具类 * @author: wangshaopeng@sunnybs.com * @date: 2021年03月22日 下午8:27:29 */ diff --git a/src/main/java/com/genersoft/iot/vmp/utils/redis/RedisUtil.java b/src/main/java/com/genersoft/iot/vmp/utils/redis/RedisUtil.java index dd5614f07..35da67881 100644 --- a/src/main/java/com/genersoft/iot/vmp/utils/redis/RedisUtil.java +++ b/src/main/java/com/genersoft/iot/vmp/utils/redis/RedisUtil.java @@ -9,7 +9,7 @@ import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; /** - * @Description:Redis工具类 + * @description:Redis工具类 * @author: swwheihei * @date: 2020年5月6日 下午8:27:29 */ diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceQuery.java b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceQuery.java index c75082174..729eca282 100644 --- a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceQuery.java +++ b/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.util.StringUtils; 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 = "国标设备查询") @@ -50,6 +51,9 @@ public class DeviceQuery { @Autowired private DeviceOffLineDetector offLineDetector; + @Autowired + private IDeviceService deviceService; + /** * 使用ID查询国标设备 * @param deviceId 国标ID @@ -301,6 +305,18 @@ public class DeviceQuery { 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); } diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/ptz/PtzController.java b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/ptz/PtzController.java index 255329ba9..68acde331 100644 --- a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/ptz/PtzController.java +++ b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/ptz/PtzController.java @@ -54,7 +54,7 @@ public class PtzController { @ApiImplicitParams({ @ApiImplicitParam(name = "deviceId", value = "设备ID", dataTypeClass = String.class), @ApiImplicitParam(name = "channelId", value = "通道ID", dataTypeClass = String.class), - @ApiImplicitParam(name = "command", value = "控制指令,允许值: left, right, up, down, upleft, upright, downleft, downright, zoomin, zoomout, stop", dataTypeClass = Integer.class), + @ApiImplicitParam(name = "command", value = "控制指令,允许值: left, right, up, down, upleft, upright, downleft, downright, zoomin, zoomout, stop", dataTypeClass = String.class), @ApiImplicitParam(name = "horizonSpeed", value = "水平速度", dataTypeClass = Integer.class), @ApiImplicitParam(name = "verticalSpeed", value = "垂直速度", dataTypeClass = Integer.class), @ApiImplicitParam(name = "zoomSpeed", value = "缩放速度", dataTypeClass = Integer.class), diff --git a/src/main/resources/all-application.yml b/src/main/resources/all-application.yml index f2d85ec02..e7d681067 100644 --- a/src/main/resources/all-application.yml +++ b/src/main/resources/all-application.yml @@ -73,7 +73,7 @@ sip: # [可选] 默认设备认证密码,后续扩展使用设备单独密码, 移除密码将不进行校验 password: admin123 # [可选] 心跳超时时间, 建议设置为心跳周期的三倍 - keepalive-timeout: 180 + keepalive-timeout: 255 # [可选] 国标级联注册失败,再次发起注册的时间间隔。 默认60秒 register-time-interval: 60 # [可选] 云台控制速度 diff --git a/src/main/resources/wvp.sqlite b/src/main/resources/wvp.sqlite index c2e089306..88aea8ed9 100644 Binary files a/src/main/resources/wvp.sqlite and b/src/main/resources/wvp.sqlite differ