Merge remote-tracking branch 'origin/wvp-28181-2.0' into wvp-28181-2.0

This commit is contained in:
xiaoxie 2021-11-15 15:09:08 +08:00
commit d0de0c15ae
107 changed files with 5363 additions and 3269 deletions

View File

@ -1,5 +1,7 @@
FROM ubuntu:20.04 AS build FROM ubuntu:20.04 AS build
# DEBIAN_FRONTEND这个环境变量告知操作系统应该从哪儿获得用户输入。
# 如果设置为”noninteractive”你就可以直接运行命令而无需向用户请求输入所有操作都是非交互式的
ARG DEBIAN_FRONTEND=noninteractive ARG DEBIAN_FRONTEND=noninteractive
ENV TZ=Asia/Shanghai ENV TZ=Asia/Shanghai

View File

@ -1,7 +1,7 @@
package com.genersoft.iot.vmp.common; package com.genersoft.iot.vmp.common;
/** /**
* @Description: 定义常量 * @description: 定义常量
* @author: swwheihei * @author: swwheihei
* @date: 2019年5月30日 下午3:04:04 * @date: 2019年5月30日 下午3:04:04
* *

View 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);
}
}
}

View File

@ -16,7 +16,7 @@ import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig; import redis.clients.jedis.JedisPoolConfig;
/** /**
* @Description:Redis中间件配置类使用spring-data-redis集成自动从application.yml中加载redis配置 * @description:Redis中间件配置类使用spring-data-redis集成自动从application.yml中加载redis配置
* @author: swwheihei * @author: swwheihei
* @date: 2019年5月30日 上午10:58:25 * @date: 2019年5月30日 上午10:58:25
* *

View File

@ -1,9 +1,7 @@
package com.genersoft.iot.vmp.conf; package com.genersoft.iot.vmp.conf;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@Component @Component
@ -27,7 +25,7 @@ public class SipConfig {
Integer ptzSpeed = 50; Integer ptzSpeed = 50;
Integer keepaliveTimeOut = 180; Integer keepaliveTimeOut = 255;
Integer registerTimeInterval = 60; Integer registerTimeInterval = 60;

View File

@ -32,5 +32,7 @@ public class SipDeviceRunner implements CommandLineRunner {
for (String deviceId : onlineForAll) { for (String deviceId : onlineForAll) {
storager.online(deviceId); storager.online(deviceId);
} }
// TODO 查询在线设备那些开启了订阅为设备开启定时的目录订阅
} }
} }

View File

@ -4,7 +4,7 @@ import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
/** /**
* @Description: 获取数据库配置 * @description: 获取数据库配置
* @author: swwheihei * @author: swwheihei
* @date: 2020年5月6日 下午2:46:00 * @date: 2020年5月6日 下午2:46:00
*/ */

View File

@ -1,19 +1,10 @@
package com.genersoft.iot.vmp.gb28181; package com.genersoft.iot.vmp.gb28181;
import java.text.ParseException; import com.genersoft.iot.vmp.conf.SipConfig;
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.gb28181.event.SipSubscribe; 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.SipProviderImpl;
import gov.nist.javax.sip.SipStackImpl;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; 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.context.annotation.DependsOn;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import com.genersoft.iot.vmp.conf.SipConfig; import javax.sip.*;
import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorFactory; import java.util.Properties;
import com.genersoft.iot.vmp.gb28181.transmit.response.ISIPResponseProcessor; import java.util.TooManyListenersException;
import java.util.concurrent.LinkedBlockingQueue;
import gov.nist.javax.sip.SipStackImpl; import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
@Component @Component
public class SipLayer implements SipListener { public class SipLayer{
private final static Logger logger = LoggerFactory.getLogger(SipLayer.class); private final static Logger logger = LoggerFactory.getLogger(SipLayer.class);
@ -36,7 +28,7 @@ public class SipLayer implements SipListener {
private SipConfig sipConfig; private SipConfig sipConfig;
@Autowired @Autowired
private SIPProcessorFactory processorFactory; private SIPProcessorObserver sipProcessorObserver;
@Autowired @Autowired
private SipSubscribe sipSubscribe; private SipSubscribe sipSubscribe;
@ -50,19 +42,16 @@ public class SipLayer implements SipListener {
*/ */
private ThreadPoolExecutor processThreadPool; private ThreadPoolExecutor processThreadPool;
@Bean("initSipServer") public SipLayer() {
private ThreadPoolExecutor initSipServer() {
int processThreadNum = Runtime.getRuntime().availableProcessors() * 10; int processThreadNum = Runtime.getRuntime().availableProcessors() * 10;
LinkedBlockingQueue<Runnable> processQueue = new LinkedBlockingQueue<>(10000); LinkedBlockingQueue<Runnable> processQueue = new LinkedBlockingQueue<>(10000);
processThreadPool = new ThreadPoolExecutor(processThreadNum,processThreadNum, processThreadPool = new ThreadPoolExecutor(processThreadNum,processThreadNum,
0L,TimeUnit.MILLISECONDS,processQueue, 0L,TimeUnit.MILLISECONDS,processQueue,
new ThreadPoolExecutor.CallerRunsPolicy()); new ThreadPoolExecutor.CallerRunsPolicy());
return processThreadPool;
} }
@Bean("sipFactory") @Bean("sipFactory")
@DependsOn("initSipServer")
private SipFactory createSipFactory() { private SipFactory createSipFactory() {
sipFactory = SipFactory.getInstance(); sipFactory = SipFactory.getInstance();
sipFactory.setPathName("gov.nist"); sipFactory.setPathName("gov.nist");
@ -70,7 +59,7 @@ public class SipLayer implements SipListener {
} }
@Bean("sipStack") @Bean("sipStack")
@DependsOn({"initSipServer", "sipFactory"}) @DependsOn({"sipFactory"})
private SipStack createSipStack() throws PeerUnavailableException { private SipStack createSipStack() throws PeerUnavailableException {
Properties properties = new Properties(); Properties properties = new Properties();
properties.setProperty("javax.sip.STACK_NAME", "GB28181_SIP"); properties.setProperty("javax.sip.STACK_NAME", "GB28181_SIP");
@ -88,7 +77,7 @@ public class SipLayer implements SipListener {
return sipStack; return sipStack;
} }
@Bean("tcpSipProvider") @Bean(name = "tcpSipProvider")
@DependsOn("sipStack") @DependsOn("sipStack")
private SipProviderImpl startTcpListener() { private SipProviderImpl startTcpListener() {
ListeningPoint tcpListeningPoint = null; ListeningPoint tcpListeningPoint = null;
@ -96,7 +85,7 @@ public class SipLayer implements SipListener {
try { try {
tcpListeningPoint = sipStack.createListeningPoint(sipConfig.getMonitorIp(), sipConfig.getPort(), "TCP"); tcpListeningPoint = sipStack.createListeningPoint(sipConfig.getMonitorIp(), sipConfig.getPort(), "TCP");
tcpSipProvider = (SipProviderImpl)sipStack.createSipProvider(tcpListeningPoint); tcpSipProvider = (SipProviderImpl)sipStack.createSipProvider(tcpListeningPoint);
tcpSipProvider.addSipListener(this); tcpSipProvider.addSipListener(sipProcessorObserver);
logger.info("Sip Server TCP 启动成功 port {" + sipConfig.getMonitorIp() + ":" + sipConfig.getPort() + "}"); logger.info("Sip Server TCP 启动成功 port {" + sipConfig.getMonitorIp() + ":" + sipConfig.getPort() + "}");
} catch (TransportNotSupportedException e) { } catch (TransportNotSupportedException e) {
e.printStackTrace(); e.printStackTrace();
@ -111,7 +100,7 @@ public class SipLayer implements SipListener {
return tcpSipProvider; return tcpSipProvider;
} }
@Bean("udpSipProvider") @Bean(name = "udpSipProvider")
@DependsOn("sipStack") @DependsOn("sipStack")
private SipProviderImpl startUdpListener() { private SipProviderImpl startUdpListener() {
ListeningPoint udpListeningPoint = null; ListeningPoint udpListeningPoint = null;
@ -119,8 +108,7 @@ public class SipLayer implements SipListener {
try { try {
udpListeningPoint = sipStack.createListeningPoint(sipConfig.getMonitorIp(), sipConfig.getPort(), "UDP"); udpListeningPoint = sipStack.createListeningPoint(sipConfig.getMonitorIp(), sipConfig.getPort(), "UDP");
udpSipProvider = (SipProviderImpl)sipStack.createSipProvider(udpListeningPoint); udpSipProvider = (SipProviderImpl)sipStack.createSipProvider(udpListeningPoint);
udpSipProvider.addSipListener(this); udpSipProvider.addSipListener(sipProcessorObserver);
// udpSipProvider.setAutomaticDialogSupportEnabled(false);
} catch (TransportNotSupportedException e) { } catch (TransportNotSupportedException e) {
e.printStackTrace(); e.printStackTrace();
} catch (InvalidArgumentException e) { } catch (InvalidArgumentException e) {
@ -135,140 +123,4 @@ public class SipLayer implements SipListener {
return udpSipProvider; 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)) {
// 增加其它无需回复的响应如101180等
} 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);
}
} }

View File

@ -9,7 +9,7 @@ import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
/** /**
* @Description:注册逻辑处理当设备注册后触发逻辑 * @description:注册逻辑处理当设备注册后触发逻辑
* @author: swwheihei * @author: swwheihei
* @date: 2020年5月8日 下午9:41:46 * @date: 2020年5月8日 下午9:41:46
*/ */

View File

@ -109,6 +109,11 @@ public class Device {
*/ */
private String charset ; private String charset ;
/**
* 目录订阅周期0为不订阅
*/
private int subscribeCycleForCatalog ;
public String getDeviceId() { public String getDeviceId() {
@ -270,4 +275,12 @@ public class Device {
public void setCharset(String charset) { public void setCharset(String charset) {
this.charset = charset; this.charset = charset;
} }
public int getSubscribeCycleForCatalog() {
return subscribeCycleForCatalog;
}
public void setSubscribeCycleForCatalog(int subscribeCycleForCatalog) {
this.subscribeCycleForCatalog = subscribeCycleForCatalog;
}
} }

View File

@ -1,7 +1,7 @@
package com.genersoft.iot.vmp.gb28181.bean; package com.genersoft.iot.vmp.gb28181.bean;
/** /**
* @Description: 移动位置bean * @description: 移动位置bean
* @author: lawrencehj * @author: lawrencehj
* @date: 2021年1月23日 * @date: 2021年1月23日
*/ */

View File

@ -6,7 +6,7 @@ package com.genersoft.iot.vmp.gb28181.bean;
import java.util.List; import java.util.List;
/** /**
* @Description:设备录像信息bean * @description:设备录像信息bean
* @author: swwheihei * @author: swwheihei
* @date: 2020年5月8日 下午2:05:56 * @date: 2020年5月8日 下午2:05:56
*/ */

View File

@ -8,7 +8,7 @@ import java.text.SimpleDateFormat;
import java.util.Date; import java.util.Date;
/** /**
* @Description:设备录像bean * @description:设备录像bean
* @author: swwheihei * @author: swwheihei
* @date: 2020年5月8日 下午2:06:54 * @date: 2020年5月8日 下午2:06:54
*/ */

View File

@ -7,7 +7,7 @@ import com.genersoft.iot.vmp.common.VideoManagerConstants;
import com.genersoft.iot.vmp.utils.redis.RedisUtil; import com.genersoft.iot.vmp.utils.redis.RedisUtil;
/** /**
* @Description:设备离在线状态检测器用于检测设备状态 * @description:设备离在线状态检测器用于检测设备状态
* @author: swwheihei * @author: swwheihei
* @date: 2020年5月13日 下午2:40:29 * @date: 2020年5月13日 下午2:40:29
*/ */

View File

@ -13,7 +13,7 @@ import com.genersoft.iot.vmp.gb28181.event.offline.OfflineEvent;
import com.genersoft.iot.vmp.gb28181.event.online.OnlineEvent; import com.genersoft.iot.vmp.gb28181.event.online.OnlineEvent;
/** /**
* @Description:Event事件通知推送器支持推送在线事件离线事件 * @description:Event事件通知推送器支持推送在线事件离线事件
* @author: swwheihei * @author: swwheihei
* @date: 2020年5月6日 上午11:30:50 * @date: 2020年5月6日 上午11:30:50
*/ */

View File

@ -12,7 +12,7 @@ import com.genersoft.iot.vmp.common.VideoManagerConstants;
import com.genersoft.iot.vmp.gb28181.event.EventPublisher; import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
/** /**
* @Description:设备心跳超时监听,借助redis过期特性进行监听监听到说明设备心跳超时发送离线事件 * @description:设备心跳超时监听,借助redis过期特性进行监听监听到说明设备心跳超时发送离线事件
* @author: swwheihei * @author: swwheihei
* @date: 2020年5月6日 上午11:35:46 * @date: 2020年5月6日 上午11:35:46
*/ */

View File

@ -12,7 +12,7 @@ import com.genersoft.iot.vmp.common.VideoManagerConstants;
import com.genersoft.iot.vmp.gb28181.event.EventPublisher; import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
/** /**
* @Description:设备心跳超时监听,借助redis过期特性进行监听监听到说明设备心跳超时发送离线事件 * @description:设备心跳超时监听,借助redis过期特性进行监听监听到说明设备心跳超时发送离线事件
* @author: swwheihei * @author: swwheihei
* @date: 2020年5月6日 上午11:35:46 * @date: 2020年5月6日 上午11:35:46
*/ */

View File

@ -3,7 +3,7 @@ package com.genersoft.iot.vmp.gb28181.event.offline;
import org.springframework.context.ApplicationEvent; import org.springframework.context.ApplicationEvent;
/** /**
* @Description: 离线事件类 * @description: 离线事件类
* @author: swwheihei * @author: swwheihei
* @date: 2020年5月6日 上午11:33:13 * @date: 2020年5月6日 上午11:33:13
*/ */

View File

@ -11,8 +11,8 @@ import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
import com.genersoft.iot.vmp.utils.redis.RedisUtil; import com.genersoft.iot.vmp.utils.redis.RedisUtil;
/** /**
* @Description: 离线事件监听器监听到离线后修改设备离在线状态 设备离线有两个来源 * @description: 离线事件监听器监听到离线后修改设备离在线状态 设备离线有两个来源
* 1设备主动注销发送注销指令{@link com.genersoft.iot.vmp.gb28181.transmit.request.impl.RegisterRequestProcessor} * 1设备主动注销发送注销指令{@link com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.RegisterRequestProcessor}
* 2设备未知原因离线心跳超时,{@link com.genersoft.iot.vmp.gb28181.event.offline.OfflineEventListener} * 2设备未知原因离线心跳超时,{@link com.genersoft.iot.vmp.gb28181.event.offline.OfflineEventListener}
* @author: swwheihei * @author: swwheihei
* @date: 2020年5月6日 下午1:51:23 * @date: 2020年5月6日 下午1:51:23
@ -54,5 +54,8 @@ public class OfflineEventListener implements ApplicationListener<OfflineEvent> {
// 处理离线监听 // 处理离线监听
storager.outline(event.getDeviceId()); storager.outline(event.getDeviceId());
// TODO 离线取消订阅
} }
} }

View File

@ -4,7 +4,7 @@ import com.genersoft.iot.vmp.gb28181.bean.Device;
import org.springframework.context.ApplicationEvent; import org.springframework.context.ApplicationEvent;
/** /**
* @Description: 在线事件类 * @description: 在线事件类
* @author: swwheihei * @author: swwheihei
* @date: 2020年5月6日 上午11:32:56 * @date: 2020年5月6日 上午11:32:56
*/ */

View File

@ -13,12 +13,11 @@ import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
import com.genersoft.iot.vmp.utils.redis.RedisUtil; import com.genersoft.iot.vmp.utils.redis.RedisUtil;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.Date;
/** /**
* @Description: 在线事件监听器监听到离线后修改设备离在线状态 设备在线有两个来源 * @description: 在线事件监听器监听到离线后修改设备离在线状态 设备在线有两个来源
* 1设备主动注销发送注销指令{@link com.genersoft.iot.vmp.gb28181.transmit.request.impl.RegisterRequestProcessor} * 1设备主动注销发送注销指令
* 2设备未知原因离线心跳超时,{@link com.genersoft.iot.vmp.gb28181.transmit.request.impl.MessageRequestProcessor} * 2设备未知原因离线心跳超时
* @author: swwheihei * @author: swwheihei
* @date: 2020年5月6日 下午1:51:23 * @date: 2020年5月6日 下午1:51:23
*/ */

View File

@ -18,7 +18,7 @@ import javax.sip.ResponseEvent;
import javax.sip.message.Response; import javax.sip.message.Response;
/** /**
* @Description: 平台心跳超时事件 * @description: 平台心跳超时事件
* @author: panll * @author: panll
* @date: 2020年11月5日 10:00 * @date: 2020年11月5日 10:00
*/ */

View File

@ -19,7 +19,7 @@ import org.springframework.stereotype.Component;
import java.util.*; import java.util.*;
/** /**
* @Description: 平台未注册事件,来源有二: * @description: 平台未注册事件,来源有二:
* 1平台新添加 * 1平台新添加
* 2平台心跳超时 * 2平台心跳超时
* @author: panll * @author: panll

View File

@ -15,7 +15,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
/** /**
* @Description:视频流session管理器管理视频预览预览回放的通信句柄 * @description:视频流session管理器管理视频预览预览回放的通信句柄
* @author: swwheihei * @author: swwheihei
* @date: 2020年5月13日 下午4:03:02 * @date: 2020年5月13日 下午4:03:02
*/ */

View File

@ -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;
}
}

View File

@ -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日 下午1532
*/
@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)) {
// 增加其它无需回复的响应如101180等
} 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);
}
}

View File

@ -1,17 +1,16 @@
package com.genersoft.iot.vmp.gb28181.transmit.callback; 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.ArrayList;
import java.util.Comparator; import java.util.Comparator;
import java.util.List; import java.util.List;
import java.util.concurrent.TimeUnit; 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") @SuppressWarnings("unchecked")
public class CheckForAllRecordsThread extends Thread { public class CheckForAllRecordsThread extends Thread {
@ -58,7 +57,7 @@ public class CheckForAllRecordsThread extends Thread {
msg.setData(recordInfo); msg.setData(recordInfo);
deferredResultHolder.invokeAllResult(msg); deferredResultHolder.invokeAllResult(msg);
logger.info("处理完成,返回结果"); logger.info("处理完成,返回结果");
MessageRequestProcessor.threadNameList.remove(cacheKey); RecordInfoResponseMessageHandler.threadNameList.remove(cacheKey);
} }
public void setRedis(RedisUtil redis) { public void setRedis(RedisUtil redis) {

View File

@ -11,7 +11,7 @@ import org.springframework.stereotype.Component;
import org.springframework.web.context.request.async.DeferredResult; import org.springframework.web.context.request.async.DeferredResult;
/** /**
* @Description: 异步请求处理 * @description: 异步请求处理
* @author: swwheihei * @author: swwheihei
* @date: 2020年5月8日 下午7:59:05 * @date: 2020年5月8日 下午7:59:05
*/ */

View File

@ -1,7 +1,7 @@
package com.genersoft.iot.vmp.gb28181.transmit.callback; package com.genersoft.iot.vmp.gb28181.transmit.callback;
/** /**
* @Description: 请求信息定义 * @description: 请求信息定义
* @author: swwheihei * @author: swwheihei
* @date: 2020年5月8日 下午1:09:18 * @date: 2020年5月8日 下午1:09:18
*/ */

View File

@ -7,7 +7,7 @@ import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
import com.genersoft.iot.vmp.service.bean.SSRCInfo; import com.genersoft.iot.vmp.service.bean.SSRCInfo;
/** /**
* @Description:设备能力接口用于定义设备的控制查询能力 * @description:设备能力接口用于定义设备的控制查询能力
* @author: swwheihei * @author: swwheihei
* @date: 2020年5月3日 下午9:16:34 * @date: 2020年5月3日 下午9:16:34
*/ */
@ -299,4 +299,11 @@ public interface ISIPCommander {
* @return true = 命令发送成功 * @return true = 命令发送成功
*/ */
boolean alarmSubscribe(Device device, int expires, String startPriority, String endPriority, String alarmMethod, String alarmType, String startTime, String endTime); 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);
} }

View File

@ -19,7 +19,7 @@ import java.util.List;
import java.util.UUID; import java.util.UUID;
/** /**
* @Description: 平台命令request创造器 TODO 冗余代码太多待优化 * @description: 平台命令request创造器 TODO 冗余代码太多待优化
* @author: panll * @author: panll
* @date: 2020年5月6日 上午9:29:02 * @date: 2020年5月6日 上午9:29:02
*/ */

View File

@ -18,7 +18,7 @@ import com.genersoft.iot.vmp.conf.SipConfig;
import com.genersoft.iot.vmp.gb28181.bean.Device; import com.genersoft.iot.vmp.gb28181.bean.Device;
/** /**
* @Description:摄像头命令request创造器 TODO 冗余代码太多待优化 * @description:摄像头命令request创造器 TODO 冗余代码太多待优化
* @author: swwheihei * @author: swwheihei
* @date: 2020年5月6日 上午9:29:02 * @date: 2020年5月6日 上午9:29:02
*/ */

View File

@ -1,20 +1,17 @@
package com.genersoft.iot.vmp.gb28181.transmit.cmd.impl; 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.alibaba.fastjson.JSONObject;
import com.genersoft.iot.vmp.conf.SipConfig;
import com.genersoft.iot.vmp.conf.UserSetup; 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.gb28181.bean.SsrcTransaction;
import com.genersoft.iot.vmp.media.zlm.*;
import com.genersoft.iot.vmp.gb28181.event.SipSubscribe; 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.media.zlm.dto.MediaServerItem;
import com.genersoft.iot.vmp.service.IMediaServerService; import com.genersoft.iot.vmp.service.IMediaServerService;
import com.genersoft.iot.vmp.service.bean.SSRCInfo; 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.Autowired;
import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.DependsOn; import org.springframework.context.annotation.DependsOn;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component; 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 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 * @author: swwheihei
* @date: 2020年5月3日 下午9:22:48 * @date: 2020年5月3日 下午9:22:48
*/ */
@ -55,12 +52,10 @@ public class SIPCommander implements ISIPCommander {
@Autowired @Autowired
private SipConfig sipConfig; private SipConfig sipConfig;
@Lazy
@Autowired @Autowired
@Qualifier(value="tcpSipProvider") @Qualifier(value="tcpSipProvider")
private SipProviderImpl tcpSipProvider; private SipProviderImpl tcpSipProvider;
@Lazy
@Autowired @Autowired
@Qualifier(value="udpSipProvider") @Qualifier(value="udpSipProvider")
private SipProviderImpl udpSipProvider; private SipProviderImpl udpSipProvider;
@ -89,11 +84,6 @@ public class SIPCommander implements ISIPCommander {
@Autowired @Autowired
private IMediaServerService mediaServerService; 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 { private ClientTransaction transmitRequest(Device device, Request request) throws SipException {
return transmitRequest(device, request, null, null); return transmitRequest(device, request, null, null);

View File

@ -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日 1547
*/
public interface ISIPRequestProcessor {
void process(RequestEvent event);
}

View File

@ -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;
}

View File

@ -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();
}
}

View File

@ -1,142 +1,125 @@
package com.genersoft.iot.vmp.gb28181.transmit.request.impl; package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl;
import java.util.HashMap; import com.genersoft.iot.vmp.common.StreamInfo;
import java.util.Map; import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver;
import javax.sip.*; import com.genersoft.iot.vmp.gb28181.transmit.event.request.ISIPRequestProcessor;
import javax.sip.address.SipURI; import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
import javax.sip.header.FromHeader; import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
import javax.sip.header.HeaderAddress; import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
import javax.sip.header.ToHeader; import com.genersoft.iot.vmp.service.IMediaServerService;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import com.genersoft.iot.vmp.common.StreamInfo; import org.slf4j.Logger;
import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem; import org.slf4j.LoggerFactory;
import com.genersoft.iot.vmp.gb28181.transmit.request.SIPRequestAbstractProcessor; import org.springframework.beans.factory.InitializingBean;
import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory; import org.springframework.beans.factory.annotation.Autowired;
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; import org.springframework.stereotype.Component;
import com.genersoft.iot.vmp.service.IMediaServerService;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage; import javax.sip.Dialog;
import org.slf4j.Logger; import javax.sip.DialogState;
import org.slf4j.LoggerFactory; import javax.sip.RequestEvent;
import javax.sip.address.SipURI;
/** import javax.sip.header.FromHeader;
* @Description:ACK请求处理器 import javax.sip.header.HeaderAddress;
* @author: swwheihei import javax.sip.header.ToHeader;
* @date: 2020年5月3日 下午5:31:45 import java.util.HashMap;
*/ import java.util.Map;
public class AckRequestProcessor extends SIPRequestAbstractProcessor {
/**
private Logger logger = LoggerFactory.getLogger(AckRequestProcessor.class); * @description:ACK请求处理器
* @author: swwheihei
private IRedisCatchStorage redisCatchStorage; * @date: 2020年5月3日 下午5:31:45
*/
private ZLMRTPServerFactory zlmrtpServerFactory; @Component
public class AckRequestProcessor extends SIPRequestProcessorParent implements InitializingBean, ISIPRequestProcessor {
private IMediaServerService mediaServerService;
private Logger logger = LoggerFactory.getLogger(AckRequestProcessor.class);
/** private String method = "ACK";
* 处理 ACK请求
* @Autowired
* @param evt private SIPProcessorObserver sipProcessorObserver;
*/
@Override @Override
public void process(RequestEvent evt) { public void afterPropertiesSet() throws Exception {
//Request request = evt.getRequest(); // 添加消息处理的订阅
Dialog dialog = evt.getDialog(); sipProcessorObserver.addRequestProcessor(method, this);
if (dialog == null) return; }
//DialogState state = dialog.getState();
if (/*request.getMecodewwthod().equals(Request.INVITE) &&*/ dialog.getState()== DialogState.CONFIRMED) { @Autowired
String platformGbId = ((SipURI) ((HeaderAddress) evt.getRequest().getHeader(FromHeader.NAME)).getAddress().getURI()).getUser(); private IRedisCatchStorage redisCatchStorage;
String channelId = ((SipURI) ((HeaderAddress) evt.getRequest().getHeader(ToHeader.NAME)).getAddress().getURI()).getUser();
SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(platformGbId, channelId); @Autowired
String is_Udp = sendRtpItem.isTcp() ? "0" : "1"; private ZLMRTPServerFactory zlmrtpServerFactory;
String deviceId = sendRtpItem.getDeviceId();
StreamInfo streamInfo = null; @Autowired
if (deviceId == null) { private IMediaServerService mediaServerService;
streamInfo = new StreamInfo();
streamInfo.setApp(sendRtpItem.getApp());
streamInfo.setStreamId(sendRtpItem.getStreamId()); /**
}else { * 处理 ACK请求
streamInfo = redisCatchStorage.queryPlayByDevice(deviceId, channelId); *
sendRtpItem.setStreamId(streamInfo.getStreamId()); * @param evt
streamInfo.setApp("rtp"); */
} @Override
public void process(RequestEvent evt) {
redisCatchStorage.updateSendRTPSever(sendRtpItem); Dialog dialog = evt.getDialog();
logger.info(platformGbId); if (dialog == null) return;
logger.info(channelId); if (dialog.getState()== DialogState.CONFIRMED) {
Map<String, Object> param = new HashMap<>(); String platformGbId = ((SipURI) ((HeaderAddress) evt.getRequest().getHeader(FromHeader.NAME)).getAddress().getURI()).getUser();
param.put("vhost","__defaultVhost__"); String channelId = ((SipURI) ((HeaderAddress) evt.getRequest().getHeader(ToHeader.NAME)).getAddress().getURI()).getUser();
param.put("app",streamInfo.getApp()); SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(platformGbId, channelId);
param.put("stream",streamInfo.getStreamId()); String is_Udp = sendRtpItem.isTcp() ? "0" : "1";
param.put("ssrc", sendRtpItem.getSsrc()); String deviceId = sendRtpItem.getDeviceId();
param.put("dst_url",sendRtpItem.getIp()); StreamInfo streamInfo = null;
param.put("dst_port", sendRtpItem.getPort()); if (deviceId == null) {
param.put("is_udp", is_Udp); streamInfo = new StreamInfo();
//param.put ("src_port", sendRtpItem.getLocalPort()); streamInfo.setApp(sendRtpItem.getApp());
// 设备推流查询成功后才能转推 streamInfo.setStreamId(sendRtpItem.getStreamId());
boolean rtpPushed = false; }else {
long startTime = System.currentTimeMillis(); streamInfo = redisCatchStorage.queryPlayByDevice(deviceId, channelId);
while (!rtpPushed) { sendRtpItem.setStreamId(streamInfo.getStreamId());
try { streamInfo.setApp("rtp");
if (System.currentTimeMillis() - startTime < 30 * 1000) { }
MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId());
if (zlmrtpServerFactory.isStreamReady(mediaInfo, streamInfo.getApp(), streamInfo.getStreamId())) { redisCatchStorage.updateSendRTPSever(sendRtpItem);
rtpPushed = true; logger.info(platformGbId);
logger.info("已获取设备推流[{}/{}],开始向上级推流[{}:{}]", logger.info(channelId);
streamInfo.getApp() ,streamInfo.getStreamId(), sendRtpItem.getIp(), sendRtpItem.getPort()); Map<String, Object> param = new HashMap<>();
zlmrtpServerFactory.startSendRtpStream(mediaInfo, param); param.put("vhost","__defaultVhost__");
} else { param.put("app",streamInfo.getApp());
logger.info("等待设备推流[{}/{}].......", param.put("stream",streamInfo.getStreamId());
streamInfo.getApp() ,streamInfo.getStreamId()); param.put("ssrc", sendRtpItem.getSsrc());
Thread.sleep(1000); param.put("dst_url",sendRtpItem.getIp());
continue; param.put("dst_port", sendRtpItem.getPort());
} param.put("is_udp", is_Udp);
} else { //param.put ("src_port", sendRtpItem.getLocalPort());
rtpPushed = true; // 设备推流查询成功后才能转推
logger.info("设备推流[{}/{}]超时,终止向上级推流", boolean rtpPushed = false;
streamInfo.getApp() ,streamInfo.getStreamId()); long startTime = System.currentTimeMillis();
} while (!rtpPushed) {
} catch (InterruptedException e) { try {
e.printStackTrace(); if (System.currentTimeMillis() - startTime < 30 * 1000) {
} MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId());
} if (zlmrtpServerFactory.isStreamReady(mediaInfo, streamInfo.getApp(), streamInfo.getStreamId())) {
} rtpPushed = true;
// try { logger.info("已获取设备推流[{}/{}],开始向上级推流[{}:{}]",
// Request ackRequest = null; streamInfo.getApp() ,streamInfo.getStreamId(), sendRtpItem.getIp(), sendRtpItem.getPort());
// CSeq csReq = (CSeq) request.getHeader(CSeq.NAME); zlmrtpServerFactory.startSendRtpStream(mediaInfo, param);
// ackRequest = dialog.createAck(csReq.getSeqNumber()); } else {
// dialog.sendAck(ackRequest); logger.info("等待设备推流[{}/{}].......",
// logger.info("send ack to callee:" + ackRequest.toString()); streamInfo.getApp() ,streamInfo.getStreamId());
// } catch (SipException e) { Thread.sleep(1000);
// e.printStackTrace(); continue;
// } catch (InvalidArgumentException e) { }
// e.printStackTrace(); } else {
// } rtpPushed = true;
logger.info("设备推流[{}/{}]超时,终止向上级推流",
} streamInfo.getApp() ,streamInfo.getStreamId());
}
public IRedisCatchStorage getRedisCatchStorage() { } catch (InterruptedException e) {
return redisCatchStorage; e.printStackTrace();
} }
}
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;
}
}

View File

@ -1,150 +1,117 @@
package com.genersoft.iot.vmp.gb28181.transmit.request.impl; package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl;
import javax.sip.*; import com.genersoft.iot.vmp.common.StreamInfo;
import javax.sip.address.SipURI; import com.genersoft.iot.vmp.gb28181.bean.Device;
import javax.sip.header.FromHeader; import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
import javax.sip.header.HeaderAddress; import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver;
import javax.sip.header.ToHeader; import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander;
import javax.sip.message.Response; 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.common.StreamInfo; import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
import com.genersoft.iot.vmp.gb28181.bean.Device; import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem; import com.genersoft.iot.vmp.service.IMediaServerService;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander; import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import com.genersoft.iot.vmp.gb28181.transmit.request.SIPRequestAbstractProcessor; import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory; import org.slf4j.Logger;
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; import org.slf4j.LoggerFactory;
import com.genersoft.iot.vmp.service.IMediaServerService; import org.springframework.beans.factory.InitializingBean;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage; import org.springframework.beans.factory.annotation.Autowired;
import com.genersoft.iot.vmp.storager.IVideoManagerStorager; import org.springframework.stereotype.Component;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import javax.sip.*;
import javax.sip.address.SipURI;
import java.text.ParseException; import javax.sip.header.FromHeader;
import java.util.HashMap; import javax.sip.header.HeaderAddress;
import java.util.Map; import javax.sip.header.ToHeader;
import javax.sip.message.Response;
/** import java.text.ParseException;
* @Description: BYE请求处理器 import java.util.HashMap;
* @author: lawrencehj import java.util.Map;
* @date: 2021年3月9日
*/ /**
public class ByeRequestProcessor extends SIPRequestAbstractProcessor { * @description: BYE请求处理器
* @author: lawrencehj
private Logger logger = LoggerFactory.getLogger(ByeRequestProcessor.class); * @date: 2021年3月9日
*/
private ISIPCommander cmder; @Component
public class ByeRequestProcessor extends SIPRequestProcessorParent implements InitializingBean, ISIPRequestProcessor {
private IRedisCatchStorage redisCatchStorage;
private Logger logger = LoggerFactory.getLogger(ByeRequestProcessor.class);
private IVideoManagerStorager storager;
@Autowired
private ZLMRTPServerFactory zlmrtpServerFactory; private ISIPCommander cmder;
private IMediaServerService mediaServerService; @Autowired
private IRedisCatchStorage redisCatchStorage;
/**
* 处理BYE请求 @Autowired
* @param evt private IVideoManagerStorager storager;
*/
@Override @Autowired
public void process(RequestEvent evt) { private ZLMRTPServerFactory zlmrtpServerFactory;
try {
responseAck(evt); @Autowired
Dialog dialog = evt.getDialog(); private IMediaServerService mediaServerService;
if (dialog == null) return;
if (dialog.getState().equals(DialogState.TERMINATED)) { private String method = "BYE";
String platformGbId = ((SipURI) ((HeaderAddress) evt.getRequest().getHeader(FromHeader.NAME)).getAddress().getURI()).getUser();
String channelId = ((SipURI) ((HeaderAddress) evt.getRequest().getHeader(ToHeader.NAME)).getAddress().getURI()).getUser(); @Autowired
SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(platformGbId, channelId); private SIPProcessorObserver sipProcessorObserver;
logger.info("收到bye, [{}/{}]", platformGbId, channelId);
if (sendRtpItem != null){ @Override
String streamId = sendRtpItem.getStreamId(); public void afterPropertiesSet() throws Exception {
Map<String, Object> param = new HashMap<>(); // 添加消息处理的订阅
param.put("vhost","__defaultVhost__"); sipProcessorObserver.addRequestProcessor(method, this);
param.put("app",sendRtpItem.getApp()); }
param.put("stream",streamId);
param.put("ssrc",sendRtpItem.getSsrc()); /**
logger.info("停止向上级推流:" + streamId); * 处理BYE请求
MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId()); * @param evt
zlmrtpServerFactory.stopSendRtpStream(mediaInfo, param); */
redisCatchStorage.deleteSendRTPServer(platformGbId, channelId); @Override
if (zlmrtpServerFactory.totalReaderCount(mediaInfo, sendRtpItem.getApp(), streamId) == 0) { public void process(RequestEvent evt) {
logger.info(streamId + "无其它观看者,通知设备停止推流"); try {
cmder.streamByeCmd(sendRtpItem.getDeviceId(), channelId); responseAck(evt, Response.OK);
} Dialog dialog = evt.getDialog();
} if (dialog == null) return;
// 可能是设备主动停止 if (dialog.getState().equals(DialogState.TERMINATED)) {
Device device = storager.queryVideoDeviceByChannelId(platformGbId); String platformGbId = ((SipURI) ((HeaderAddress) evt.getRequest().getHeader(FromHeader.NAME)).getAddress().getURI()).getUser();
if (device != null) { String channelId = ((SipURI) ((HeaderAddress) evt.getRequest().getHeader(ToHeader.NAME)).getAddress().getURI()).getUser();
StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(device.getDeviceId(), channelId); SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(platformGbId, channelId);
if (streamInfo != null) { logger.info("收到bye, [{}/{}]", platformGbId, channelId);
redisCatchStorage.stopPlay(streamInfo); if (sendRtpItem != null){
} String streamId = sendRtpItem.getStreamId();
storager.stopPlay(device.getDeviceId(), channelId); Map<String, Object> param = new HashMap<>();
mediaServerService.closeRTPServer(device, channelId); param.put("vhost","__defaultVhost__");
} param.put("app",sendRtpItem.getApp());
} param.put("stream",streamId);
} catch (SipException e) { param.put("ssrc",sendRtpItem.getSsrc());
e.printStackTrace(); logger.info("停止向上级推流:" + streamId);
} catch (InvalidArgumentException e) { MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId());
e.printStackTrace(); zlmrtpServerFactory.stopSendRtpStream(mediaInfo, param);
} catch (ParseException e) { redisCatchStorage.deleteSendRTPServer(platformGbId, channelId);
e.printStackTrace(); if (zlmrtpServerFactory.totalReaderCount(mediaInfo, sendRtpItem.getApp(), streamId) == 0) {
} logger.info(streamId + "无其它观看者,通知设备停止推流");
} cmder.streamByeCmd(sendRtpItem.getDeviceId(), channelId);
}
/*** }
* 回复200 OK // 可能是设备主动停止
* @param evt Device device = storager.queryVideoDeviceByChannelId(platformGbId);
* @throws SipException if (device != null) {
* @throws InvalidArgumentException StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(device.getDeviceId(), channelId);
* @throws ParseException if (streamInfo != null) {
*/ redisCatchStorage.stopPlay(streamInfo);
private void responseAck(RequestEvent evt) throws SipException, InvalidArgumentException, ParseException { }
Response response = getMessageFactory().createResponse(Response.OK, evt.getRequest()); storager.stopPlay(device.getDeviceId(), channelId);
ServerTransaction serverTransaction = getServerTransaction(evt); mediaServerService.closeRTPServer(device, channelId);
serverTransaction.sendResponse(response); }
if (serverTransaction.getDialog() != null) serverTransaction.getDialog().delete(); }
} } catch (SipException e) {
e.printStackTrace();
public IRedisCatchStorage getRedisCatchStorage() { } catch (InvalidArgumentException e) {
return redisCatchStorage; e.printStackTrace();
} } catch (ParseException e) {
e.printStackTrace();
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;
}
}

View File

@ -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消息实现此消息一般为级联消息上级给下级发送请求取消指令
}
}

View File

@ -1,478 +1,388 @@
package com.genersoft.iot.vmp.gb28181.transmit.request.impl; package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl;
import javax.sdp.*; import com.genersoft.iot.vmp.gb28181.bean.*;
import javax.sip.*; import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver;
import javax.sip.address.Address; import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
import javax.sip.address.SipURI; import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform;
import javax.sip.header.*; import com.genersoft.iot.vmp.gb28181.transmit.event.request.ISIPRequestProcessor;
import javax.sip.message.Request; import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
import javax.sip.message.Response; import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
import com.genersoft.iot.vmp.gb28181.bean.*; import com.genersoft.iot.vmp.service.IMediaServerService;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; import com.genersoft.iot.vmp.service.IPlayService;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform; import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import com.genersoft.iot.vmp.gb28181.transmit.request.SIPRequestAbstractProcessor; import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory; import com.genersoft.iot.vmp.vmanager.gb28181.play.bean.PlayResult;
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; import gov.nist.javax.sip.address.AddressImpl;
import com.genersoft.iot.vmp.service.IMediaServerService; import gov.nist.javax.sip.address.SipUri;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage; import org.slf4j.Logger;
import com.genersoft.iot.vmp.storager.IVideoManagerStorager; import org.slf4j.LoggerFactory;
import com.genersoft.iot.vmp.vmanager.gb28181.play.bean.PlayResult; import org.springframework.beans.factory.InitializingBean;
import com.genersoft.iot.vmp.service.IPlayService; import org.springframework.beans.factory.annotation.Autowired;
import gov.nist.javax.sip.address.AddressImpl; import org.springframework.stereotype.Component;
import gov.nist.javax.sip.address.SipUri;
import org.slf4j.Logger; import javax.sdp.*;
import org.slf4j.LoggerFactory; import javax.sip.InvalidArgumentException;
import javax.sip.RequestEvent;
import java.text.ParseException; import javax.sip.ServerTransaction;
import java.util.Vector; import javax.sip.SipException;
import javax.sip.address.SipURI;
/** import javax.sip.header.FromHeader;
* @Description:处理INVITE请求 import javax.sip.message.Request;
* @author: panll import javax.sip.message.Response;
* @date: 2021年1月14日 import java.text.ParseException;
*/ import java.util.Vector;
@SuppressWarnings("rawtypes")
public class InviteRequestProcessor extends SIPRequestAbstractProcessor { /**
* @description:处理INVITE请求
private final static Logger logger = LoggerFactory.getLogger(InviteRequestProcessor.class); * @author: panll
* @date: 2021年1月14日
private SIPCommanderFroPlatform cmderFroPlatform; */
@SuppressWarnings("rawtypes")
private IVideoManagerStorager storager; @Component
public class InviteRequestProcessor extends SIPRequestProcessorParent implements InitializingBean, ISIPRequestProcessor {
private IRedisCatchStorage redisCatchStorage;
private final static Logger logger = LoggerFactory.getLogger(InviteRequestProcessor.class);
private SIPCommander cmder;
private String method = "INVITE";
private IPlayService playService;
@Autowired
private ZLMRTPServerFactory zlmrtpServerFactory; private SIPCommanderFroPlatform cmderFroPlatform;
private IMediaServerService mediaServerService; @Autowired
private IVideoManagerStorager storager;
public ZLMRTPServerFactory getZlmrtpServerFactory() {
return zlmrtpServerFactory; @Autowired
} private IRedisCatchStorage redisCatchStorage;
public void setZlmrtpServerFactory(ZLMRTPServerFactory zlmrtpServerFactory) { @Autowired
this.zlmrtpServerFactory = zlmrtpServerFactory; private SIPCommander cmder;
}
@Autowired
/** private IPlayService playService;
* 处理invite请求
* @Autowired
* @param evt private ZLMRTPServerFactory zlmrtpServerFactory;
* 请求消息
*/ @Autowired
@Override private IMediaServerService mediaServerService;
public void process(RequestEvent evt) {
// Invite Request消息实现此消息一般为级联消息上级给下级发送请求视频指令 @Autowired
try { private SIPProcessorObserver sipProcessorObserver;
Request request = evt.getRequest();
SipURI sipURI = (SipURI) request.getRequestURI(); @Override
String channelId = sipURI.getUser(); public void afterPropertiesSet() throws Exception {
String requesterId = null; // 添加消息处理的订阅
sipProcessorObserver.addRequestProcessor(method, this);
FromHeader fromHeader = (FromHeader)request.getHeader(FromHeader.NAME); }
AddressImpl address = (AddressImpl) fromHeader.getAddress();
SipUri uri = (SipUri) address.getURI(); /**
requesterId = uri.getUser(); * 处理invite请求
*
if (requesterId == null || channelId == null) { * @param evt
logger.info("无法从FromHeader的Address中获取到平台id返回400"); * 请求消息
responseAck(evt, Response.BAD_REQUEST); // 参数不全 发400请求错误 */
return; @Override
} public void process(RequestEvent evt) {
// Invite Request消息实现此消息一般为级联消息上级给下级发送请求视频指令
// 查询请求方是否上级平台 try {
ParentPlatform platform = storager.queryParentPlatByServerGBId(requesterId); Request request = evt.getRequest();
if (platform != null) { SipURI sipURI = (SipURI) request.getRequestURI();
// 查询平台下是否有该通道 String channelId = sipURI.getUser();
DeviceChannel channel = storager.queryChannelInParentPlatform(requesterId, channelId); String requesterId = null;
GbStream gbStream = storager.queryStreamInParentPlatform(requesterId, channelId);
MediaServerItem mediaServerItem = null; FromHeader fromHeader = (FromHeader)request.getHeader(FromHeader.NAME);
// 不是通道可能是直播流 AddressImpl address = (AddressImpl) fromHeader.getAddress();
if (channel != null && gbStream == null ) { SipUri uri = (SipUri) address.getURI();
if (channel.getStatus() == 0) { requesterId = uri.getUser();
logger.info("通道离线返回400");
responseAck(evt, Response.BAD_REQUEST, "channel [" + channel.getChannelId() + "] offline"); if (requesterId == null || channelId == null) {
return; logger.info("无法从FromHeader的Address中获取到平台id返回400");
} responseAck(evt, Response.BAD_REQUEST); // 参数不全 发400请求错误
responseAck(evt, Response.CALL_IS_BEING_FORWARDED); // 通道存在发181呼叫转接中 return;
}else if(channel == null && gbStream != null){ }
String mediaServerId = gbStream.getMediaServerId();
mediaServerItem = mediaServerService.getOne(mediaServerId); // 查询请求方是否上级平台
if (mediaServerItem == null) { ParentPlatform platform = storager.queryParentPlatByServerGBId(requesterId);
logger.info("[ app={}, stream={} ]找不到zlm {}返回410",gbStream.getApp(), gbStream.getStream(), mediaServerId); if (platform != null) {
responseAck(evt, Response.GONE, "media server not found"); // 查询平台下是否有该通道
return; DeviceChannel channel = storager.queryChannelInParentPlatform(requesterId, channelId);
} GbStream gbStream = storager.queryStreamInParentPlatform(requesterId, channelId);
Boolean streamReady = zlmrtpServerFactory.isStreamReady(mediaServerItem, gbStream.getApp(), gbStream.getStream()); MediaServerItem mediaServerItem = null;
if (!streamReady ) { // 不是通道可能是直播流
logger.info("[ app={}, stream={} ]通道离线返回400",gbStream.getApp(), gbStream.getStream()); if (channel != null && gbStream == null ) {
responseAck(evt, Response.BAD_REQUEST, "channel [" + gbStream.getGbId() + "] offline"); if (channel.getStatus() == 0) {
return; logger.info("通道离线返回400");
} responseAck(evt, Response.BAD_REQUEST, "channel [" + channel.getChannelId() + "] offline");
responseAck(evt, Response.CALL_IS_BEING_FORWARDED); // 通道存在发181呼叫转接中 return;
}else { }
logger.info("通道不存在返回404"); responseAck(evt, Response.CALL_IS_BEING_FORWARDED); // 通道存在发181呼叫转接中
responseAck(evt, Response.NOT_FOUND); // 通道不存在发404资源不存在 }else if(channel == null && gbStream != null){
return; String mediaServerId = gbStream.getMediaServerId();
} mediaServerItem = mediaServerService.getOne(mediaServerId);
// 解析sdp消息, 使用jainsip 自带的sdp解析方式 if (mediaServerItem == null) {
String contentString = new String(request.getRawContent()); logger.info("[ app={}, stream={} ]找不到zlm {}返回410",gbStream.getApp(), gbStream.getStream(), mediaServerId);
responseAck(evt, Response.GONE, "media server not found");
// jainSip不支持y=字段 移除移除以解析 return;
int ssrcIndex = contentString.indexOf("y="); }
//ssrc规定长度为10字节不取余下长度以避免后续还有f=字段 Boolean streamReady = zlmrtpServerFactory.isStreamReady(mediaServerItem, gbStream.getApp(), gbStream.getStream());
String ssrc = contentString.substring(ssrcIndex + 2, ssrcIndex + 12); if (!streamReady ) {
String substring = contentString.substring(0, contentString.indexOf("y=")); logger.info("[ app={}, stream={} ]通道离线返回400",gbStream.getApp(), gbStream.getStream());
SessionDescription sdp = SdpFactory.getInstance().createSessionDescription(substring); responseAck(evt, Response.BAD_REQUEST, "channel [" + gbStream.getGbId() + "] offline");
return;
// 获取支持的格式 }
Vector mediaDescriptions = sdp.getMediaDescriptions(true); responseAck(evt, Response.CALL_IS_BEING_FORWARDED); // 通道存在发181呼叫转接中
// 查看是否支持PS 负载96 }else {
//String ip = null; logger.info("通道不存在返回404");
int port = -1; responseAck(evt, Response.NOT_FOUND); // 通道不存在发404资源不存在
//boolean recvonly = false; return;
boolean mediaTransmissionTCP = false; }
Boolean tcpActive = null; // 解析sdp消息, 使用jainsip 自带的sdp解析方式
for (Object description : mediaDescriptions) { String contentString = new String(request.getRawContent());
MediaDescription mediaDescription = (MediaDescription) description;
Media media = mediaDescription.getMedia(); // jainSip不支持y=字段 移除移除以解析
int ssrcIndex = contentString.indexOf("y=");
Vector mediaFormats = media.getMediaFormats(false); //ssrc规定长度为10字节不取余下长度以避免后续还有f=字段
if (mediaFormats.contains("96")) { String ssrc = contentString.substring(ssrcIndex + 2, ssrcIndex + 12);
port = media.getMediaPort(); String substring = contentString.substring(0, contentString.indexOf("y="));
//String mediaType = media.getMediaType(); SessionDescription sdp = SdpFactory.getInstance().createSessionDescription(substring);
String protocol = media.getProtocol();
// 获取支持的格式
// 区分TCP发流还是udp 当前默认udp Vector mediaDescriptions = sdp.getMediaDescriptions(true);
if ("TCP/RTP/AVP".equals(protocol)) { // 查看是否支持PS 负载96
String setup = mediaDescription.getAttribute("setup"); //String ip = null;
if (setup != null) { int port = -1;
mediaTransmissionTCP = true; //boolean recvonly = false;
if ("active".equals(setup)) { boolean mediaTransmissionTCP = false;
tcpActive = true; Boolean tcpActive = null;
} else if ("passive".equals(setup)) { for (Object description : mediaDescriptions) {
tcpActive = false; MediaDescription mediaDescription = (MediaDescription) description;
} Media media = mediaDescription.getMedia();
}
} Vector mediaFormats = media.getMediaFormats(false);
break; if (mediaFormats.contains("96")) {
} port = media.getMediaPort();
} //String mediaType = media.getMediaType();
if (port == -1) { String protocol = media.getProtocol();
logger.info("不支持的媒体格式返回415");
// 回复不支持的格式 // 区分TCP发流还是udp 当前默认udp
responseAck(evt, Response.UNSUPPORTED_MEDIA_TYPE); // 不支持的格式发415 if ("TCP/RTP/AVP".equals(protocol)) {
return; String setup = mediaDescription.getAttribute("setup");
} if (setup != null) {
String username = sdp.getOrigin().getUsername(); mediaTransmissionTCP = true;
String addressStr = sdp.getOrigin().getAddress(); if ("active".equals(setup)) {
//String sessionName = sdp.getSessionName().getValue(); tcpActive = true;
logger.info("[上级点播]用户:{} 地址:{}:{} ssrc{}", username, addressStr, port, ssrc); } else if ("passive".equals(setup)) {
Device device = null; tcpActive = false;
// 通过 channel gbStream 是否为null 值判断来源是直播流合适国标 }
if (channel != null) { }
device = storager.queryVideoDeviceByPlatformIdAndChannelId(requesterId, channelId); }
if (device == null) { break;
logger.warn("点播平台{}的通道{}时未找到设备信息", requesterId, channel); }
responseAck(evt, Response.SERVER_INTERNAL_ERROR); }
return; if (port == -1) {
} logger.info("不支持的媒体格式返回415");
mediaServerItem = playService.getNewMediaServerItem(device); // 回复不支持的格式
if (mediaServerItem == null) { responseAck(evt, Response.UNSUPPORTED_MEDIA_TYPE); // 不支持的格式发415
logger.warn("未找到可用的zlm"); return;
responseAck(evt, Response.BUSY_HERE); }
return; String username = sdp.getOrigin().getUsername();
} String addressStr = sdp.getOrigin().getAddress();
SendRtpItem sendRtpItem = zlmrtpServerFactory.createSendRtpItem(mediaServerItem, addressStr, port, ssrc, requesterId, //String sessionName = sdp.getSessionName().getValue();
device.getDeviceId(), channelId, logger.info("[上级点播]用户:{} 地址:{}:{} ssrc{}", username, addressStr, port, ssrc);
mediaTransmissionTCP); Device device = null;
if (tcpActive != null) { // 通过 channel gbStream 是否为null 值判断来源是直播流合适国标
sendRtpItem.setTcpActive(tcpActive); if (channel != null) {
} device = storager.queryVideoDeviceByPlatformIdAndChannelId(requesterId, channelId);
if (sendRtpItem == null) { if (device == null) {
logger.warn("服务器端口资源不足"); logger.warn("点播平台{}的通道{}时未找到设备信息", requesterId, channel);
responseAck(evt, Response.BUSY_HERE); responseAck(evt, Response.SERVER_INTERNAL_ERROR);
return; return;
} }
mediaServerItem = playService.getNewMediaServerItem(device);
// 写入redis 超时时回复 if (mediaServerItem == null) {
redisCatchStorage.updateSendRTPSever(sendRtpItem); logger.warn("未找到可用的zlm");
// 通知下级推流 responseAck(evt, Response.BUSY_HERE);
PlayResult playResult = playService.play(mediaServerItem,device.getDeviceId(), channelId, (mediaServerItemInUSe, responseJSON)->{ return;
// 收到推流 回复200OK, 等待ack }
// if (sendRtpItem == null) return; SendRtpItem sendRtpItem = zlmrtpServerFactory.createSendRtpItem(mediaServerItem, addressStr, port, ssrc, requesterId,
sendRtpItem.setStatus(1); device.getDeviceId(), channelId,
redisCatchStorage.updateSendRTPSever(sendRtpItem); mediaTransmissionTCP);
// TODO 添加对tcp的支持 if (tcpActive != null) {
sendRtpItem.setTcpActive(tcpActive);
StringBuffer content = new StringBuffer(200); }
content.append("v=0\r\n"); if (sendRtpItem == null) {
content.append("o="+ channelId +" 0 0 IN IP4 "+mediaServerItemInUSe.getSdpIp()+"\r\n"); logger.warn("服务器端口资源不足");
content.append("s=Play\r\n"); responseAck(evt, Response.BUSY_HERE);
content.append("c=IN IP4 "+mediaServerItemInUSe.getSdpIp()+"\r\n"); return;
content.append("t=0 0\r\n"); }
content.append("m=video "+ sendRtpItem.getLocalPort()+" RTP/AVP 96\r\n");
content.append("a=sendonly\r\n"); // 写入redis 超时时回复
content.append("a=rtpmap:96 PS/90000\r\n"); redisCatchStorage.updateSendRTPSever(sendRtpItem);
content.append("y="+ ssrc + "\r\n"); // 通知下级推流
content.append("f=\r\n"); PlayResult playResult = playService.play(mediaServerItem,device.getDeviceId(), channelId, (mediaServerItemInUSe, responseJSON)->{
// 收到推流 回复200OK, 等待ack
try { // if (sendRtpItem == null) return;
responseAck(evt, content.toString()); sendRtpItem.setStatus(1);
} catch (SipException e) { redisCatchStorage.updateSendRTPSever(sendRtpItem);
e.printStackTrace(); // TODO 添加对tcp的支持
} catch (InvalidArgumentException e) {
e.printStackTrace(); StringBuffer content = new StringBuffer(200);
} catch (ParseException e) { content.append("v=0\r\n");
e.printStackTrace(); content.append("o="+ channelId +" 0 0 IN IP4 "+mediaServerItemInUSe.getSdpIp()+"\r\n");
} content.append("s=Play\r\n");
} ,((event) -> { content.append("c=IN IP4 "+mediaServerItemInUSe.getSdpIp()+"\r\n");
// 未知错误直接转发设备点播的错误 content.append("t=0 0\r\n");
Response response = null; content.append("m=video "+ sendRtpItem.getLocalPort()+" RTP/AVP 96\r\n");
try { content.append("a=sendonly\r\n");
response = getMessageFactory().createResponse(event.statusCode, evt.getRequest()); content.append("a=rtpmap:96 PS/90000\r\n");
ServerTransaction serverTransaction = getServerTransaction(evt); content.append("y="+ ssrc + "\r\n");
serverTransaction.sendResponse(response); content.append("f=\r\n");
if (serverTransaction.getDialog() != null) serverTransaction.getDialog().delete();
} catch (ParseException | SipException | InvalidArgumentException e) { try {
e.printStackTrace(); responseAck(evt, content.toString());
} } catch (SipException e) {
})); e.printStackTrace();
if (logger.isDebugEnabled()) { } catch (InvalidArgumentException e) {
logger.debug(playResult.getResult().toString()); e.printStackTrace();
} } catch (ParseException e) {
e.printStackTrace();
}else if (gbStream != null) { }
SendRtpItem sendRtpItem = zlmrtpServerFactory.createSendRtpItem(mediaServerItem, addressStr, port, ssrc, requesterId, } ,((event) -> {
gbStream.getApp(), gbStream.getStream(), channelId, // 未知错误直接转发设备点播的错误
mediaTransmissionTCP); Response response = null;
try {
if (tcpActive != null) { response = getMessageFactory().createResponse(event.statusCode, evt.getRequest());
sendRtpItem.setTcpActive(tcpActive); ServerTransaction serverTransaction = getServerTransaction(evt);
} serverTransaction.sendResponse(response);
if (sendRtpItem == null) { if (serverTransaction.getDialog() != null) serverTransaction.getDialog().delete();
logger.warn("服务器端口资源不足"); } catch (ParseException | SipException | InvalidArgumentException e) {
responseAck(evt, Response.BUSY_HERE); e.printStackTrace();
return; }
} }));
if (logger.isDebugEnabled()) {
// 写入redis 超时时回复 logger.debug(playResult.getResult().toString());
redisCatchStorage.updateSendRTPSever(sendRtpItem); }
sendRtpItem.setStatus(1); }else if (gbStream != null) {
redisCatchStorage.updateSendRTPSever(sendRtpItem); SendRtpItem sendRtpItem = zlmrtpServerFactory.createSendRtpItem(mediaServerItem, addressStr, port, ssrc, requesterId,
// TODO 添加对tcp的支持 gbStream.getApp(), gbStream.getStream(), channelId,
StringBuffer content = new StringBuffer(200); mediaTransmissionTCP);
content.append("v=0\r\n");
content.append("o="+ channelId +" 0 0 IN IP4 "+mediaServerItem.getSdpIp()+"\r\n"); if (tcpActive != null) {
content.append("s=Play\r\n"); sendRtpItem.setTcpActive(tcpActive);
content.append("c=IN IP4 "+mediaServerItem.getSdpIp()+"\r\n"); }
content.append("t=0 0\r\n"); if (sendRtpItem == null) {
content.append("m=video "+ sendRtpItem.getLocalPort()+" RTP/AVP 96\r\n"); logger.warn("服务器端口资源不足");
content.append("a=sendonly\r\n"); responseAck(evt, Response.BUSY_HERE);
content.append("a=rtpmap:96 PS/90000\r\n"); return;
content.append("y="+ ssrc + "\r\n"); }
content.append("f=\r\n");
// 写入redis 超时时回复
try { redisCatchStorage.updateSendRTPSever(sendRtpItem);
responseAck(evt, content.toString());
} catch (SipException e) { sendRtpItem.setStatus(1);
e.printStackTrace(); redisCatchStorage.updateSendRTPSever(sendRtpItem);
} catch (InvalidArgumentException e) { // TODO 添加对tcp的支持
e.printStackTrace(); StringBuffer content = new StringBuffer(200);
} catch (ParseException e) { content.append("v=0\r\n");
e.printStackTrace(); 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");
} else { content.append("m=video "+ sendRtpItem.getLocalPort()+" RTP/AVP 96\r\n");
// 非上级平台请求查询是否设备请求通常为接收语音广播的设备 content.append("a=sendonly\r\n");
Device device = storager.queryVideoDevice(requesterId); content.append("a=rtpmap:96 PS/90000\r\n");
if (device != null) { content.append("y="+ ssrc + "\r\n");
logger.info("收到设备" + requesterId + "的语音广播Invite请求"); content.append("f=\r\n");
responseAck(evt, Response.TRYING);
try {
String contentString = new String(request.getRawContent()); responseAck(evt, content.toString());
// jainSip不支持y=字段 移除移除以解析 } catch (SipException e) {
String substring = contentString; e.printStackTrace();
String ssrc = "0000000404"; } catch (InvalidArgumentException e) {
int ssrcIndex = contentString.indexOf("y="); e.printStackTrace();
if (ssrcIndex > 0) { } catch (ParseException e) {
substring = contentString.substring(0, ssrcIndex); e.printStackTrace();
ssrc = contentString.substring(ssrcIndex + 2, ssrcIndex + 12); }
} }
ssrcIndex = substring.indexOf("f=");
if (ssrcIndex > 0) { } else {
substring = contentString.substring(0, ssrcIndex); // 非上级平台请求查询是否设备请求通常为接收语音广播的设备
} Device device = storager.queryVideoDevice(requesterId);
SessionDescription sdp = SdpFactory.getInstance().createSessionDescription(substring); if (device != null) {
logger.info("收到设备" + requesterId + "的语音广播Invite请求");
// 获取支持的格式 responseAck(evt, Response.TRYING);
Vector mediaDescriptions = sdp.getMediaDescriptions(true);
// 查看是否支持PS 负载96 String contentString = new String(request.getRawContent());
int port = -1; // jainSip不支持y=字段 移除移除以解析
//boolean recvonly = false; String substring = contentString;
boolean mediaTransmissionTCP = false; String ssrc = "0000000404";
Boolean tcpActive = null; int ssrcIndex = contentString.indexOf("y=");
for (int i = 0; i < mediaDescriptions.size(); i++) { if (ssrcIndex > 0) {
MediaDescription mediaDescription = (MediaDescription)mediaDescriptions.get(i); substring = contentString.substring(0, ssrcIndex);
Media media = mediaDescription.getMedia(); ssrc = contentString.substring(ssrcIndex + 2, ssrcIndex + 12);
}
Vector mediaFormats = media.getMediaFormats(false); ssrcIndex = substring.indexOf("f=");
if (mediaFormats.contains("8")) { if (ssrcIndex > 0) {
port = media.getMediaPort(); substring = contentString.substring(0, ssrcIndex);
String protocol = media.getProtocol(); }
// 区分TCP发流还是udp 当前默认udp SessionDescription sdp = SdpFactory.getInstance().createSessionDescription(substring);
if ("TCP/RTP/AVP".equals(protocol)) {
String setup = mediaDescription.getAttribute("setup"); // 获取支持的格式
if (setup != null) { Vector mediaDescriptions = sdp.getMediaDescriptions(true);
mediaTransmissionTCP = true; // 查看是否支持PS 负载96
if ("active".equals(setup)) { int port = -1;
tcpActive = true; //boolean recvonly = false;
} else if ("passive".equals(setup)) { boolean mediaTransmissionTCP = false;
tcpActive = false; Boolean tcpActive = null;
} for (int i = 0; i < mediaDescriptions.size(); i++) {
} MediaDescription mediaDescription = (MediaDescription)mediaDescriptions.get(i);
} Media media = mediaDescription.getMedia();
break;
} Vector mediaFormats = media.getMediaFormats(false);
} if (mediaFormats.contains("8")) {
if (port == -1) { port = media.getMediaPort();
logger.info("不支持的媒体格式返回415"); String protocol = media.getProtocol();
// 回复不支持的格式 // 区分TCP发流还是udp 当前默认udp
responseAck(evt, Response.UNSUPPORTED_MEDIA_TYPE); // 不支持的格式发415 if ("TCP/RTP/AVP".equals(protocol)) {
return; String setup = mediaDescription.getAttribute("setup");
} if (setup != null) {
String username = sdp.getOrigin().getUsername(); mediaTransmissionTCP = true;
String addressStr = sdp.getOrigin().getAddress(); if ("active".equals(setup)) {
logger.info("设备{}请求语音流,地址:{}:{}ssrc{}", username, addressStr, port, ssrc); tcpActive = true;
} else if ("passive".equals(setup)) {
} else { tcpActive = false;
logger.warn("来自无效设备/平台的请求"); }
responseAck(evt, Response.BAD_REQUEST); }
} }
} break;
}
} catch (SipException | InvalidArgumentException | ParseException e) { }
e.printStackTrace(); if (port == -1) {
logger.warn("sdp解析错误"); logger.info("不支持的媒体格式返回415");
e.printStackTrace(); // 回复不支持的格式
} catch (SdpParseException e) { responseAck(evt, Response.UNSUPPORTED_MEDIA_TYPE); // 不支持的格式发415
e.printStackTrace(); return;
} catch (SdpException e) { }
e.printStackTrace(); 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);
* 100 trying }
* 200 OK }
* 400
* 404 } catch (SipException | InvalidArgumentException | ParseException e) {
* @param evt e.printStackTrace();
* @throws SipException logger.warn("sdp解析错误");
* @throws InvalidArgumentException e.printStackTrace();
* @throws ParseException } catch (SdpParseException e) {
*/ e.printStackTrace();
private void responseAck(RequestEvent evt, int statusCode) throws SipException, InvalidArgumentException, ParseException { } catch (SdpException e) {
Response response = getMessageFactory().createResponse(statusCode, evt.getRequest()); e.printStackTrace();
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;
}
}

View File

@ -1,67 +1,78 @@
package com.genersoft.iot.vmp.gb28181.transmit.request.impl; package com.genersoft.iot.vmp.gb28181.transmit.event.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;
import com.genersoft.iot.vmp.common.VideoManagerConstants; import com.genersoft.iot.vmp.common.VideoManagerConstants;
import com.genersoft.iot.vmp.conf.UserSetup; import com.genersoft.iot.vmp.conf.UserSetup;
import com.genersoft.iot.vmp.gb28181.bean.BaiduPoint; import com.genersoft.iot.vmp.gb28181.bean.*;
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.event.DeviceOffLineDetector; import com.genersoft.iot.vmp.gb28181.event.DeviceOffLineDetector;
import com.genersoft.iot.vmp.gb28181.event.EventPublisher; 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.callback.DeferredResultHolder;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; 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.NumericUtil;
import com.genersoft.iot.vmp.gb28181.utils.SipUtils;
import com.genersoft.iot.vmp.gb28181.utils.XmlUtil; import com.genersoft.iot.vmp.gb28181.utils.XmlUtil;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage; import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import com.genersoft.iot.vmp.storager.IVideoManagerStorager; import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
import com.genersoft.iot.vmp.utils.GpsUtil; import com.genersoft.iot.vmp.utils.GpsUtil;
import com.genersoft.iot.vmp.utils.SpringBeanFactory;
import com.genersoft.iot.vmp.utils.redis.RedisUtil; import com.genersoft.iot.vmp.utils.redis.RedisUtil;
import org.dom4j.Document;
import org.dom4j.DocumentException; import org.dom4j.DocumentException;
import org.dom4j.Element; import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; 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 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 * @author: lawrencehj
* @date: 2021年1月27日 * @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; private IVideoManagerStorager storager;
@Autowired
private IRedisCatchStorage redisCatchStorage; private IRedisCatchStorage redisCatchStorage;
@Autowired
private EventPublisher publisher; private EventPublisher publisher;
@Autowired
private DeviceOffLineDetector offLineDetector; private DeviceOffLineDetector offLineDetector;
private static final String NOTIFY_CATALOG = "Catalog"; private static final String NOTIFY_CATALOG = "Catalog";
private static final String NOTIFY_ALARM = "Alarm"; private static final String NOTIFY_ALARM = "Alarm";
private static final String NOTIFY_MOBILE_POSITION = "MobilePosition"; 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 @Override
public void process(RequestEvent evt) { public void process(RequestEvent evt) {
@ -80,7 +91,7 @@ public class NotifyRequestProcessor extends SIPRequestAbstractProcessor {
processNotifyMobilePosition(evt); processNotifyMobilePosition(evt);
} else { } else {
logger.info("接收到消息:" + cmd); logger.info("接收到消息:" + cmd);
response200Ok(evt); responseAck(evt, Response.OK);
} }
} catch (DocumentException | SipException | InvalidArgumentException | ParseException e) { } catch (DocumentException | SipException | InvalidArgumentException | ParseException e) {
e.printStackTrace(); e.printStackTrace();
@ -135,7 +146,7 @@ public class NotifyRequestProcessor extends SIPRequestAbstractProcessor {
storager.clearMobilePositionsByDeviceId(deviceId); storager.clearMobilePositionsByDeviceId(deviceId);
} }
storager.insertMobilePosition(mobilePosition); storager.insertMobilePosition(mobilePosition);
response200Ok(evt); responseAck(evt, Response.OK);
} catch (DocumentException | SipException | InvalidArgumentException | ParseException e) { } catch (DocumentException | SipException | InvalidArgumentException | ParseException e) {
e.printStackTrace(); e.printStackTrace();
} }
@ -199,7 +210,7 @@ public class NotifyRequestProcessor extends SIPRequestAbstractProcessor {
// TODO: 需要实现存储报警信息报警分类 // TODO: 需要实现存储报警信息报警分类
// 回复200 OK // 回复200 OK
response200Ok(evt); responseAck(evt, Response.OK);
if (offLineDetector.isOnline(deviceId)) { if (offLineDetector.isOnline(deviceId)) {
publisher.deviceAlarmEventPublish(deviceAlarm); publisher.deviceAlarmEventPublish(deviceAlarm);
} }
@ -215,10 +226,16 @@ public class NotifyRequestProcessor extends SIPRequestAbstractProcessor {
*/ */
private void processNotifyCatalogList(RequestEvent evt) { private void processNotifyCatalogList(RequestEvent evt) {
try { try {
FromHeader fromHeader = (FromHeader) evt.getRequest().getHeader(FromHeader.NAME);
String deviceId = SipUtils.getUserIdFromFromHeader(fromHeader);
Element rootElement = getRootElement(evt); Element rootElement = getRootElement(evt);
Element deviceIdElement = rootElement.element("DeviceID"); Element deviceIdElement = rootElement.element("DeviceID");
String deviceId = deviceIdElement.getText(); String channelId = deviceIdElement.getText();
Device device = storager.queryVideoDevice(deviceId); Device device = storager.queryVideoDevice(deviceId);
if (device == null) {
return;
}
if (device != null ) { if (device != null ) {
rootElement = getRootElement(evt, device.getCharset()); rootElement = getRootElement(evt, device.getCharset());
} }
@ -228,9 +245,7 @@ public class NotifyRequestProcessor extends SIPRequestAbstractProcessor {
} }
Iterator<Element> deviceListIterator = deviceListElement.elementIterator(); Iterator<Element> deviceListIterator = deviceListElement.elementIterator();
if (deviceListIterator != null) { if (deviceListIterator != null) {
if (device == null) {
return;
}
// 遍历DeviceList // 遍历DeviceList
while (deviceListIterator.hasNext()) { while (deviceListIterator.hasNext()) {
Element itemDevice = deviceListIterator.next(); Element itemDevice = deviceListIterator.next();
@ -238,87 +253,52 @@ public class NotifyRequestProcessor extends SIPRequestAbstractProcessor {
if (channelDeviceElement == null) { if (channelDeviceElement == null) {
continue; continue;
} }
String channelDeviceId = channelDeviceElement.getTextTrim(); Element eventElement = itemDevice.element("Event");
Element channdelNameElement = itemDevice.element("Name"); switch (eventElement.getText().toUpperCase()) {
String channelName = channdelNameElement != null ? channdelNameElement.getTextTrim().toString() : ""; case "ON" : // 上线
Element statusElement = itemDevice.element("Status"); logger.info("收到来自设备【{}】的通道上线【{}】通知", device.getDeviceId(), channelId);
String status = statusElement != null ? statusElement.getTextTrim().toString() : "ON"; storager.deviceChannelOnline(deviceId, channelId);
DeviceChannel deviceChannel = new DeviceChannel(); // 回复200 OK
deviceChannel.setName(channelName); responseAck(evt, Response.OK);
deviceChannel.setChannelId(channelDeviceId); break;
// ONLINE OFFLINE HIKVISION DS-7716N-E4 NVR的兼容性处理 case "OFF" : // 离线
if (status.equals("ON") || status.equals("On") || status.equals("ONLINE")) { logger.info("收到来自设备【{}】的通道离线【{}】通知", device.getDeviceId(), channelId);
deviceChannel.setStatus(1); storager.deviceChannelOffline(deviceId, channelId);
} // 回复200 OK
if (status.equals("OFF") || status.equals("Off") || status.equals("OFFLINE")) { responseAck(evt, Response.OK);
deviceChannel.setStatus(0); 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(); // RequestMessage msg = new RequestMessage();
@ -326,8 +306,7 @@ public class NotifyRequestProcessor extends SIPRequestAbstractProcessor {
// msg.setType(DeferredResultHolder.CALLBACK_CMD_CATALOG); // msg.setType(DeferredResultHolder.CALLBACK_CMD_CATALOG);
// msg.setData(device); // msg.setData(device);
// deferredResultHolder.invokeResult(msg); // deferredResultHolder.invokeResult(msg);
// 回复200 OK
response200Ok(evt);
if (offLineDetector.isOnline(deviceId)) { if (offLineDetector.isOnline(deviceId)) {
publisher.onlineEventPublish(device, VideoManagerConstants.EVENT_ONLINE_MESSAGE); publisher.onlineEventPublish(device, VideoManagerConstants.EVENT_ONLINE_MESSAGE);
} }
@ -337,32 +316,91 @@ public class NotifyRequestProcessor extends SIPRequestAbstractProcessor {
} }
} }
/*** public DeviceChannel channelContentHander(Element itemDevice, String channelId){
* 回复200 OK Element channdelNameElement = itemDevice.element("Name");
* String channelName = channdelNameElement != null ? channdelNameElement.getTextTrim().toString() : "";
* @param evt Element statusElement = itemDevice.element("Status");
* @throws SipException String status = statusElement != null ? statusElement.getTextTrim().toString() : "ON";
* @throws InvalidArgumentException DeviceChannel deviceChannel = new DeviceChannel();
* @throws ParseException deviceChannel.setName(channelName);
*/ deviceChannel.setChannelId(channelId);
private void response200Ok(RequestEvent evt) throws SipException, InvalidArgumentException, ParseException { // ONLINE OFFLINE HIKVISION DS-7716N-E4 NVR的兼容性处理
Response response = getMessageFactory().createResponse(Response.OK, evt.getRequest()); if (status.equals("ON") || status.equals("On") || status.equals("ONLINE")) {
ServerTransaction serverTransaction = getServerTransaction(evt); deviceChannel.setStatus(1);
serverTransaction.sendResponse(response); }
if (serverTransaction.getDialog() != null) serverTransaction.getDialog().delete(); if (status.equals("OFF") || status.equals("Off") || status.equals("OFFLINE")) {
} deviceChannel.setStatus(0);
private Element getRootElement(RequestEvent evt) throws DocumentException { }
return getRootElement(evt, "gb2312");
} deviceChannel.setManufacture(XmlUtil.getText(itemDevice, "Manufacturer"));
private Element getRootElement(RequestEvent evt, String charset) throws DocumentException { deviceChannel.setModel(XmlUtil.getText(itemDevice, "Model"));
if (charset == null) charset = "gb2312"; deviceChannel.setOwner(XmlUtil.getText(itemDevice, "Owner"));
Request request = evt.getRequest(); deviceChannel.setCivilCode(XmlUtil.getText(itemDevice, "CivilCode"));
SAXReader reader = new SAXReader(); deviceChannel.setBlock(XmlUtil.getText(itemDevice, "Block"));
reader.setEncoding(charset); deviceChannel.setAddress(XmlUtil.getText(itemDevice, "Address"));
Document xml = reader.read(new ByteArrayInputStream(request.getRawContent())); if (XmlUtil.getText(itemDevice, "Parental") == null
return xml.getRootElement(); || 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) { public void setCmder(SIPCommander cmder) {
} }

View File

@ -1,201 +1,199 @@
package com.genersoft.iot.vmp.gb28181.transmit.request.impl; package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl;
import java.security.NoSuchAlgorithmException; import com.genersoft.iot.vmp.common.VideoManagerConstants;
import java.text.ParseException; import com.genersoft.iot.vmp.conf.SipConfig;
import java.util.Calendar; import com.genersoft.iot.vmp.gb28181.auth.DigestServerAuthenticationHelper;
import java.util.Locale; import com.genersoft.iot.vmp.gb28181.auth.RegisterLogicHandler;
import com.genersoft.iot.vmp.gb28181.bean.Device;
import javax.sip.InvalidArgumentException; import com.genersoft.iot.vmp.gb28181.bean.WvpSipDate;
import javax.sip.RequestEvent; import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
import javax.sip.ServerTransaction; import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver;
import javax.sip.SipException; import com.genersoft.iot.vmp.gb28181.transmit.event.request.ISIPRequestProcessor;
import javax.sip.header.AuthorizationHeader; import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
import javax.sip.header.ContactHeader; import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
import javax.sip.header.ExpiresHeader; import gov.nist.javax.sip.RequestEventExt;
import javax.sip.header.FromHeader; import gov.nist.javax.sip.address.AddressImpl;
import javax.sip.header.ViaHeader; import gov.nist.javax.sip.address.SipUri;
import javax.sip.message.Request; import gov.nist.javax.sip.header.Expires;
import javax.sip.message.Response; import gov.nist.javax.sip.header.SIPDateHeader;
import org.slf4j.Logger;
import com.genersoft.iot.vmp.gb28181.bean.WvpSipDate; import org.slf4j.LoggerFactory;
import gov.nist.javax.sip.RequestEventExt; import org.springframework.beans.factory.InitializingBean;
import gov.nist.javax.sip.header.SIPDateHeader; import org.springframework.beans.factory.annotation.Autowired;
import org.slf4j.Logger; import org.springframework.stereotype.Component;
import org.slf4j.LoggerFactory; import org.springframework.util.StringUtils;
import org.springframework.util.StringUtils;
import javax.sip.InvalidArgumentException;
import com.genersoft.iot.vmp.common.VideoManagerConstants; import javax.sip.RequestEvent;
import com.genersoft.iot.vmp.conf.SipConfig; import javax.sip.ServerTransaction;
import com.genersoft.iot.vmp.gb28181.auth.DigestServerAuthenticationHelper; import javax.sip.SipException;
import com.genersoft.iot.vmp.gb28181.auth.RegisterLogicHandler; import javax.sip.header.*;
import com.genersoft.iot.vmp.gb28181.bean.Device; import javax.sip.message.Request;
import com.genersoft.iot.vmp.gb28181.event.EventPublisher; import javax.sip.message.Response;
import com.genersoft.iot.vmp.gb28181.transmit.request.SIPRequestAbstractProcessor; import java.security.NoSuchAlgorithmException;
import com.genersoft.iot.vmp.storager.IVideoManagerStorager; import java.text.ParseException;
import java.util.Calendar;
import gov.nist.javax.sip.address.AddressImpl; import java.util.Locale;
import gov.nist.javax.sip.address.SipUri;
import gov.nist.javax.sip.header.Expires; /**
* @description:收到注册请求 处理
/** * @author: swwheihei
* @Description:收到注册请求 处理 * @date: 2020年5月3日 下午4:47:25
* @author: swwheihei */
* @date: 2020年5月3日 下午4:47:25 @Component
*/ public class RegisterRequestProcessor extends SIPRequestProcessorParent implements InitializingBean, ISIPRequestProcessor {
public class RegisterRequestProcessor extends SIPRequestAbstractProcessor {
private Logger logger = LoggerFactory.getLogger(RegisterRequestProcessor.class);
private Logger logger = LoggerFactory.getLogger(RegisterRequestProcessor.class);
public String method = "REGISTER";
private SipConfig sipConfig;
@Autowired
private RegisterLogicHandler handler; private SipConfig sipConfig;
private IVideoManagerStorager storager; @Autowired
private RegisterLogicHandler handler;
private EventPublisher publisher;
@Autowired
/** private IVideoManagerStorager storager;
* 收到注册请求 处理
* @param evt @Autowired
*/ private EventPublisher publisher;
@Override
public void process(RequestEvent evt) { @Autowired
try { private SIPProcessorObserver sipProcessorObserver;
RequestEventExt evtExt = (RequestEventExt)evt;
String requestAddress = evtExt.getRemoteIpAddress() + ":" + evtExt.getRemotePort(); @Override
logger.info("[{}] 收到注册请求,开始处理", requestAddress); public void afterPropertiesSet() throws Exception {
Request request = evt.getRequest(); // 添加消息处理的订阅
sipProcessorObserver.addRequestProcessor(method, this);
Response response = null; }
boolean passwordCorrect = false;
// 注册标志 0未携带授权头或者密码错误 1注册成功 2注销成功 /**
int registerFlag = 0; * 收到注册请求 处理
FromHeader fromHeader = (FromHeader) request.getHeader(FromHeader.NAME); * @param evt
AddressImpl address = (AddressImpl) fromHeader.getAddress(); */
SipUri uri = (SipUri) address.getURI(); @Override
String deviceId = uri.getUser(); public void process(RequestEvent evt) {
Device device = storager.queryVideoDevice(deviceId); try {
AuthorizationHeader authorhead = (AuthorizationHeader) request.getHeader(AuthorizationHeader.NAME); RequestEventExt evtExt = (RequestEventExt)evt;
// 校验密码是否正确 String requestAddress = evtExt.getRemoteIpAddress() + ":" + evtExt.getRemotePort();
if (authorhead != null) { logger.info("[{}] 收到注册请求,开始处理", requestAddress);
passwordCorrect = new DigestServerAuthenticationHelper().doAuthenticatePlainTextPassword(request, Request request = evt.getRequest();
sipConfig.getPassword());
} Response response = null;
if (StringUtils.isEmpty(sipConfig.getPassword())){ boolean passwordCorrect = false;
passwordCorrect = true; // 注册标志 0未携带授权头或者密码错误 1注册成功 2注销成功
} int registerFlag = 0;
FromHeader fromHeader = (FromHeader) request.getHeader(FromHeader.NAME);
// 未携带授权头或者密码错误 回复401 AddressImpl address = (AddressImpl) fromHeader.getAddress();
if (authorhead == null ) { SipUri uri = (SipUri) address.getURI();
String deviceId = uri.getUser();
logger.info("[{}] 未携带授权头 回复401", requestAddress); Device device = storager.queryVideoDevice(deviceId);
response = getMessageFactory().createResponse(Response.UNAUTHORIZED, request); AuthorizationHeader authorhead = (AuthorizationHeader) request.getHeader(AuthorizationHeader.NAME);
new DigestServerAuthenticationHelper().generateChallenge(getHeaderFactory(), response, sipConfig.getDomain()); // 校验密码是否正确
}else { if (authorhead != null) {
if (!passwordCorrect){ passwordCorrect = new DigestServerAuthenticationHelper().doAuthenticatePlainTextPassword(request,
// 注册失败 sipConfig.getPassword());
response = getMessageFactory().createResponse(Response.FORBIDDEN, request); }
response.setReasonPhrase("wrong password"); if (StringUtils.isEmpty(sipConfig.getPassword())){
logger.info("[{}] 密码/SIP服务器ID错误, 回复403", requestAddress); passwordCorrect = true;
}else { }
// 携带授权头并且密码正确
response = getMessageFactory().createResponse(Response.OK, request); // 未携带授权头或者密码错误 回复401
// 添加date头 if (authorhead == null ) {
SIPDateHeader dateHeader = new SIPDateHeader();
// 使用自己修改的 logger.info("[{}] 未携带授权头 回复401", requestAddress);
WvpSipDate wvpSipDate = new WvpSipDate(Calendar.getInstance(Locale.ENGLISH).getTimeInMillis()); response = getMessageFactory().createResponse(Response.UNAUTHORIZED, request);
dateHeader.setDate(wvpSipDate); new DigestServerAuthenticationHelper().generateChallenge(getHeaderFactory(), response, sipConfig.getDomain());
response.addHeader(dateHeader); }else {
if (!passwordCorrect){
ExpiresHeader expiresHeader = (ExpiresHeader) request.getHeader(Expires.NAME); // 注册失败
if (expiresHeader == null) { response = getMessageFactory().createResponse(Response.FORBIDDEN, request);
response = getMessageFactory().createResponse(Response.BAD_REQUEST, request); response.setReasonPhrase("wrong password");
ServerTransaction serverTransaction = getServerTransaction(evt); logger.info("[{}] 密码/SIP服务器ID错误, 回复403", requestAddress);
serverTransaction.sendResponse(response); }else {
if (serverTransaction.getDialog() != null) serverTransaction.getDialog().delete(); // 携带授权头并且密码正确
return; response = getMessageFactory().createResponse(Response.OK, request);
} // 添加date头
// 添加Contact头 SIPDateHeader dateHeader = new SIPDateHeader();
response.addHeader(request.getHeader(ContactHeader.NAME)); // 使用自己修改的
// 添加Expires头 WvpSipDate wvpSipDate = new WvpSipDate(Calendar.getInstance(Locale.ENGLISH).getTimeInMillis());
response.addHeader(request.getExpires()); dateHeader.setDate(wvpSipDate);
response.addHeader(dateHeader);
// 获取到通信地址等信息
ViaHeader viaHeader = (ViaHeader) request.getHeader(ViaHeader.NAME); ExpiresHeader expiresHeader = (ExpiresHeader) request.getHeader(Expires.NAME);
String received = viaHeader.getReceived(); if (expiresHeader == null) {
int rPort = viaHeader.getRPort(); response = getMessageFactory().createResponse(Response.BAD_REQUEST, request);
// 解析本地地址替代 ServerTransaction serverTransaction = getServerTransaction(evt);
if (StringUtils.isEmpty(received) || rPort == -1) { serverTransaction.sendResponse(response);
received = viaHeader.getHost(); if (serverTransaction.getDialog() != null) serverTransaction.getDialog().delete();
rPort = viaHeader.getPort(); return;
} }
// // 添加Contact头
response.addHeader(request.getHeader(ContactHeader.NAME));
if (device == null) { // 添加Expires头
device = new Device(); response.addHeader(request.getExpires());
device.setStreamMode("UDP");
device.setCharset("gb2312"); // 获取到通信地址等信息
device.setDeviceId(deviceId); ViaHeader viaHeader = (ViaHeader) request.getHeader(ViaHeader.NAME);
device.setFirsRegister(true); String received = viaHeader.getReceived();
} int rPort = viaHeader.getRPort();
device.setIp(received); // 解析本地地址替代
device.setPort(rPort); if (StringUtils.isEmpty(received) || rPort == -1) {
device.setHostAddress(received.concat(":").concat(String.valueOf(rPort))); received = viaHeader.getHost();
// 注销成功 rPort = viaHeader.getPort();
if (expiresHeader.getExpires() == 0) { }
registerFlag = 2; //
}
// 注册成功 if (device == null) {
else { device = new Device();
device.setExpires(expiresHeader.getExpires()); device.setStreamMode("UDP");
registerFlag = 1; device.setCharset("gb2312");
// 判断TCP还是UDP device.setDeviceId(deviceId);
boolean isTcp = false; device.setFirsRegister(true);
ViaHeader reqViaHeader = (ViaHeader) request.getHeader(ViaHeader.NAME); }
String transport = reqViaHeader.getTransport(); device.setIp(received);
if (transport.equals("TCP")) { device.setPort(rPort);
isTcp = true; device.setHostAddress(received.concat(":").concat(String.valueOf(rPort)));
} // 注销成功
device.setTransport(isTcp ? "TCP" : "UDP"); if (expiresHeader.getExpires() == 0) {
} registerFlag = 2;
} }
} // 注册成功
else {
ServerTransaction serverTransaction = getServerTransaction(evt); device.setExpires(expiresHeader.getExpires());
serverTransaction.sendResponse(response); registerFlag = 1;
if (serverTransaction.getDialog() != null) serverTransaction.getDialog().delete(); // 判断TCP还是UDP
// 注册成功 boolean isTcp = false;
// 保存到redis ViaHeader reqViaHeader = (ViaHeader) request.getHeader(ViaHeader.NAME);
// 下发catelog查询目录 String transport = reqViaHeader.getTransport();
if (registerFlag == 1 ) { if (transport.equals("TCP")) {
logger.info("[{}] 注册成功! deviceId:" + device.getDeviceId(), requestAddress); isTcp = true;
publisher.onlineEventPublish(device, VideoManagerConstants.EVENT_ONLINE_REGISTER); }
// 重新注册更新设备和通道以免设备替换或更新后信息无法更新 device.setTransport(isTcp ? "TCP" : "UDP");
handler.onRegister(device); }
} else if (registerFlag == 2) { }
logger.info("[{}] 注销成功! deviceId:" + device.getDeviceId(), requestAddress); }
publisher.outlineEventPublish(device.getDeviceId(), VideoManagerConstants.EVENT_OUTLINE_UNREGISTER);
} ServerTransaction serverTransaction = getServerTransaction(evt);
} catch (SipException | InvalidArgumentException | NoSuchAlgorithmException | ParseException e) { serverTransaction.sendResponse(response);
e.printStackTrace(); if (serverTransaction.getDialog() != null) serverTransaction.getDialog().delete();
} // 注册成功
// 保存到redis
} // 下发catelog查询目录
if (registerFlag == 1 ) {
public void setSipConfig(SipConfig sipConfig) { logger.info("[{}] 注册成功! deviceId:" + device.getDeviceId(), requestAddress);
this.sipConfig = sipConfig; publisher.onlineEventPublish(device, VideoManagerConstants.EVENT_ONLINE_REGISTER);
} // 重新注册更新设备和通道以免设备替换或更新后信息无法更新
handler.onRegister(device);
public void setHandler(RegisterLogicHandler handler) { } else if (registerFlag == 2) {
this.handler = handler; logger.info("[{}] 注销成功! deviceId:" + device.getDeviceId(), requestAddress);
} publisher.outlineEventPublish(device.getDeviceId(), VideoManagerConstants.EVENT_OUTLINE_UNREGISTER);
}
public void setVideoManagerStorager(IVideoManagerStorager storager) { } catch (SipException | InvalidArgumentException | NoSuchAlgorithmException | ParseException e) {
this.storager = storager; e.printStackTrace();
} }
public void setPublisher(EventPublisher publisher) { }
this.publisher = publisher;
} }
}

View File

@ -1,62 +1,77 @@
package com.genersoft.iot.vmp.gb28181.transmit.request.impl; package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl;
import java.text.ParseException; import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.ISIPRequestProcessor;
import javax.sip.InvalidArgumentException; import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
import javax.sip.RequestEvent; import org.slf4j.Logger;
import javax.sip.ServerTransaction; import org.slf4j.LoggerFactory;
import javax.sip.SipException; import org.springframework.beans.factory.InitializingBean;
import javax.sip.header.ExpiresHeader; import org.springframework.beans.factory.annotation.Autowired;
import javax.sip.message.Request; import org.springframework.stereotype.Component;
import javax.sip.message.Response;
import javax.sip.InvalidArgumentException;
import com.genersoft.iot.vmp.gb28181.transmit.request.SIPRequestAbstractProcessor; import javax.sip.RequestEvent;
import org.slf4j.Logger; import javax.sip.ServerTransaction;
import org.slf4j.LoggerFactory; import javax.sip.SipException;
import javax.sip.header.ExpiresHeader;
/** import javax.sip.message.Request;
* @Description:SUBSCRIBE请求处理器 import javax.sip.message.Response;
* @author: swwheihei import java.text.ParseException;
* @date: 2020年5月3日 下午5:31:20
*/ /**
public class SubscribeRequestProcessor extends SIPRequestAbstractProcessor { * @description:SUBSCRIBE请求处理器
* @author: swwheihei
private Logger logger = LoggerFactory.getLogger(SubscribeRequestProcessor.class); * @date: 2020年5月3日 下午5:31:20
*/
/** @Component
* 处理SUBSCRIBE请求 public class SubscribeRequestProcessor extends SIPRequestProcessorParent implements InitializingBean, ISIPRequestProcessor {
*
* @param evt private Logger logger = LoggerFactory.getLogger(SubscribeRequestProcessor.class);
*/ private String method = "SUBSCRIBE";
@Override
public void process(RequestEvent evt) { @Autowired
Request request = evt.getRequest(); private SIPProcessorObserver sipProcessorObserver;
try { @Override
Response response = null; public void afterPropertiesSet() throws Exception {
response = getMessageFactory().createResponse(200, request); // 添加消息处理的订阅
if (response != null) { sipProcessorObserver.addRequestProcessor(method, this);
ExpiresHeader expireHeader = getHeaderFactory().createExpiresHeader(30); }
response.setExpires(expireHeader);
} /**
logger.info("response : " + response.toString()); * 处理SUBSCRIBE请求
ServerTransaction transaction = getServerTransaction(evt); *
if (transaction != null) { * @param evt
transaction.sendResponse(response); */
transaction.getDialog().delete(); @Override
transaction.terminate(); public void process(RequestEvent evt) {
} else { Request request = evt.getRequest();
logger.info("processRequest serverTransactionId is null.");
} try {
Response response = null;
} catch (ParseException e) { response = getMessageFactory().createResponse(200, request);
e.printStackTrace(); if (response != null) {
} catch (SipException e) { ExpiresHeader expireHeader = getHeaderFactory().createExpiresHeader(30);
e.printStackTrace(); response.setExpires(expireHeader);
} catch (InvalidArgumentException e) { }
e.printStackTrace(); 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();
}
}
}

View File

@ -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);
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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) {
}
}

View File

@ -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();
}
}
}

View File

@ -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) {
// 不会收到上级平台的心跳信息
}
}

View File

@ -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) {
}
}

View File

@ -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) {
}
}

View File

@ -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);
}
}

View File

@ -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();
}
}
}

View File

@ -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);
}
}
}

View File

@ -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());
}
}

View File

@ -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());
}
}

View File

@ -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);
}
}

View File

@ -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) {
}
}

View File

@ -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) {
}
}

View File

@ -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) {
}
}

View File

@ -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) {
// 不会收到上级平台的心跳信息
}
}

View File

@ -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) {
}
}

View File

@ -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) {
}
}

View File

@ -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) {
}
}

View File

@ -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) {
}
}

View File

@ -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) {
}
}

View File

@ -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) {
}
}

View File

@ -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);
}

View File

@ -0,0 +1,8 @@
package com.genersoft.iot.vmp.gb28181.transmit.event.response;
import org.springframework.beans.factory.InitializingBean;
public abstract class SIPResponseProcessorAbstract implements InitializingBean, ISIPResponseProcessor {
}

View File

@ -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");
}
}

View File

@ -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
}
}

View File

@ -1,75 +1,97 @@
package com.genersoft.iot.vmp.gb28181.transmit.response.impl; package com.genersoft.iot.vmp.gb28181.transmit.event.response.impl;
import java.text.ParseException; import com.genersoft.iot.vmp.conf.SipConfig;
import com.genersoft.iot.vmp.gb28181.SipLayer;
import javax.sip.*; import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
import javax.sip.address.SipURI; import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver;
import javax.sip.header.CSeqHeader; import com.genersoft.iot.vmp.gb28181.transmit.event.response.SIPResponseProcessorAbstract;
import javax.sip.message.Request; import gov.nist.javax.sip.ResponseEventExt;
import javax.sip.message.Response; import gov.nist.javax.sip.stack.SIPDialog;
import org.slf4j.Logger;
import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager; import org.slf4j.LoggerFactory;
import gov.nist.javax.sip.ResponseEventExt; import org.springframework.beans.factory.annotation.Autowired;
import gov.nist.javax.sip.stack.SIPDialog; import org.springframework.stereotype.Component;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import javax.sip.InvalidArgumentException;
import org.springframework.beans.factory.annotation.Autowired; import javax.sip.ResponseEvent;
import org.springframework.stereotype.Component; import javax.sip.SipException;
import javax.sip.address.SipURI;
import com.genersoft.iot.vmp.conf.SipConfig; import javax.sip.header.CSeqHeader;
import com.genersoft.iot.vmp.gb28181.SipLayer; import javax.sip.message.Request;
import com.genersoft.iot.vmp.gb28181.transmit.response.ISIPResponseProcessor; import javax.sip.message.Response;
import java.text.ParseException;
/**
* @Description:处理INVITE响应 /**
* @author: swwheihei * @description: 处理INVITE响应
* @date: 2020年5月3日 下午4:43:52 * @author: panlinlin
*/ * @date: 2021年11月5日 1640
@Component */
public class InviteResponseProcessor implements ISIPResponseProcessor { @Component
public class InviteResponseProcessor extends SIPResponseProcessorAbstract {
private final static Logger logger = LoggerFactory.getLogger(InviteResponseProcessor.class);
private final static Logger logger = LoggerFactory.getLogger(InviteResponseProcessor.class);
@Autowired private String method = "INVITE";
private VideoStreamSessionManager streamSession;
@Autowired
/** private SipLayer sipLayer;
* 处理invite响应
* @Autowired
* @param evt 响应消息 private SipConfig config;
* @throws ParseException
*/
@Override @Autowired
public void process(ResponseEvent evt, SipLayer layer, SipConfig config) throws ParseException { private SIPProcessorObserver sipProcessorObserver;
try {
Response response = evt.getResponse(); @Override
int statusCode = response.getStatusCode(); public void afterPropertiesSet() throws Exception {
// trying不会回复 // 添加消息处理的订阅
if (statusCode == Response.TRYING) { sipProcessorObserver.addResponseProcessor(method, this);
} }
// 成功响应
// 下发ack @Autowired
if (statusCode == Response.OK) { private VideoStreamSessionManager streamSession;
ResponseEventExt event = (ResponseEventExt)evt;
SIPDialog dialog = (SIPDialog)evt.getDialog(); /**
CSeqHeader cseq = (CSeqHeader) response.getHeader(CSeqHeader.NAME); * 处理invite响应
Request reqAck = dialog.createAck(cseq.getSeqNumber()); *
SipURI requestURI = (SipURI) reqAck.getRequestURI(); * @param evt 响应消息
requestURI.setHost(event.getRemoteIpAddress()); * @throws ParseException
requestURI.setPort(event.getRemotePort()); */
reqAck.setRequestURI(requestURI); @Override
logger.info("" + event.getRemoteIpAddress() + ":" + event.getRemotePort() + "回复ack"); public void process(ResponseEvent evt ){
SipURI sipURI = (SipURI)dialog.getRemoteParty().getURI(); try {
String deviceId = requestURI.getUser(); Response response = evt.getResponse();
String channelId = sipURI.getUser(); int statusCode = response.getStatusCode();
// trying不会回复
dialog.sendAck(reqAck); if (statusCode == Response.TRYING) {
}
} // 成功响应
} catch (InvalidArgumentException | SipException e) { // 下发ack
e.printStackTrace(); 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();
}
}
}

View File

@ -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.ParentPlatform;
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatformCatch; 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.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.IRedisCatchStorage;
import com.genersoft.iot.vmp.storager.IVideoManagerStorager; import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -19,14 +18,15 @@ import javax.sip.header.WWWAuthenticateHeader;
import javax.sip.message.Response; import javax.sip.message.Response;
/** /**
* @Description:Register响应处理器 * @description:Register响应处理器
* @author: swwheihei * @author: swwheihei
* @date: 2020年5月3日 下午5:32:23 * @date: 2020年5月3日 下午5:32:23
*/ */
@Component @Component
public class RegisterResponseProcessor implements ISIPResponseProcessor { public class RegisterResponseProcessor extends SIPResponseProcessorAbstract {
private Logger logger = LoggerFactory.getLogger(RegisterResponseProcessor.class); private Logger logger = LoggerFactory.getLogger(RegisterResponseProcessor.class);
private String method = "REGISTER";
@Autowired @Autowired
private ISIPCommanderForPlatform sipCommanderForPlatform; private ISIPCommanderForPlatform sipCommanderForPlatform;
@ -37,18 +37,22 @@ public class RegisterResponseProcessor implements ISIPResponseProcessor {
@Autowired @Autowired
private IRedisCatchStorage redisCatchStorage; private IRedisCatchStorage redisCatchStorage;
public RegisterResponseProcessor() { @Autowired
private SIPProcessorObserver sipProcessorObserver;
@Override
public void afterPropertiesSet() throws Exception {
// 添加消息处理的订阅
sipProcessorObserver.addResponseProcessor(method, this);
} }
/** /**
* 处理Register响应 * 处理Register响应
* *
* @param evt * @param evt 事件
* @param layer
* @param config
*/ */
@Override @Override
public void process(ResponseEvent evt, SipLayer layer, SipConfig config) { public void process(ResponseEvent evt) {
Response response = evt.getResponse(); Response response = evt.getResponse();
CallIdHeader callIdHeader = (CallIdHeader) response.getHeader(CallIdHeader.NAME); CallIdHeader callIdHeader = (CallIdHeader) response.getHeader(CallIdHeader.NAME);
String callId = callIdHeader.getCallId(); String callId = callIdHeader.getCallId();

View File

@ -0,0 +1,7 @@
package com.genersoft.iot.vmp.gb28181.transmit.event.timeout;
import javax.sip.TimeoutEvent;
public interface ITimeoutProcessor {
void process(TimeoutEvent event);
}

View File

@ -0,0 +1,36 @@
package com.genersoft.iot.vmp.gb28181.transmit.event.timeout.impl;
import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver;
import com.genersoft.iot.vmp.gb28181.transmit.event.timeout.ITimeoutProcessor;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.sip.TimeoutEvent;
import javax.sip.header.CallIdHeader;
@Component
public class TimeoutProcessorImpl implements InitializingBean, ITimeoutProcessor {
@Autowired
private SIPProcessorObserver processorObserver;
@Autowired
private SipSubscribe sipSubscribe;
@Override
public void afterPropertiesSet() throws Exception {
processorObserver.addTimeoutProcessor(this);
}
@Override
public void process(TimeoutEvent event) {
// TODO Auto-generated method stub
CallIdHeader callIdHeader = event.getClientTransaction().getDialog().getCallId();
String callId = callIdHeader.getCallId();
SipSubscribe.Event errorSubscribe = sipSubscribe.getErrorSubscribe(callId);
SipSubscribe.EventResult<TimeoutEvent> timeoutEventEventResult = new SipSubscribe.EventResult<>(event);
errorSubscribe.response(timeoutEventEventResult);
}
}

View File

@ -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();
}

View File

@ -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;
}
}

View File

@ -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消息实现此消息一般为级联消息上级给下级发送请求取消指令
}
}

View File

@ -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());
}
}

View File

@ -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;
}

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -6,7 +6,7 @@ import java.util.Date;
import java.util.Locale; import java.util.Locale;
/** /**
* @Description:时间工具类主要处理ISO 8601格式转换 * @description:时间工具类主要处理ISO 8601格式转换
* @author: swwheihei * @author: swwheihei
* @date: 2020年5月8日 下午3:24:42 * @date: 2020年5月8日 下午3:24:42
*/ */

View File

@ -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.AddressImpl;
import gov.nist.javax.sip.address.SipUri; import gov.nist.javax.sip.address.SipUri;
@ -9,15 +9,20 @@ import javax.sip.message.Request;
/** /**
* @author panlinlin * @author panlinlin
* @version 1.0.0 * @version 1.0.0
* @Description JAIN SIP的工具类 * @description JAIN SIP的工具类
* @createTime 2021年09月27日 15:12:00 * @createTime 2021年09月27日 15:12:00
*/ */
public class SipUtils { public class SipUtils {
public static String getUserIdFromFromHeader(Request request) { public static String getUserIdFromFromHeader(Request request) {
FromHeader fromHeader = (FromHeader)request.getHeader(FromHeader.NAME); FromHeader fromHeader = (FromHeader)request.getHeader(FromHeader.NAME);
return getUserIdFromFromHeader(fromHeader);
}
public static String getUserIdFromFromHeader(FromHeader fromHeader) {
AddressImpl address = (AddressImpl)fromHeader.getAddress(); AddressImpl address = (AddressImpl)fromHeader.getAddress();
SipUri uri = (SipUri) address.getURI(); SipUri uri = (SipUri) address.getURI();
return uri.getUser(); return uri.getUser();
} }
} }

View File

@ -1,15 +1,7 @@
package com.genersoft.iot.vmp.gb28181.utils; 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.JSONArray;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import org.dom4j.Attribute; import org.dom4j.Attribute;
import org.dom4j.Document; import org.dom4j.Document;
import org.dom4j.DocumentException; import org.dom4j.DocumentException;
@ -19,6 +11,12 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils; 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的工具包 * 基于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();
}
} }

View File

@ -31,7 +31,7 @@ import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
/** /**
* @Description:针对 ZLMediaServer的hook事件监听 * @description:针对 ZLMediaServer的hook事件监听
* @author: swwheihei * @author: swwheihei
* @date: 2020年5月8日 上午10:46:48 * @date: 2020年5月8日 上午10:46:48
*/ */

View File

@ -8,7 +8,7 @@ import java.util.*;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
/** /**
* @Description:针对 ZLMediaServer的hook事件订阅 * @description:针对 ZLMediaServer的hook事件订阅
* @author: pan * @author: pan
* @date: 2020年12月2日 21:17:32 * @date: 2020年12月2日 21:17:32
*/ */

View File

@ -55,6 +55,9 @@ public class ZLMRESTfulUtils {
if (responseStr != null) { if (responseStr != null) {
responseJSON = JSON.parseObject(responseStr); responseJSON = JSON.parseObject(responseStr);
} }
}else {
response.close();
Objects.requireNonNull(response.body()).close();
} }
} catch (ConnectException e) { } catch (ConnectException e) {
logger.error(String.format("连接ZLM失败: %s, %s", e.getCause().getMessage(), e.getMessage())); logger.error(String.format("连接ZLM失败: %s, %s", e.getCause().getMessage(), e.getMessage()));
@ -74,6 +77,10 @@ public class ZLMRESTfulUtils {
} catch (IOException e) { } catch (IOException e) {
logger.error(String.format("[ %s ]请求失败: %s", url, e.getMessage())); logger.error(String.format("[ %s ]请求失败: %s", url, e.getMessage()));
} }
}else {
response.close();
Objects.requireNonNull(response.body()).close();
} }
} }

View File

@ -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);
}

View File

@ -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());
});
}
}

View File

@ -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 * * * ?";
}
}
}

View File

@ -1,7 +1,5 @@
package com.genersoft.iot.vmp.storager; package com.genersoft.iot.vmp.storager;
import java.util.List;
import com.genersoft.iot.vmp.gb28181.bean.*; import com.genersoft.iot.vmp.gb28181.bean.*;
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; 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.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.genersoft.iot.vmp.vmanager.gb28181.platform.bean.ChannelReduce;
import com.github.pagehelper.PageInfo; import com.github.pagehelper.PageInfo;
import java.util.List;
/** /**
* @Description:视频设备数据存储接口 * @description:视频设备数据存储接口
* @author: swwheihei * @author: swwheihei
* @date: 2020年5月6日 下午2:14:31 * @date: 2020年5月6日 下午2:14:31
*/ */
@ -97,6 +97,13 @@ public interface IVideoManagerStorager {
*/ */
public DeviceChannel queryChannel(String deviceId, String channelId); public DeviceChannel queryChannel(String deviceId, String channelId);
/**
* 删除通道
* @param deviceId 设备ID
* @param channelId 通道ID
*/
public int delChannel(String deviceId, String channelId);
/** /**
* 获取多个设备 * 获取多个设备
* @param page 当前页数 * @param page 当前页数
@ -373,7 +380,30 @@ public interface IVideoManagerStorager {
*/ */
void updateMediaServer(MediaServerItem mediaServerItem); void updateMediaServer(MediaServerItem mediaServerItem);
/**
* 根据媒体ID获取启用/不启用的代理列表
* @param id 媒体ID
* @param b 启用/不启用
* @return
*/
List<StreamProxyItem> getStreamProxyListForEnableInMediaServer(String id, boolean b); 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);
} }

View File

@ -74,6 +74,9 @@ public interface DeviceChannelMapper {
@Delete("DELETE FROM device_channel WHERE deviceId=#{deviceId}") @Delete("DELETE FROM device_channel WHERE deviceId=#{deviceId}")
int cleanChannelsByDeviceId(String 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}"}) @Update(value = {"UPDATE device_channel SET streamId=null WHERE deviceId=#{deviceId} AND channelId=#{channelId}"})
void stopPlay(String deviceId, String 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); List<ChannelReduce> queryChannelListInAll(String query, Boolean online, Boolean hasSubChannel, String platformId, Boolean inPlatform);
@Select("SELECT * FROM device_channel WHERE channelId=#{channelId}") @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);
} }

View File

@ -33,6 +33,7 @@ public interface DeviceMapper {
"createTime," + "createTime," +
"updateTime," + "updateTime," +
"charset," + "charset," +
"subscribeCycleForCatalog," +
"online" + "online" +
") VALUES (" + ") VALUES (" +
"#{deviceId}," + "#{deviceId}," +
@ -51,6 +52,7 @@ public interface DeviceMapper {
"#{createTime}," + "#{createTime}," +
"#{updateTime}," + "#{updateTime}," +
"#{charset}," + "#{charset}," +
"#{subscribeCycleForCatalog}," +
"#{online}" + "#{online}" +
")") ")")
int add(Device device); int add(Device device);
@ -72,6 +74,7 @@ public interface DeviceMapper {
"<if test=\"keepaliveTime != null\">, keepaliveTime='${keepaliveTime}'</if>" + "<if test=\"keepaliveTime != null\">, keepaliveTime='${keepaliveTime}'</if>" +
"<if test=\"expires != null\">, expires=${expires}</if>" + "<if test=\"expires != null\">, expires=${expires}</if>" +
"<if test=\"charset != null\">, charset='${charset}'</if>" + "<if test=\"charset != null\">, charset='${charset}'</if>" +
"<if test=\"subscribeCycleForCatalog != null\">, subscribeCycleForCatalog=#{subscribeCycleForCatalog}</if>" +
"WHERE deviceId='${deviceId}'"+ "WHERE deviceId='${deviceId}'"+
" </script>"}) " </script>"})
int update(Device device); int update(Device device);

View File

@ -1,14 +1,12 @@
package com.genersoft.iot.vmp.storager.impl; 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.bean.*;
import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager; 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.MediaServerItem;
import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem; import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem;
import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem; import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage; 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.storager.dao.*;
import com.genersoft.iot.vmp.vmanager.gb28181.platform.bean.ChannelReduce; import com.genersoft.iot.vmp.vmanager.gb28181.platform.bean.ChannelReduce;
import com.github.pagehelper.PageHelper; import com.github.pagehelper.PageHelper;
@ -18,14 +16,18 @@ import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.datasource.DataSourceTransactionManager; import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
import org.springframework.transaction.TransactionDefinition; import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Transactional; 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 * @author: swwheihei
* @date: 2020年5月6日 下午2:31:42 * @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 @Override
public void startPlay(String deviceId, String channelId, String streamId) { public void startPlay(String deviceId, String channelId, String streamId) {
deviceChannelMapper.startPlay(deviceId, channelId, 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); return streamProxyMapper.selectForEnableInMediaServer(id, enable);
} }
@Override @Override
public Device queryVideoDeviceByChannelId(String channelId) { public Device queryVideoDeviceByChannelId( String channelId) {
Device result = null; Device result = null;
List<DeviceChannel> channelList = deviceChannelMapper.queryChannelByChannelId(channelId); List<DeviceChannel> channelList = deviceChannelMapper.queryChannelByChannelId(channelId);
if (channelList.size() == 1) { if (channelList.size() == 1) {

View File

@ -6,7 +6,7 @@ import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
/** /**
* @Description:spring bean获取工厂获取spring中的已初始化的bean * @description:spring bean获取工厂获取spring中的已初始化的bean
* @author: swwheihei * @author: swwheihei
* @date: 2019年6月25日 下午4:51:52 * @date: 2019年6月25日 下午4:51:52
* *

Some files were not shown because too many files have changed in this diff Show More