mirror of
https://gitee.com/pan648540858/wvp-GB28181-pro.git
synced 2026-05-26 23:17:50 +08:00
Merge remote-tracking branch 'origin/wvp-28181-2.0' into wvp-28181-2.0
This commit is contained in:
commit
d0de0c15ae
@ -1,5 +1,7 @@
|
||||
FROM ubuntu:20.04 AS build
|
||||
|
||||
# DEBIAN_FRONTEND这个环境变量,告知操作系统应该从哪儿获得用户输入。
|
||||
# 如果设置为”noninteractive”,你就可以直接运行命令,而无需向用户请求输入(所有操作都是非交互式的)。
|
||||
ARG DEBIAN_FRONTEND=noninteractive
|
||||
ENV TZ=Asia/Shanghai
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
package com.genersoft.iot.vmp.common;
|
||||
|
||||
/**
|
||||
* @Description: 定义常量
|
||||
* @description: 定义常量
|
||||
* @author: swwheihei
|
||||
* @date: 2019年5月30日 下午3:04:04
|
||||
*
|
||||
|
||||
42
src/main/java/com/genersoft/iot/vmp/conf/DynamicTask.java
Normal file
42
src/main/java/com/genersoft/iot/vmp/conf/DynamicTask.java
Normal file
@ -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<String, ScheduledFuture<?>> 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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -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
|
||||
*
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -32,5 +32,7 @@ public class SipDeviceRunner implements CommandLineRunner {
|
||||
for (String deviceId : onlineForAll) {
|
||||
storager.online(deviceId);
|
||||
}
|
||||
|
||||
// TODO 查询在线设备那些开启了订阅,为设备开启定时的目录订阅
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
|
||||
*/
|
||||
|
||||
@ -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<Runnable> processQueue = new LinkedBlockingQueue<>(10000);
|
||||
processThreadPool = new ThreadPoolExecutor(processThreadNum,processThreadNum,
|
||||
0L,TimeUnit.MILLISECONDS,processQueue,
|
||||
new ThreadPoolExecutor.CallerRunsPolicy());
|
||||
return processThreadPool;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Bean("sipFactory")
|
||||
@DependsOn("initSipServer")
|
||||
private SipFactory createSipFactory() {
|
||||
sipFactory = SipFactory.getInstance();
|
||||
sipFactory.setPathName("gov.nist");
|
||||
@ -70,7 +59,7 @@ 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Title: processTimeout
|
||||
* </p>
|
||||
* <p>
|
||||
* Description:
|
||||
* </p>
|
||||
*
|
||||
* @param timeoutEvent
|
||||
*/
|
||||
@Override
|
||||
public void processTimeout(TimeoutEvent timeoutEvent) {
|
||||
// TODO Auto-generated method stub
|
||||
CallIdHeader callIdHeader = timeoutEvent.getClientTransaction().getDialog().getCallId();
|
||||
String callId = callIdHeader.getCallId();
|
||||
SipSubscribe.Event errorSubscribe = sipSubscribe.getErrorSubscribe(callId);
|
||||
SipSubscribe.EventResult<TimeoutEvent> timeoutEventEventResult = new SipSubscribe.EventResult<>(timeoutEvent);
|
||||
errorSubscribe.response(timeoutEventEventResult);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Title: processIOException
|
||||
* </p>
|
||||
* <p>
|
||||
* Description:
|
||||
* </p>
|
||||
*
|
||||
* @param exceptionEvent
|
||||
*/
|
||||
@Override
|
||||
public void processIOException(IOExceptionEvent exceptionEvent) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Title: processTransactionTerminated
|
||||
* </p>
|
||||
* <p>
|
||||
* Description:
|
||||
* </p>
|
||||
*
|
||||
* @param transactionTerminatedEvent
|
||||
*/
|
||||
@Override
|
||||
public void processTransactionTerminated(TransactionTerminatedEvent transactionTerminatedEvent) {
|
||||
// TODO Auto-generated method stub
|
||||
// CallIdHeader callIdHeader = transactionTerminatedEvent.getClientTransaction().getDialog().getCallId();
|
||||
// String callId = callIdHeader.getCallId();
|
||||
// SipSubscribe.Event errorSubscribe = sipSubscribe.getErrorSubscribe(callId);
|
||||
// SipSubscribe.EventResult<TransactionTerminatedEvent> eventResult = new SipSubscribe.EventResult<>(transactionTerminatedEvent);
|
||||
// errorSubscribe.response(eventResult);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Title: processDialogTerminated
|
||||
* </p>
|
||||
* <p>
|
||||
* Description:
|
||||
* </p>
|
||||
*
|
||||
* @param dialogTerminatedEvent
|
||||
*/
|
||||
@Override
|
||||
public void processDialogTerminated(DialogTerminatedEvent dialogTerminatedEvent) {
|
||||
// TODO Auto-generated method stub
|
||||
// CallIdHeader callIdHeader = dialogTerminatedEvent.getDialog().getCallId();
|
||||
// String callId = callIdHeader.getCallId();
|
||||
// SipSubscribe.Event errorSubscribe = sipSubscribe.getErrorSubscribe(callId);
|
||||
// SipSubscribe.EventResult<DialogTerminatedEvent> eventResult = new SipSubscribe.EventResult<>(dialogTerminatedEvent);
|
||||
// errorSubscribe.response(eventResult);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -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
|
||||
*/
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
package com.genersoft.iot.vmp.gb28181.bean;
|
||||
|
||||
/**
|
||||
* @Description: 移动位置bean
|
||||
* @description: 移动位置bean
|
||||
* @author: lawrencehj
|
||||
* @date: 2021年1月23日
|
||||
*/
|
||||
|
||||
@ -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
|
||||
*/
|
||||
|
||||
@ -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
|
||||
*/
|
||||
|
||||
@ -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
|
||||
*/
|
||||
|
||||
@ -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
|
||||
*/
|
||||
|
||||
@ -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
|
||||
*/
|
||||
|
||||
@ -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
|
||||
*/
|
||||
|
||||
@ -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
|
||||
*/
|
||||
|
||||
@ -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<OfflineEvent> {
|
||||
|
||||
// 处理离线监听
|
||||
storager.outline(event.getDeviceId());
|
||||
|
||||
// TODO 离线取消订阅
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
|
||||
*/
|
||||
|
||||
@ -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
|
||||
*/
|
||||
|
||||
@ -18,7 +18,7 @@ import javax.sip.ResponseEvent;
|
||||
import javax.sip.message.Response;
|
||||
|
||||
/**
|
||||
* @Description: 平台心跳超时事件
|
||||
* @description: 平台心跳超时事件
|
||||
* @author: panll
|
||||
* @date: 2020年11月5日 10:00
|
||||
*/
|
||||
|
||||
@ -19,7 +19,7 @@ import org.springframework.stereotype.Component;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @Description: 平台未注册事件,来源有二:
|
||||
* @description: 平台未注册事件,来源有二:
|
||||
* 1、平台新添加
|
||||
* 2、平台心跳超时
|
||||
* @author: panll
|
||||
|
||||
@ -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
|
||||
*/
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@ -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<String, ISIPRequestProcessor> requestProcessorMap = new ConcurrentHashMap<>();
|
||||
private static Map<String, ISIPResponseProcessor> 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);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -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) {
|
||||
|
||||
@ -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
|
||||
*/
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
package com.genersoft.iot.vmp.gb28181.transmit.callback;
|
||||
|
||||
/**
|
||||
* @Description: 请求信息定义
|
||||
* @description: 请求信息定义
|
||||
* @author: swwheihei
|
||||
* @date: 2020年5月8日 下午1:09:18
|
||||
*/
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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
|
||||
*/
|
||||
|
||||
@ -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
|
||||
*/
|
||||
|
||||
@ -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("<?xml version=\"1.0\" encoding=\"GB2312\"?>\r\n");
|
||||
cmdXml.append("<Query>\r\n");
|
||||
cmdXml.append("<CmdType>CataLog</CmdType>\r\n");
|
||||
cmdXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
|
||||
cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
|
||||
cmdXml.append("</Query>\r\n");
|
||||
|
||||
String tm = Long.toString(System.currentTimeMillis());
|
||||
|
||||
CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
|
||||
: udpSipProvider.getNewCallId();
|
||||
|
||||
Request request = headerProvider.createSubscribeRequest(device, cmdXml.toString(), "z9hG4bK-viaPos-" + tm, "fromTagPos" + tm, null, device.getSubscribeCycleForCatalog(), "presence" , callIdHeader);
|
||||
transmitRequest(device, request, errorEvent, okEvent);
|
||||
|
||||
return true;
|
||||
|
||||
} catch ( NumberFormatException | ParseException | InvalidArgumentException | SipException e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private ClientTransaction transmitRequest(Device device, Request request) throws SipException {
|
||||
return transmitRequest(device, request, null, null);
|
||||
|
||||
@ -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);
|
||||
|
||||
}
|
||||
@ -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;
|
||||
|
||||
}
|
||||
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@ -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<String, Object> 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<String, Object> 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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<String, Object> 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<String, Object> 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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消息实现,此消息一般为级联消息,上级给下级发送请求取消指令
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@ -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<Element> 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) {
|
||||
}
|
||||
|
||||
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
@ -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<String, IMessageHandler> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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<String, IMessageHandler> 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
@ -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) {
|
||||
|
||||
}
|
||||
}
|
||||
@ -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<ChannelReduce> channelReduces = storager.queryChannelListInParentPlatform(parentPlatform.getServerGBId());
|
||||
// 查询关联的直播通道
|
||||
List<GbStream> 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();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@ -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) {
|
||||
// 不会收到上级平台的心跳信息
|
||||
|
||||
}
|
||||
}
|
||||
@ -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) {
|
||||
|
||||
}
|
||||
}
|
||||
@ -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) {
|
||||
|
||||
}
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
@ -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<ChannelReduce> channelReduces = storager.queryChannelListInParentPlatform(parentPlatform.getServerGBId());
|
||||
// 查询关联的直播通道
|
||||
List<GbStream> 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();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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());
|
||||
}
|
||||
}
|
||||
@ -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());
|
||||
}
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
@ -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) {
|
||||
|
||||
}
|
||||
}
|
||||
@ -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) {
|
||||
|
||||
}
|
||||
}
|
||||
@ -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<Element> 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) {
|
||||
|
||||
}
|
||||
}
|
||||
@ -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) {
|
||||
// 不会收到上级平台的心跳信息
|
||||
|
||||
}
|
||||
}
|
||||
@ -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) {
|
||||
}
|
||||
}
|
||||
@ -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) {
|
||||
}
|
||||
}
|
||||
@ -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) {
|
||||
|
||||
}
|
||||
}
|
||||
@ -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) {
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@ -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) {
|
||||
|
||||
}
|
||||
}
|
||||
@ -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<String> 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<Element> recordListIterator = recordListElement.elementIterator();
|
||||
List<RecordItem> recordList = new ArrayList<RecordItem>();
|
||||
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) {
|
||||
|
||||
}
|
||||
}
|
||||
@ -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);
|
||||
|
||||
|
||||
}
|
||||
@ -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 {
|
||||
|
||||
|
||||
}
|
||||
@ -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");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -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
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -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();
|
||||
@ -0,0 +1,7 @@
|
||||
package com.genersoft.iot.vmp.gb28181.transmit.event.timeout;
|
||||
|
||||
import javax.sip.TimeoutEvent;
|
||||
|
||||
public interface ITimeoutProcessor {
|
||||
void process(TimeoutEvent event);
|
||||
}
|
||||
@ -0,0 +1,36 @@
|
||||
package com.genersoft.iot.vmp.gb28181.transmit.event.timeout.impl;
|
||||
|
||||
import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
|
||||
import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver;
|
||||
import com.genersoft.iot.vmp.gb28181.transmit.event.timeout.ITimeoutProcessor;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.sip.TimeoutEvent;
|
||||
import javax.sip.header.CallIdHeader;
|
||||
|
||||
@Component
|
||||
public class TimeoutProcessorImpl implements InitializingBean, ITimeoutProcessor {
|
||||
|
||||
@Autowired
|
||||
private SIPProcessorObserver processorObserver;
|
||||
|
||||
@Autowired
|
||||
private SipSubscribe sipSubscribe;
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
processorObserver.addTimeoutProcessor(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process(TimeoutEvent event) {
|
||||
// TODO Auto-generated method stub
|
||||
CallIdHeader callIdHeader = event.getClientTransaction().getDialog().getCallId();
|
||||
String callId = callIdHeader.getCallId();
|
||||
SipSubscribe.Event errorSubscribe = sipSubscribe.getErrorSubscribe(callId);
|
||||
SipSubscribe.EventResult<TimeoutEvent> timeoutEventEventResult = new SipSubscribe.EventResult<>(event);
|
||||
errorSubscribe.response(timeoutEventEventResult);
|
||||
}
|
||||
}
|
||||
@ -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();
|
||||
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -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消息实现,此消息一般为级联消息,上级给下级发送请求取消指令
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@ -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);
|
||||
|
||||
/**
|
||||
* <p>Title: process</p>
|
||||
* <p>Description: </p>
|
||||
* @param evt
|
||||
* @param layer
|
||||
* @param transaction
|
||||
* @param config
|
||||
*/
|
||||
@Override
|
||||
public void process(RequestEvent evt) {
|
||||
logger.info("Unsupported the method: " + evt.getRequest().getMethod());
|
||||
}
|
||||
|
||||
}
|
||||
@ -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;
|
||||
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
|
||||
}
|
||||
@ -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
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@ -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 {
|
||||
|
||||
/**
|
||||
* <p>Title: process</p>
|
||||
* <p>Description: </p>
|
||||
* @param evt
|
||||
* @param layer
|
||||
* @param config
|
||||
*/
|
||||
@Override
|
||||
public void process(ResponseEvent evt, SipLayer layer, SipConfig config) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@ -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
|
||||
*/
|
||||
|
||||
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
|
||||
*/
|
||||
|
||||
@ -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
|
||||
*/
|
||||
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
}
|
||||
@ -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());
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -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 * * * ?";
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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<StreamProxyItem> 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);
|
||||
}
|
||||
|
||||
@ -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<ChannelReduce> queryChannelListInAll(String query, Boolean online, Boolean hasSubChannel, String platformId, Boolean inPlatform);
|
||||
|
||||
@Select("SELECT * FROM device_channel WHERE channelId=#{channelId}")
|
||||
List<DeviceChannel> queryChannelByChannelId(String channelId);
|
||||
List<DeviceChannel> 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);
|
||||
}
|
||||
|
||||
@ -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 {
|
||||
"<if test=\"keepaliveTime != null\">, keepaliveTime='${keepaliveTime}'</if>" +
|
||||
"<if test=\"expires != null\">, expires=${expires}</if>" +
|
||||
"<if test=\"charset != null\">, charset='${charset}'</if>" +
|
||||
"<if test=\"subscribeCycleForCatalog != null\">, subscribeCycleForCatalog=#{subscribeCycleForCatalog}</if>" +
|
||||
"WHERE deviceId='${deviceId}'"+
|
||||
" </script>"})
|
||||
int update(Device device);
|
||||
|
||||
@ -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<DeviceChannel> channelList = deviceChannelMapper.queryChannelByChannelId(channelId);
|
||||
if (channelList.size() == 1) {
|
||||
|
||||
@ -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
|
||||
*
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user