初始提交
This commit is contained in:
commit
70091f29f2
173
pom.xml
Normal file
173
pom.xml
Normal file
@ -0,0 +1,173 @@
|
||||
<?xml version="1.0"?>
|
||||
<project
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
|
||||
xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>1.5.10.RELEASE</version>
|
||||
</parent>
|
||||
|
||||
<groupId>com.genersoft</groupId>
|
||||
<artifactId>wvp</artifactId>
|
||||
<name>web video platform</name>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
|
||||
<hystrix.version>1.5.12</hystrix.version>
|
||||
<!-- 依赖版本 -->
|
||||
<mapper.version>3.4.0</mapper.version>
|
||||
<mybatis.version>3.3.1</mybatis.version>
|
||||
<mybatis.spring.version>1.2.4</mybatis.spring.version>
|
||||
<pagehelper.version>4.1.1</pagehelper.version>
|
||||
<snippetsDirectory>${project.build.directory}/generated-snippets</snippetsDirectory>
|
||||
<asciidoctor.input.directory>${project.basedir}/docs/asciidoc</asciidoctor.input.directory>
|
||||
<generated.asciidoc.directory>${project.build.directory}/asciidoc</generated.asciidoc.directory>
|
||||
<asciidoctor.html.output.directory>${project.build.directory}/asciidoc/html</asciidoctor.html.output.directory>
|
||||
<asciidoctor.pdf.output.directory>${project.build.directory}/asciidoc/pdf</asciidoctor.pdf.output.directory>
|
||||
<gson.version>2.8.0</gson.version>
|
||||
<jedis.version>3.0.1</jedis.version>
|
||||
<jsonlib.version>2.4</jsonlib.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-jdbc</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-undertow</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context</artifactId>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- druid -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>druid</artifactId>
|
||||
<version>1.0.11</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
<version>5.1.30</version>
|
||||
</dependency>
|
||||
|
||||
<!--Mybatis -->
|
||||
<dependency>
|
||||
<groupId>org.mybatis</groupId>
|
||||
<artifactId>mybatis</artifactId>
|
||||
<version>${mybatis.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mybatis</groupId>
|
||||
<artifactId>mybatis-spring</artifactId>
|
||||
<version>${mybatis.spring.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!--分页插件 -->
|
||||
<dependency>
|
||||
<groupId>com.github.pagehelper</groupId>
|
||||
<artifactId>pagehelper</artifactId>
|
||||
<version>${pagehelper.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!--通用Mapper -->
|
||||
<dependency>
|
||||
<groupId>tk.mybatis</groupId>
|
||||
<artifactId>mapper</artifactId>
|
||||
<version>${mapper.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
<version>3.4</version>
|
||||
</dependency>
|
||||
<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>fastjson</artifactId>
|
||||
<version>1.2.33</version>
|
||||
</dependency>
|
||||
|
||||
<!--Swagger2 -->
|
||||
<!--在线文档 -->
|
||||
<dependency>
|
||||
<groupId>io.springfox</groupId>
|
||||
<artifactId>springfox-swagger2</artifactId>
|
||||
<version>2.6.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.springfox</groupId>
|
||||
<artifactId>springfox-swagger-ui</artifactId>
|
||||
<version>2.6.1</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 日志相关 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-aop</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>javax.sip</groupId>
|
||||
<artifactId>jain-sip-ri</artifactId>
|
||||
<version>1.3.0-91</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.dom4j</groupId>
|
||||
<artifactId>dom4j</artifactId>
|
||||
<version>2.1.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.code.gson</groupId>
|
||||
<artifactId>gson</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-redis</artifactId>
|
||||
<version>1.8.4.RELEASE</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>redis.clients</groupId>
|
||||
<artifactId>jedis</artifactId>
|
||||
<version>2.9.0</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>1.8</source>
|
||||
<target>1.8</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
</plugin>
|
||||
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
20
src/main/java/com/genersoft/iot/vmp/VManageBootstrap.java
Normal file
20
src/main/java/com/genersoft/iot/vmp/VManageBootstrap.java
Normal file
@ -0,0 +1,20 @@
|
||||
package com.genersoft.iot.vmp;
|
||||
|
||||
import java.util.logging.LogManager;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
//@EnableEurekaClient
|
||||
//@EnableTransactionManagement
|
||||
//@EnableFeignClients(basePackages = { "com.genersoft.iot.vmp", "org.integrain" })
|
||||
//@ServletComponentScan("com.genersoft.iot.vmp")
|
||||
@EnableAutoConfiguration
|
||||
public class VManageBootstrap extends LogManager {
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(VManageBootstrap.class, args);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
package com.genersoft.iot.vmp.common;
|
||||
|
||||
/**
|
||||
* @Description:TODO(这里用一句话描述这个类的作用)
|
||||
* @author: songww
|
||||
* @date: 2019年5月30日 下午3:04:04
|
||||
*
|
||||
*/
|
||||
public class VideoManagerConstants {
|
||||
|
||||
public static final String CACHEKEY_PREFIX = "VMP_deviceId_";
|
||||
|
||||
public static final String KEEPLIVEKEY_PREFIX = "VMP_keeplive_";
|
||||
|
||||
public static final String EVENT_ONLINE_REGISTER = "1";
|
||||
|
||||
public static final String EVENT_ONLINE_KEEPLIVE = "2";
|
||||
|
||||
public static final String EVENT_OUTLINE_UNREGISTER = "1";
|
||||
|
||||
public static final String EVENT_OUTLINE_TIMEOUT = "2";
|
||||
}
|
79
src/main/java/com/genersoft/iot/vmp/conf/RedisConfig.java
Normal file
79
src/main/java/com/genersoft/iot/vmp/conf/RedisConfig.java
Normal file
@ -0,0 +1,79 @@
|
||||
package com.genersoft.iot.vmp.conf;
|
||||
|
||||
import org.springframework.cache.annotation.CachingConfigurerSupport;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
|
||||
import org.springframework.data.redis.serializer.StringRedisSerializer;
|
||||
|
||||
import com.alibaba.fastjson.parser.ParserConfig;
|
||||
import com.genersoft.iot.vmp.utils.redis.FastJsonRedisSerializer;
|
||||
|
||||
/**
|
||||
* @Description:Redis中间件配置类
|
||||
* @author: songww
|
||||
* @date: 2019年5月30日 上午10:58:25
|
||||
*
|
||||
*/
|
||||
@Configuration
|
||||
// @EnableCaching
|
||||
public class RedisConfig extends CachingConfigurerSupport {
|
||||
|
||||
@Bean("redisTemplate")
|
||||
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
|
||||
RedisTemplate<Object, Object> template = new RedisTemplate<>();
|
||||
template.setConnectionFactory(redisConnectionFactory);
|
||||
ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
|
||||
FastJsonRedisSerializer<Object> serializer = new FastJsonRedisSerializer<Object>(Object.class);
|
||||
// value值的序列化采用fastJsonRedisSerializer
|
||||
template.setValueSerializer(serializer);
|
||||
template.setHashValueSerializer(serializer);
|
||||
// key的序列化采用StringRedisSerializer
|
||||
template.setKeySerializer(new StringRedisSerializer());
|
||||
template.setHashKeySerializer(new StringRedisSerializer());
|
||||
|
||||
template.setConnectionFactory(redisConnectionFactory);
|
||||
return template;
|
||||
}
|
||||
|
||||
/**
|
||||
* redis消息监听器容器 可以添加多个监听不同话题的redis监听器,只需要把消息监听器和相应的消息订阅处理器绑定,该消息监听器
|
||||
* 通过反射技术调用消息订阅处理器的相关方法进行一些业务处理
|
||||
*
|
||||
* @param connectionFactory
|
||||
* @param listenerAdapter
|
||||
* @return
|
||||
*/
|
||||
@Bean
|
||||
RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory) {
|
||||
|
||||
RedisMessageListenerContainer container = new RedisMessageListenerContainer();
|
||||
container.setConnectionFactory(connectionFactory);
|
||||
return container;
|
||||
}
|
||||
// @Bean
|
||||
// RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory,
|
||||
// MessageListenerAdapter listenerAdapter) {
|
||||
//
|
||||
// RedisMessageListenerContainer container = new RedisMessageListenerContainer();
|
||||
// container.setConnectionFactory(connectionFactory);
|
||||
// // 订阅了一个叫通道
|
||||
// container.addMessageListener(listenerAdapter, new PatternTopic(VideoManagerConstants.KEEPLIVEKEY_PREFIX+"*"));
|
||||
// // 这个container 可以添加多个 messageListener
|
||||
// return container;
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * 消息监听器适配器,绑定消息处理器,利用反射技术调用消息处理器的业务方法
|
||||
// * @param receiver
|
||||
// * @return
|
||||
// */
|
||||
// @Bean
|
||||
// MessageListenerAdapter listenerAdapter(MessageReceiver receiver) {
|
||||
// //这个地方 是给messageListenerAdapter 传入一个消息接受的处理器,利用反射的方法调用“receiveMessage”
|
||||
// //也有好几个重载方法,这边默认调用处理器的方法 叫handleMessage 可以自己到源码里面看
|
||||
// return new MessageListenerAdapter(receiver, "receiveMessage");
|
||||
// }
|
||||
}
|
83
src/main/java/com/genersoft/iot/vmp/conf/SipConfig.java
Normal file
83
src/main/java/com/genersoft/iot/vmp/conf/SipConfig.java
Normal file
@ -0,0 +1,83 @@
|
||||
package com.genersoft.iot.vmp.conf;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration
|
||||
public class SipConfig {
|
||||
|
||||
@Value("${sip.ip}")
|
||||
String sipIp;
|
||||
@Value("${sip.port}")
|
||||
Integer sipPort;
|
||||
@Value("${sip.domain}")
|
||||
String sipDomain;
|
||||
@Value("${sip.password}")
|
||||
String sipPassword;
|
||||
@Value("${media.ip}")
|
||||
String mediaIp;
|
||||
|
||||
@Value("${media.port}")
|
||||
Integer mediaPort;
|
||||
|
||||
@Value("${sip.ptz.speed:50}")
|
||||
Integer speed;
|
||||
|
||||
public String getSipIp() {
|
||||
return sipIp;
|
||||
}
|
||||
|
||||
public void setSipIp(String sipIp) {
|
||||
this.sipIp = sipIp;
|
||||
}
|
||||
|
||||
public Integer getSipPort() {
|
||||
return sipPort;
|
||||
}
|
||||
|
||||
public void setSipPort(Integer sipPort) {
|
||||
this.sipPort = sipPort;
|
||||
}
|
||||
|
||||
public String getSipDomain() {
|
||||
return sipDomain;
|
||||
}
|
||||
|
||||
public void setSipDomain(String sipDomain) {
|
||||
this.sipDomain = sipDomain;
|
||||
}
|
||||
|
||||
public String getSipPassword() {
|
||||
return sipPassword;
|
||||
}
|
||||
|
||||
public void setSipPassword(String sipPassword) {
|
||||
this.sipPassword = sipPassword;
|
||||
}
|
||||
|
||||
public String getMediaIp() {
|
||||
return mediaIp;
|
||||
}
|
||||
|
||||
public void setMediaIp(String mediaIp) {
|
||||
this.mediaIp = mediaIp;
|
||||
}
|
||||
|
||||
public Integer getMediaPort() {
|
||||
return mediaPort;
|
||||
}
|
||||
|
||||
public void setMediaPort(Integer mediaPort) {
|
||||
this.mediaPort = mediaPort;
|
||||
}
|
||||
|
||||
public Integer getSpeed() {
|
||||
return speed;
|
||||
}
|
||||
|
||||
public void setSpeed(Integer speed) {
|
||||
this.speed = speed;
|
||||
}
|
||||
|
||||
|
||||
}
|
25
src/main/java/com/genersoft/iot/vmp/conf/VManagerConfig.java
Normal file
25
src/main/java/com/genersoft/iot/vmp/conf/VManagerConfig.java
Normal file
@ -0,0 +1,25 @@
|
||||
package com.genersoft.iot.vmp.conf;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* @Description:TODO(这里用一句话描述这个类的作用)
|
||||
* @author: songww
|
||||
* @date: 2020年5月6日 下午2:46:00
|
||||
*/
|
||||
@Configuration("vmConfig")
|
||||
public class VManagerConfig {
|
||||
|
||||
@Value("${spring.application.database:redis}")
|
||||
private String database;
|
||||
|
||||
public String getDatabase() {
|
||||
return database;
|
||||
}
|
||||
|
||||
public void setDatabase(String database) {
|
||||
this.database = database;
|
||||
}
|
||||
|
||||
}
|
223
src/main/java/com/genersoft/iot/vmp/gb28181/SipLayer.java
Normal file
223
src/main/java/com/genersoft/iot/vmp/gb28181/SipLayer.java
Normal file
@ -0,0 +1,223 @@
|
||||
package com.genersoft.iot.vmp.gb28181;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import javax.sip.DialogTerminatedEvent;
|
||||
import javax.sip.IOExceptionEvent;
|
||||
import javax.sip.ListeningPoint;
|
||||
import javax.sip.RequestEvent;
|
||||
import javax.sip.ResponseEvent;
|
||||
import javax.sip.ServerTransaction;
|
||||
import javax.sip.SipFactory;
|
||||
import javax.sip.SipListener;
|
||||
import javax.sip.SipProvider;
|
||||
import javax.sip.SipStack;
|
||||
import javax.sip.TimeoutEvent;
|
||||
import javax.sip.TransactionAlreadyExistsException;
|
||||
import javax.sip.TransactionTerminatedEvent;
|
||||
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 javax.sip.message.Response;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.genersoft.iot.vmp.conf.SipConfig;
|
||||
import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorFactory;
|
||||
import com.genersoft.iot.vmp.gb28181.transmit.request.ISIPRequestProcessor;
|
||||
import com.genersoft.iot.vmp.gb28181.transmit.response.ISIPResponseProcessor;
|
||||
|
||||
import gov.nist.javax.sip.SipStackImpl;
|
||||
|
||||
@Component
|
||||
public class SipLayer implements SipListener{
|
||||
|
||||
private final static Logger logger = LoggerFactory.getLogger(SipLayer.class);
|
||||
|
||||
@Autowired
|
||||
private SipConfig config;
|
||||
|
||||
private SipProvider tcpSipProvider;
|
||||
|
||||
private SipProvider udpSipProvider;
|
||||
|
||||
@Autowired
|
||||
private SIPProcessorFactory processorFactory;
|
||||
|
||||
private SipStack sipStack;
|
||||
|
||||
private AddressFactory addressFactory;
|
||||
private HeaderFactory headerFactory;
|
||||
private MessageFactory messageFactory;
|
||||
|
||||
@Bean
|
||||
private boolean initSipServer() throws Exception {
|
||||
SipFactory sipFactory = SipFactory.getInstance();
|
||||
sipFactory.setPathName("gov.nist");
|
||||
headerFactory = sipFactory.createHeaderFactory();
|
||||
addressFactory = sipFactory.createAddressFactory();
|
||||
messageFactory = sipFactory.createMessageFactory();
|
||||
|
||||
Properties properties = new Properties();
|
||||
properties.setProperty("javax.sip.STACK_NAME", "GB28181_SIP");
|
||||
properties.setProperty("javax.sip.IP_ADDRESS", config.getSipIp());
|
||||
/**
|
||||
* sip_server_log.log 和 sip_debug_log.log public static final int TRACE_NONE =
|
||||
* 0; public static final int TRACE_MESSAGES = 16; public static final int
|
||||
* TRACE_EXCEPTION = 17; public static final int TRACE_DEBUG = 32;
|
||||
*/
|
||||
properties.setProperty("gov.nist.javax.sip.TRACE_LEVEL", "16");
|
||||
properties.setProperty("gov.nist.javax.sip.SERVER_LOG", "sip_server_log");
|
||||
properties.setProperty("gov.nist.javax.sip.DEBUG_LOG", "sip_debug_log");
|
||||
sipStack = (SipStackImpl) sipFactory.createSipStack(properties);
|
||||
|
||||
try {
|
||||
startTcpListener();
|
||||
startUdpListener();
|
||||
} catch (Exception e) {
|
||||
logger.error("Sip Server 启动失败! port {"+config.getSipPort()+"}");
|
||||
e.printStackTrace();
|
||||
throw e;
|
||||
}
|
||||
logger.info("Sip Server 启动成功 port {"+config.getSipPort()+"}");
|
||||
return true;
|
||||
}
|
||||
|
||||
private void startTcpListener() throws Exception {
|
||||
ListeningPoint tcpListeningPoint = sipStack.createListeningPoint(config.getSipIp(), config.getSipPort(), "TCP");
|
||||
tcpSipProvider = sipStack.createSipProvider(tcpListeningPoint);
|
||||
tcpSipProvider.addSipListener(this);
|
||||
}
|
||||
|
||||
private void startUdpListener() throws Exception {
|
||||
ListeningPoint udpListeningPoint = sipStack.createListeningPoint(config.getSipIp(), config.getSipPort(), "UDP");
|
||||
udpSipProvider = sipStack.createSipProvider(udpListeningPoint);
|
||||
udpSipProvider.addSipListener(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* SIP服务端接收消息的方法 Content 里面是GBK编码 This method is called by the SIP stack when a
|
||||
* new request arrives.
|
||||
*/
|
||||
@Override
|
||||
public void processRequest(RequestEvent evt) {
|
||||
ISIPRequestProcessor processor = processorFactory.createRequestProcessor(evt);
|
||||
processor.process(evt, this, getServerTransaction(evt));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processResponse(ResponseEvent evt) {
|
||||
Response response = evt.getResponse();
|
||||
int status = response.getStatusCode();
|
||||
if ((status >= 200) && (status < 300)) { // Success!
|
||||
ISIPResponseProcessor processor = processorFactory.createResponseProcessor(evt);
|
||||
processor.process(evt,this,config);
|
||||
} else {
|
||||
logger.warn("接收到失败的response响应!status:"+status+",message:"+response.getContent().toString());
|
||||
}
|
||||
//trying不会回复
|
||||
if(status == Response.TRYING){
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Title: processTimeout</p>
|
||||
* <p>Description: </p>
|
||||
* @param timeoutEvent
|
||||
*/
|
||||
@Override
|
||||
public void processTimeout(TimeoutEvent timeoutEvent) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* <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
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Title: processDialogTerminated</p>
|
||||
* <p>Description: </p>
|
||||
* @param dialogTerminatedEvent
|
||||
*/
|
||||
@Override
|
||||
public void processDialogTerminated(DialogTerminatedEvent dialogTerminatedEvent) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
private 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) {
|
||||
serverTransaction = tcpSipProvider.getNewServerTransaction(request);
|
||||
} else {
|
||||
serverTransaction = udpSipProvider.getNewServerTransaction(request);
|
||||
}
|
||||
} catch (TransactionAlreadyExistsException e) {
|
||||
e.printStackTrace();
|
||||
} catch (TransactionUnavailableException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return serverTransaction;
|
||||
}
|
||||
|
||||
|
||||
public AddressFactory getAddressFactory() {
|
||||
return addressFactory;
|
||||
}
|
||||
|
||||
public HeaderFactory getHeaderFactory() {
|
||||
return headerFactory;
|
||||
}
|
||||
|
||||
public MessageFactory getMessageFactory() {
|
||||
return messageFactory;
|
||||
}
|
||||
|
||||
public SipProvider getTcpSipProvider() {
|
||||
return tcpSipProvider;
|
||||
}
|
||||
|
||||
public SipProvider getUdpSipProvider() {
|
||||
return udpSipProvider;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,211 @@
|
||||
/*
|
||||
* Conditions Of Use
|
||||
*
|
||||
* This software was developed by employees of the National Institute of
|
||||
* Standards and Technology (NIST), an agency of the Federal Government.
|
||||
* Pursuant to title 15 Untied States Code Section 105, works of NIST
|
||||
* employees are not subject to copyright protection in the United States
|
||||
* and are considered to be in the public domain. As a result, a formal
|
||||
* license is not needed to use the software.
|
||||
*
|
||||
* This software is provided by NIST as a service and is expressly
|
||||
* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED
|
||||
* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT
|
||||
* AND DATA ACCURACY. NIST does not warrant or make any representations
|
||||
* regarding the use of the software or the results thereof, including but
|
||||
* not limited to the correctness, accuracy, reliability or usefulness of
|
||||
* the software.
|
||||
*
|
||||
* Permission to use this software is contingent upon your acceptance
|
||||
* of the terms of this agreement
|
||||
*
|
||||
* .
|
||||
*
|
||||
*/
|
||||
package com.genersoft.iot.vmp.gb28181.auth;
|
||||
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.Date;
|
||||
import java.util.Random;
|
||||
|
||||
import javax.sip.address.URI;
|
||||
import javax.sip.header.AuthorizationHeader;
|
||||
import javax.sip.header.HeaderFactory;
|
||||
import javax.sip.header.WWWAuthenticateHeader;
|
||||
import javax.sip.message.Request;
|
||||
import javax.sip.message.Response;
|
||||
|
||||
import gov.nist.core.InternalErrorHandler;
|
||||
|
||||
/**
|
||||
* Implements the HTTP digest authentication method server side functionality.
|
||||
*
|
||||
* @author M. Ranganathan
|
||||
* @author Marc Bednarek
|
||||
*/
|
||||
|
||||
public class DigestServerAuthenticationHelper {
|
||||
|
||||
private MessageDigest messageDigest;
|
||||
|
||||
public static final String DEFAULT_ALGORITHM = "MD5";
|
||||
public static final String DEFAULT_SCHEME = "Digest";
|
||||
|
||||
|
||||
|
||||
|
||||
/** to hex converter */
|
||||
private static final char[] toHex = { '0', '1', '2', '3', '4', '5', '6',
|
||||
'7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
|
||||
|
||||
/**
|
||||
* Default constructor.
|
||||
* @throws NoSuchAlgorithmException
|
||||
*/
|
||||
public DigestServerAuthenticationHelper()
|
||||
throws NoSuchAlgorithmException {
|
||||
messageDigest = MessageDigest.getInstance(DEFAULT_ALGORITHM);
|
||||
}
|
||||
|
||||
public static String toHexString(byte b[]) {
|
||||
int pos = 0;
|
||||
char[] c = new char[b.length * 2];
|
||||
for (int i = 0; i < b.length; i++) {
|
||||
c[pos++] = toHex[(b[i] >> 4) & 0x0F];
|
||||
c[pos++] = toHex[b[i] & 0x0f];
|
||||
}
|
||||
return new String(c);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the challenge string.
|
||||
*
|
||||
* @return a generated nonce.
|
||||
*/
|
||||
private String generateNonce() {
|
||||
// Get the time of day and run MD5 over it.
|
||||
Date date = new Date();
|
||||
long time = date.getTime();
|
||||
Random rand = new Random();
|
||||
long pad = rand.nextLong();
|
||||
String nonceString = (new Long(time)).toString()
|
||||
+ (new Long(pad)).toString();
|
||||
byte mdbytes[] = messageDigest.digest(nonceString.getBytes());
|
||||
// Convert the mdbytes array into a hex string.
|
||||
return toHexString(mdbytes);
|
||||
}
|
||||
|
||||
public Response generateChallenge(HeaderFactory headerFactory, Response response, String realm) {
|
||||
try {
|
||||
WWWAuthenticateHeader proxyAuthenticate = headerFactory
|
||||
.createWWWAuthenticateHeader(DEFAULT_SCHEME);
|
||||
proxyAuthenticate.setParameter("realm", realm);
|
||||
proxyAuthenticate.setParameter("nonce", generateNonce());
|
||||
proxyAuthenticate.setParameter("opaque", "");
|
||||
proxyAuthenticate.setParameter("stale", "FALSE");
|
||||
proxyAuthenticate.setParameter("algorithm", DEFAULT_ALGORITHM);
|
||||
response.setHeader(proxyAuthenticate);
|
||||
} catch (Exception ex) {
|
||||
InternalErrorHandler.handleException(ex);
|
||||
}
|
||||
return response;
|
||||
}
|
||||
/**
|
||||
* Authenticate the inbound request.
|
||||
*
|
||||
* @param request - the request to authenticate.
|
||||
* @param hashedPassword -- the MD5 hashed string of username:realm:plaintext password.
|
||||
*
|
||||
* @return true if authentication succeded and false otherwise.
|
||||
*/
|
||||
public boolean doAuthenticateHashedPassword(Request request, String hashedPassword) {
|
||||
AuthorizationHeader authHeader = (AuthorizationHeader) request.getHeader(AuthorizationHeader.NAME);
|
||||
if ( authHeader == null ) return false;
|
||||
String realm = authHeader.getRealm();
|
||||
String username = authHeader.getUsername();
|
||||
|
||||
if ( username == null || realm == null ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
String nonce = authHeader.getNonce();
|
||||
URI uri = authHeader.getURI();
|
||||
if (uri == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
String A2 = request.getMethod().toUpperCase() + ":" + uri.toString();
|
||||
String HA1 = hashedPassword;
|
||||
|
||||
|
||||
byte[] mdbytes = messageDigest.digest(A2.getBytes());
|
||||
String HA2 = toHexString(mdbytes);
|
||||
|
||||
String cnonce = authHeader.getCNonce();
|
||||
String KD = HA1 + ":" + nonce;
|
||||
if (cnonce != null) {
|
||||
KD += ":" + cnonce;
|
||||
}
|
||||
KD += ":" + HA2;
|
||||
mdbytes = messageDigest.digest(KD.getBytes());
|
||||
String mdString = toHexString(mdbytes);
|
||||
String response = authHeader.getResponse();
|
||||
|
||||
|
||||
return mdString.equals(response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Authenticate the inbound request given plain text password.
|
||||
*
|
||||
* @param request - the request to authenticate.
|
||||
* @param pass -- the plain text password.
|
||||
*
|
||||
* @return true if authentication succeded and false otherwise.
|
||||
*/
|
||||
public boolean doAuthenticatePlainTextPassword(Request request, String pass) {
|
||||
AuthorizationHeader authHeader = (AuthorizationHeader) request.getHeader(AuthorizationHeader.NAME);
|
||||
if ( authHeader == null ) return false;
|
||||
String realm = authHeader.getRealm();
|
||||
String username = authHeader.getUsername();
|
||||
|
||||
|
||||
if ( username == null || realm == null ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
String nonce = authHeader.getNonce();
|
||||
URI uri = authHeader.getURI();
|
||||
if (uri == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
String A1 = username + ":" + realm + ":" + pass;
|
||||
String A2 = request.getMethod().toUpperCase() + ":" + uri.toString();
|
||||
byte mdbytes[] = messageDigest.digest(A1.getBytes());
|
||||
String HA1 = toHexString(mdbytes);
|
||||
|
||||
|
||||
mdbytes = messageDigest.digest(A2.getBytes());
|
||||
String HA2 = toHexString(mdbytes);
|
||||
|
||||
String cnonce = authHeader.getCNonce();
|
||||
String KD = HA1 + ":" + nonce;
|
||||
if (cnonce != null) {
|
||||
KD += ":" + cnonce;
|
||||
}
|
||||
KD += ":" + HA2;
|
||||
mdbytes = messageDigest.digest(KD.getBytes());
|
||||
String mdString = toHexString(mdbytes);
|
||||
String response = authHeader.getResponse();
|
||||
return mdString.equals(response);
|
||||
|
||||
}
|
||||
|
||||
}
|
126
src/main/java/com/genersoft/iot/vmp/gb28181/bean/Device.java
Normal file
126
src/main/java/com/genersoft/iot/vmp/gb28181/bean/Device.java
Normal file
@ -0,0 +1,126 @@
|
||||
package com.genersoft.iot.vmp.gb28181.bean;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
public class Device {
|
||||
|
||||
/**
|
||||
* 设备Id
|
||||
*/
|
||||
private String deviceId;
|
||||
|
||||
/**
|
||||
* 设备名
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 生产厂商
|
||||
*/
|
||||
private String manufacturer;
|
||||
|
||||
/**
|
||||
* 型号
|
||||
*/
|
||||
private String model;
|
||||
|
||||
/**
|
||||
* 固件版本
|
||||
*/
|
||||
private String firmware;
|
||||
|
||||
/**
|
||||
* 传输协议
|
||||
* UDP/TCP
|
||||
*/
|
||||
private String transport;
|
||||
|
||||
/**
|
||||
* wan地址
|
||||
*/
|
||||
private Host host;
|
||||
|
||||
/**
|
||||
* 在线
|
||||
*/
|
||||
private int online;
|
||||
|
||||
/**
|
||||
* 通道列表
|
||||
*/
|
||||
private Map<String,DeviceChannel> channelMap;
|
||||
|
||||
|
||||
public String getDeviceId() {
|
||||
return deviceId;
|
||||
}
|
||||
|
||||
public void setDeviceId(String deviceId) {
|
||||
this.deviceId = deviceId;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getTransport() {
|
||||
return transport;
|
||||
}
|
||||
|
||||
public void setTransport(String transport) {
|
||||
this.transport = transport;
|
||||
}
|
||||
|
||||
public Host getHost() {
|
||||
return host;
|
||||
}
|
||||
|
||||
public void setHost(Host host) {
|
||||
this.host = host;
|
||||
}
|
||||
|
||||
public Map<String, DeviceChannel> getChannelMap() {
|
||||
return channelMap;
|
||||
}
|
||||
|
||||
public void setChannelMap(Map<String, DeviceChannel> channelMap) {
|
||||
this.channelMap = channelMap;
|
||||
}
|
||||
|
||||
public String getManufacturer() {
|
||||
return manufacturer;
|
||||
}
|
||||
|
||||
public void setManufacturer(String manufacturer) {
|
||||
this.manufacturer = manufacturer;
|
||||
}
|
||||
|
||||
public String getModel() {
|
||||
return model;
|
||||
}
|
||||
|
||||
public void setModel(String model) {
|
||||
this.model = model;
|
||||
}
|
||||
|
||||
public String getFirmware() {
|
||||
return firmware;
|
||||
}
|
||||
|
||||
public void setFirmware(String firmware) {
|
||||
this.firmware = firmware;
|
||||
}
|
||||
|
||||
public int getOnline() {
|
||||
return online;
|
||||
}
|
||||
|
||||
public void setOnline(int online) {
|
||||
this.online = online;
|
||||
}
|
||||
}
|
@ -0,0 +1,110 @@
|
||||
package com.genersoft.iot.vmp.gb28181.bean;
|
||||
|
||||
public class DeviceAlarm {
|
||||
|
||||
/**
|
||||
* 设备Id
|
||||
*/
|
||||
private String deviceId;
|
||||
|
||||
/**
|
||||
* 报警级别, 1为一级警情, 2为二级警情, 3为三级警情, 4为四级 警情-
|
||||
*/
|
||||
private String alarmPriorit;
|
||||
|
||||
/**
|
||||
* 报警方式 , 1为电话报警, 2为设备报警, 3为短信报警, 4为 GPS报警, 5为视频报警, 6为设备故障报警,
|
||||
* 7其他报警;可以为直接组合如12为电话报警或 设备报警-
|
||||
*/
|
||||
private String alarmMethod;
|
||||
|
||||
/**
|
||||
* 报警时间
|
||||
*/
|
||||
private String alarmTime;
|
||||
|
||||
/**
|
||||
* 报警内容描述
|
||||
*/
|
||||
private String alarmDescription;
|
||||
|
||||
/**
|
||||
* 经度
|
||||
*/
|
||||
private double longitude;
|
||||
|
||||
/**
|
||||
* 纬度
|
||||
*/
|
||||
private double latitude;
|
||||
|
||||
/**
|
||||
* 报警类型
|
||||
*/
|
||||
private String alarmType;
|
||||
|
||||
public String getDeviceId() {
|
||||
return deviceId;
|
||||
}
|
||||
|
||||
public void setDeviceId(String deviceId) {
|
||||
this.deviceId = deviceId;
|
||||
}
|
||||
|
||||
public String getAlarmPriorit() {
|
||||
return alarmPriorit;
|
||||
}
|
||||
|
||||
public void setAlarmPriorit(String alarmPriorit) {
|
||||
this.alarmPriorit = alarmPriorit;
|
||||
}
|
||||
|
||||
public String getAlarmMethod() {
|
||||
return alarmMethod;
|
||||
}
|
||||
|
||||
public void setAlarmMethod(String alarmMethod) {
|
||||
this.alarmMethod = alarmMethod;
|
||||
}
|
||||
|
||||
public String getAlarmTime() {
|
||||
return alarmTime;
|
||||
}
|
||||
|
||||
public void setAlarmTime(String alarmTime) {
|
||||
this.alarmTime = alarmTime;
|
||||
}
|
||||
|
||||
public String getAlarmDescription() {
|
||||
return alarmDescription;
|
||||
}
|
||||
|
||||
public void setAlarmDescription(String alarmDescription) {
|
||||
this.alarmDescription = alarmDescription;
|
||||
}
|
||||
|
||||
public double getLongitude() {
|
||||
return longitude;
|
||||
}
|
||||
|
||||
public void setLongitude(double longitude) {
|
||||
this.longitude = longitude;
|
||||
}
|
||||
|
||||
public double getLatitude() {
|
||||
return latitude;
|
||||
}
|
||||
|
||||
public void setLatitude(double latitude) {
|
||||
this.latitude = latitude;
|
||||
}
|
||||
|
||||
public String getAlarmType() {
|
||||
return alarmType;
|
||||
}
|
||||
|
||||
public void setAlarmType(String alarmType) {
|
||||
this.alarmType = alarmType;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,309 @@
|
||||
package com.genersoft.iot.vmp.gb28181.bean;
|
||||
|
||||
public class DeviceChannel {
|
||||
|
||||
/**
|
||||
* 通道id
|
||||
*/
|
||||
private String channelId;
|
||||
|
||||
/**
|
||||
* 通道名
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 生产厂商
|
||||
*/
|
||||
private String manufacture;
|
||||
|
||||
/**
|
||||
* 型号
|
||||
*/
|
||||
private String model;
|
||||
|
||||
/**
|
||||
* 设备归属
|
||||
*/
|
||||
private String owner;
|
||||
|
||||
/**
|
||||
* 行政区域
|
||||
*/
|
||||
private String civilCode;
|
||||
|
||||
/**
|
||||
* 警区
|
||||
*/
|
||||
private String block;
|
||||
|
||||
/**
|
||||
* 安装地址
|
||||
*/
|
||||
private String address;
|
||||
|
||||
/**
|
||||
* 是否有子设备 1有, 0没有
|
||||
*/
|
||||
private int parental;
|
||||
|
||||
/**
|
||||
* 父级id
|
||||
*/
|
||||
private String parentId;
|
||||
|
||||
/**
|
||||
* 信令安全模式 缺省为0; 0:不采用; 2: S/MIME签名方式; 3: S/ MIME加密签名同时采用方式; 4:数字摘要方式
|
||||
*/
|
||||
private int safetyWay;
|
||||
|
||||
/**
|
||||
* 注册方式 缺省为1;1:符合IETFRFC3261标准的认证注册模 式; 2:基于口令的双向认证注册模式; 3:基于数字证书的双向认证注册模式
|
||||
*/
|
||||
private int registerWay;
|
||||
|
||||
/**
|
||||
* 证书序列号
|
||||
*/
|
||||
private String certNum;
|
||||
|
||||
/**
|
||||
* 证书有效标识 缺省为0;证书有效标识:0:无效1: 有效
|
||||
*/
|
||||
private int certifiable;
|
||||
|
||||
/**
|
||||
* 证书无效原因码
|
||||
*/
|
||||
private int errCode;
|
||||
|
||||
/**
|
||||
* 证书终止有效期
|
||||
*/
|
||||
private String endTime;
|
||||
|
||||
/**
|
||||
* 保密属性 缺省为0; 0:不涉密, 1:涉密
|
||||
*/
|
||||
private String secrecy;
|
||||
|
||||
/**
|
||||
* IP地址
|
||||
*/
|
||||
private String ipAddress;
|
||||
|
||||
/**
|
||||
* 端口号
|
||||
*/
|
||||
private int port;
|
||||
|
||||
/**
|
||||
* 密码
|
||||
*/
|
||||
private String password;
|
||||
|
||||
/**
|
||||
* 在线/离线
|
||||
* 1在线,0离线
|
||||
* 默认在线
|
||||
* 信令:
|
||||
* <Status>ON</Status>
|
||||
* <Status>OFF</Status>
|
||||
* 遇到过NVR下的IPC下发信令可以推流, 但是 Status 响应 OFF
|
||||
*/
|
||||
private int status;
|
||||
|
||||
/**
|
||||
* 经度
|
||||
*/
|
||||
private double longitude;
|
||||
|
||||
/**
|
||||
* 纬度
|
||||
*/
|
||||
private double latitude;
|
||||
|
||||
public String getChannelId() {
|
||||
return channelId;
|
||||
}
|
||||
|
||||
public void setChannelId(String channelId) {
|
||||
this.channelId = channelId;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public int getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(int status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public String getManufacture() {
|
||||
return manufacture;
|
||||
}
|
||||
|
||||
public void setManufacture(String manufacture) {
|
||||
this.manufacture = manufacture;
|
||||
}
|
||||
|
||||
public String getModel() {
|
||||
return model;
|
||||
}
|
||||
|
||||
public void setModel(String model) {
|
||||
this.model = model;
|
||||
}
|
||||
|
||||
public String getOwner() {
|
||||
return owner;
|
||||
}
|
||||
|
||||
public void setOwner(String owner) {
|
||||
this.owner = owner;
|
||||
}
|
||||
|
||||
public String getCivilCode() {
|
||||
return civilCode;
|
||||
}
|
||||
|
||||
public void setCivilCode(String civilCode) {
|
||||
this.civilCode = civilCode;
|
||||
}
|
||||
|
||||
public String getBlock() {
|
||||
return block;
|
||||
}
|
||||
|
||||
public void setBlock(String block) {
|
||||
this.block = block;
|
||||
}
|
||||
|
||||
public String getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
public void setAddress(String address) {
|
||||
this.address = address;
|
||||
}
|
||||
|
||||
public int getParental() {
|
||||
return parental;
|
||||
}
|
||||
|
||||
public void setParental(int parental) {
|
||||
this.parental = parental;
|
||||
}
|
||||
|
||||
public String getParentId() {
|
||||
return parentId;
|
||||
}
|
||||
|
||||
public void setParentId(String parentId) {
|
||||
this.parentId = parentId;
|
||||
}
|
||||
|
||||
public int getSafetyWay() {
|
||||
return safetyWay;
|
||||
}
|
||||
|
||||
public void setSafetyWay(int safetyWay) {
|
||||
this.safetyWay = safetyWay;
|
||||
}
|
||||
|
||||
public int getRegisterWay() {
|
||||
return registerWay;
|
||||
}
|
||||
|
||||
public void setRegisterWay(int registerWay) {
|
||||
this.registerWay = registerWay;
|
||||
}
|
||||
|
||||
public String getCertNum() {
|
||||
return certNum;
|
||||
}
|
||||
|
||||
public void setCertNum(String certNum) {
|
||||
this.certNum = certNum;
|
||||
}
|
||||
|
||||
public int getCertifiable() {
|
||||
return certifiable;
|
||||
}
|
||||
|
||||
public void setCertifiable(int certifiable) {
|
||||
this.certifiable = certifiable;
|
||||
}
|
||||
|
||||
public int getErrCode() {
|
||||
return errCode;
|
||||
}
|
||||
|
||||
public void setErrCode(int errCode) {
|
||||
this.errCode = errCode;
|
||||
}
|
||||
|
||||
public String getEndTime() {
|
||||
return endTime;
|
||||
}
|
||||
|
||||
public void setEndTime(String endTime) {
|
||||
this.endTime = endTime;
|
||||
}
|
||||
|
||||
public String getSecrecy() {
|
||||
return secrecy;
|
||||
}
|
||||
|
||||
public void setSecrecy(String secrecy) {
|
||||
this.secrecy = secrecy;
|
||||
}
|
||||
|
||||
public String getIpAddress() {
|
||||
return ipAddress;
|
||||
}
|
||||
|
||||
public void setIpAddress(String ipAddress) {
|
||||
this.ipAddress = ipAddress;
|
||||
}
|
||||
|
||||
public int getPort() {
|
||||
return port;
|
||||
}
|
||||
|
||||
public void setPort(int port) {
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public double getLongitude() {
|
||||
return longitude;
|
||||
}
|
||||
|
||||
public void setLongitude(double longitude) {
|
||||
this.longitude = longitude;
|
||||
}
|
||||
|
||||
public double getLatitude() {
|
||||
return latitude;
|
||||
}
|
||||
|
||||
public void setLatitude(double latitude) {
|
||||
this.latitude = latitude;
|
||||
}
|
||||
}
|
30
src/main/java/com/genersoft/iot/vmp/gb28181/bean/Host.java
Normal file
30
src/main/java/com/genersoft/iot/vmp/gb28181/bean/Host.java
Normal file
@ -0,0 +1,30 @@
|
||||
package com.genersoft.iot.vmp.gb28181.bean;
|
||||
|
||||
public class Host {
|
||||
|
||||
private String ip;
|
||||
private int port;
|
||||
private String address;
|
||||
|
||||
public String getIp() {
|
||||
return ip;
|
||||
}
|
||||
public void setIp(String ip) {
|
||||
this.ip = ip;
|
||||
}
|
||||
public int getPort() {
|
||||
return port;
|
||||
}
|
||||
public void setPort(int port) {
|
||||
this.port = port;
|
||||
}
|
||||
public String getAddress() {
|
||||
return address;
|
||||
}
|
||||
public void setAddress(String address) {
|
||||
this.address = address;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
package com.genersoft.iot.vmp.gb28181.event;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.genersoft.iot.vmp.gb28181.event.online.OnlineEvent;
|
||||
import com.genersoft.iot.vmp.gb28181.event.outline.OutlineEvent;
|
||||
|
||||
/**
|
||||
* @Description:Event事件通知推送器,支持推送在线事件、离线事件
|
||||
* @author: songww
|
||||
* @date: 2020年5月6日 上午11:30:50
|
||||
*/
|
||||
@Component
|
||||
public class EventPublisher {
|
||||
|
||||
@Autowired
|
||||
private ApplicationEventPublisher applicationEventPublisher;
|
||||
|
||||
public void onlineEventPublish(String deviceId, String from) {
|
||||
OnlineEvent onEvent = new OnlineEvent(this);
|
||||
onEvent.setDeviceId(deviceId);
|
||||
onEvent.setFrom(from);
|
||||
applicationEventPublisher.publishEvent(onEvent);
|
||||
}
|
||||
|
||||
public void outlineEventPublish(String deviceId, String from){
|
||||
OutlineEvent outEvent = new OutlineEvent(this);
|
||||
outEvent.setDeviceId(deviceId);
|
||||
outEvent.setFrom(from);
|
||||
applicationEventPublisher.publishEvent(outEvent);
|
||||
}
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
package com.genersoft.iot.vmp.gb28181.event.online;
|
||||
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
|
||||
/**
|
||||
* @Description:TODO(这里用一句话描述这个类的作用)
|
||||
* @author: songww
|
||||
* @date: 2020年5月6日 上午11:32:56
|
||||
*/
|
||||
public class OnlineEvent extends ApplicationEvent {
|
||||
|
||||
/**
|
||||
* @Title: OnlineEvent
|
||||
* @Description: TODO(这里用一句话描述这个方法的作用)
|
||||
* @param: @param source
|
||||
* @throws
|
||||
*/
|
||||
public OnlineEvent(Object source) {
|
||||
super(source);
|
||||
}
|
||||
|
||||
private String deviceId;
|
||||
|
||||
private String from;
|
||||
|
||||
public String getDeviceId() {
|
||||
return deviceId;
|
||||
}
|
||||
|
||||
public void setDeviceId(String deviceId) {
|
||||
this.deviceId = deviceId;
|
||||
}
|
||||
|
||||
public String getFrom() {
|
||||
return from;
|
||||
}
|
||||
|
||||
public void setFrom(String from) {
|
||||
this.from = from;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
package com.genersoft.iot.vmp.gb28181.event.online;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.genersoft.iot.vmp.common.VideoManagerConstants;
|
||||
import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
|
||||
import com.genersoft.iot.vmp.utils.redis.RedisUtil;
|
||||
|
||||
/**
|
||||
* @Description: 在线事件监听器,监听到离线后,修改设备离在线状态。 设备在线有两个来源:
|
||||
* 1、设备主动注销,发送注销指令,{@link com.genersoft.iot.vmp.gb28181.transmit.request.impl.RegisterRequestProcessor}
|
||||
* 2、设备未知原因离线,心跳超时,{@link com.genersoft.iot.vmp.gb28181.transmit.request.impl.MessageRequestProcessor}
|
||||
* @author: songww
|
||||
* @date: 2020年5月6日 下午1:51:23
|
||||
*/
|
||||
@Component
|
||||
public class OnlineEventListener implements ApplicationListener<OnlineEvent> {
|
||||
|
||||
private final static Logger logger = LoggerFactory.getLogger(OnlineEventListener.class);
|
||||
|
||||
@Autowired
|
||||
private IVideoManagerStorager storager;
|
||||
|
||||
@Autowired
|
||||
private RedisUtil redis;
|
||||
|
||||
@Override
|
||||
public void onApplicationEvent(OnlineEvent event) {
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("设备离线事件触发,deviceId:" + event.getDeviceId() + ",from:" + event.getFrom());
|
||||
}
|
||||
|
||||
String key = VideoManagerConstants.KEEPLIVEKEY_PREFIX + event.getDeviceId();
|
||||
boolean needUpdateStorager = false;
|
||||
|
||||
switch (event.getFrom()) {
|
||||
// 注册时触发的在线事件,先在redis中增加超时超时监听
|
||||
case VideoManagerConstants.EVENT_ONLINE_REGISTER:
|
||||
// TODO 超时时间暂时写死为180秒
|
||||
redis.set(key, event.getDeviceId(), 180);
|
||||
needUpdateStorager = true;
|
||||
break;
|
||||
// 设备主动发送心跳触发的离线事件
|
||||
case VideoManagerConstants.EVENT_ONLINE_KEEPLIVE:
|
||||
boolean exist = redis.hasKey(key);
|
||||
// 先判断是否还存在,当设备先心跳超时后又发送心跳时,redis没有监听,需要增加
|
||||
if (!exist) {
|
||||
needUpdateStorager = true;
|
||||
redis.set(key, event.getDeviceId(), 180);
|
||||
} else {
|
||||
redis.expire(key, 180);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (needUpdateStorager) {
|
||||
// 处理离线监听
|
||||
storager.online(event.getDeviceId());
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
package com.genersoft.iot.vmp.gb28181.event.outline;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.redis.connection.Message;
|
||||
import org.springframework.data.redis.listener.KeyExpirationEventMessageListener;
|
||||
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.genersoft.iot.vmp.common.VideoManagerConstants;
|
||||
import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
|
||||
|
||||
/**
|
||||
* @Description:设备心跳超时监听,借助redis过期特性,进行监听,监听到说明设备心跳超时,发送离线事件
|
||||
* @author: songww
|
||||
* @date: 2020年5月6日 上午11:35:46
|
||||
*/
|
||||
@Component
|
||||
public class KeepliveTimeoutListener extends KeyExpirationEventMessageListener {
|
||||
|
||||
@Autowired
|
||||
private EventPublisher publisher;
|
||||
|
||||
public KeepliveTimeoutListener(RedisMessageListenerContainer listenerContainer) {
|
||||
super(listenerContainer);
|
||||
}
|
||||
|
||||
/**
|
||||
* 监听失效的key,key格式为keeplive_deviceId
|
||||
* @param message
|
||||
* @param pattern
|
||||
*/
|
||||
@Override
|
||||
public void onMessage(Message message, byte[] pattern) {
|
||||
// 获取失效的key
|
||||
String expiredKey = message.toString();
|
||||
if(!expiredKey.startsWith(VideoManagerConstants.KEEPLIVEKEY_PREFIX)){
|
||||
System.out.println("收到redis过期监听,但开头不是"+VideoManagerConstants.KEEPLIVEKEY_PREFIX+",忽略");
|
||||
return;
|
||||
}
|
||||
|
||||
String deviceId = expiredKey.substring(VideoManagerConstants.KEEPLIVEKEY_PREFIX.length(),expiredKey.length());
|
||||
publisher.outlineEventPublish(deviceId, VideoManagerConstants.EVENT_OUTLINE_TIMEOUT);
|
||||
}
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
package com.genersoft.iot.vmp.gb28181.event.outline;
|
||||
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
|
||||
/**
|
||||
* @Description:TODO(这里用一句话描述这个类的作用)
|
||||
* @author: songww
|
||||
* @date: 2020年5月6日 上午11:33:13
|
||||
*/
|
||||
public class OutlineEvent extends ApplicationEvent {
|
||||
|
||||
/**
|
||||
* @Title: OutlineEvent
|
||||
* @Description: TODO(这里用一句话描述这个方法的作用)
|
||||
* @param: @param source
|
||||
* @throws
|
||||
*/
|
||||
public OutlineEvent(Object source) {
|
||||
super(source);
|
||||
}
|
||||
|
||||
private String deviceId;
|
||||
|
||||
private String from;
|
||||
|
||||
public String getDeviceId() {
|
||||
return deviceId;
|
||||
}
|
||||
|
||||
public void setDeviceId(String deviceId) {
|
||||
this.deviceId = deviceId;
|
||||
}
|
||||
|
||||
public String getFrom() {
|
||||
return from;
|
||||
}
|
||||
|
||||
public void setFrom(String from) {
|
||||
this.from = from;
|
||||
}
|
||||
}
|
@ -0,0 +1,58 @@
|
||||
package com.genersoft.iot.vmp.gb28181.event.outline;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.genersoft.iot.vmp.common.VideoManagerConstants;
|
||||
import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
|
||||
import com.genersoft.iot.vmp.utils.redis.RedisUtil;
|
||||
|
||||
/**
|
||||
* @Description: 离线事件监听器,监听到离线后,修改设备离在线状态。 设备离线有两个来源:
|
||||
* 1、设备主动注销,发送注销指令,{@link com.genersoft.iot.vmp.gb28181.transmit.request.impl.RegisterRequestProcessor}
|
||||
* 2、设备未知原因离线,心跳超时,{@link com.genersoft.iot.vmp.gb28181.event.outline.OutlineEventListener}
|
||||
* @author: songww
|
||||
* @date: 2020年5月6日 下午1:51:23
|
||||
*/
|
||||
@Component
|
||||
public class OutlineEventListener implements ApplicationListener<OutlineEvent> {
|
||||
|
||||
private final static Logger logger = LoggerFactory.getLogger(OutlineEventListener.class);
|
||||
|
||||
@Autowired
|
||||
private IVideoManagerStorager storager;
|
||||
|
||||
@Autowired
|
||||
private RedisUtil redis;
|
||||
|
||||
@Override
|
||||
public void onApplicationEvent(OutlineEvent event) {
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("设备离线事件触发,deviceId:" + event.getDeviceId() + ",from:" + event.getFrom());
|
||||
}
|
||||
|
||||
String key = VideoManagerConstants.KEEPLIVEKEY_PREFIX + event.getDeviceId();
|
||||
|
||||
switch (event.getFrom()) {
|
||||
// 心跳超时触发的离线事件,说明redis中已删除,无需处理
|
||||
case VideoManagerConstants.EVENT_OUTLINE_TIMEOUT:
|
||||
break;
|
||||
// 设备主动注销触发的离线事件,需要删除redis中的超时监听
|
||||
case VideoManagerConstants.EVENT_OUTLINE_UNREGISTER:
|
||||
redis.del(key);
|
||||
break;
|
||||
default:
|
||||
boolean exist = redis.hasKey(key);
|
||||
if (exist) {
|
||||
redis.del(key);
|
||||
}
|
||||
}
|
||||
|
||||
// 处理离线监听
|
||||
storager.outline(event.getDeviceId());
|
||||
}
|
||||
}
|
@ -0,0 +1,110 @@
|
||||
package com.genersoft.iot.vmp.gb28181.transmit;
|
||||
|
||||
import javax.sip.RequestEvent;
|
||||
import javax.sip.ResponseEvent;
|
||||
import javax.sip.header.CSeqHeader;
|
||||
import javax.sip.message.Request;
|
||||
import javax.sip.message.Response;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
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.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;
|
||||
|
||||
/**
|
||||
* @Description:TODO(这里用一句话描述这个类的作用)
|
||||
* @author: songww
|
||||
* @date: 2020年5月3日 下午4:24:37
|
||||
*/
|
||||
@Component
|
||||
public class SIPProcessorFactory {
|
||||
|
||||
@Autowired
|
||||
private InviteRequestProcessor inviteRequestProcessor;
|
||||
|
||||
@Autowired
|
||||
private RegisterRequestProcessor registerRequestProcessor;
|
||||
|
||||
@Autowired
|
||||
private SubscribeRequestProcessor subscribeRequestProcessor;
|
||||
|
||||
@Autowired
|
||||
private AckRequestProcessor ackRequestProcessor;
|
||||
|
||||
@Autowired
|
||||
private ByeRequestProcessor byeRequestProcessor;
|
||||
|
||||
@Autowired
|
||||
private CancelRequestProcessor cancelRequestProcessor;
|
||||
|
||||
@Autowired
|
||||
private MessageRequestProcessor messageRequestProcessor;
|
||||
|
||||
@Autowired
|
||||
private OtherRequestProcessor otherRequestProcessor;
|
||||
|
||||
@Autowired
|
||||
private InviteResponseProcessor inviteResponseProcessor;
|
||||
|
||||
@Autowired
|
||||
private ByeResponseProcessor byeResponseProcessor;
|
||||
|
||||
@Autowired
|
||||
private CancelResponseProcessor cancelResponseProcessor;
|
||||
|
||||
@Autowired
|
||||
private OtherResponseProcessor otherResponseProcessor;
|
||||
|
||||
|
||||
public ISIPRequestProcessor createRequestProcessor(RequestEvent evt) {
|
||||
Request request = evt.getRequest();
|
||||
String method = request.getMethod();
|
||||
|
||||
if (Request.INVITE.equals(method)) {
|
||||
return inviteRequestProcessor;
|
||||
} else if (Request.REGISTER.equals(method)) {
|
||||
return registerRequestProcessor;
|
||||
} else if (Request.SUBSCRIBE.equals(method)) {
|
||||
return subscribeRequestProcessor;
|
||||
} else if (Request.ACK.equals(method)) {
|
||||
return ackRequestProcessor;
|
||||
} else if (Request.BYE.equals(method)) {
|
||||
return byeRequestProcessor;
|
||||
} else if (Request.CANCEL.equals(method)) {
|
||||
return cancelRequestProcessor;
|
||||
} else if (Request.MESSAGE.equals(method)) {
|
||||
return messageRequestProcessor;
|
||||
} else {
|
||||
return otherRequestProcessor;
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
return otherResponseProcessor;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,183 @@
|
||||
package com.genersoft.iot.vmp.gb28181.transmit.cmd;
|
||||
|
||||
import com.genersoft.iot.vmp.gb28181.bean.Device;
|
||||
|
||||
/**
|
||||
* @Description:设备能力接口,用于定义设备的控制、查询能力
|
||||
* @author: songww
|
||||
* @date: 2020年5月3日 下午9:16:34
|
||||
*/
|
||||
public interface ISIPCommander {
|
||||
|
||||
/**
|
||||
* 云台方向放控制,使用配置文件中的默认镜头移动速度
|
||||
*
|
||||
* @param deviceId 控制设备
|
||||
* @param channelId 预览通道
|
||||
* @param leftRight 镜头左移右移 0:停止 1:左移 2:右移
|
||||
* @param upDown 镜头上移下移 0:停止 1:上移 2:下移
|
||||
* @param moveSpeed 镜头移动速度
|
||||
*/
|
||||
public boolean ptzdirectCmd(String deviceId,String channelId,int leftRight, int upDown);
|
||||
|
||||
/**
|
||||
* 云台方向放控制
|
||||
*
|
||||
* @param deviceId 控制设备
|
||||
* @param channelId 预览通道
|
||||
* @param leftRight 镜头左移右移 0:停止 1:左移 2:右移
|
||||
* @param upDown 镜头上移下移 0:停止 1:上移 2:下移
|
||||
* @param moveSpeed 镜头移动速度
|
||||
*/
|
||||
public boolean ptzdirectCmd(String deviceId,String channelId,int leftRight, int upDown, int moveSpeed);
|
||||
|
||||
/**
|
||||
* 云台缩放控制,使用配置文件中的默认镜头缩放速度
|
||||
*
|
||||
* @param deviceId 控制设备
|
||||
* @param channelId 预览通道
|
||||
* @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大
|
||||
*/
|
||||
public boolean ptzZoomCmd(String deviceId,String channelId,int inOut);
|
||||
|
||||
/**
|
||||
* 云台缩放控制
|
||||
*
|
||||
* @param deviceId 控制设备
|
||||
* @param channelId 预览通道
|
||||
* @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大
|
||||
* @param zoomSpeed 镜头缩放速度
|
||||
*/
|
||||
public boolean ptzZoomCmd(String deviceId,String channelId,int inOut, int moveSpeed);
|
||||
|
||||
/**
|
||||
* 云台控制,支持方向与缩放控制
|
||||
*
|
||||
* @param deviceId 控制设备
|
||||
* @param channelId 预览通道
|
||||
* @param leftRight 镜头左移右移 0:停止 1:左移 2:右移
|
||||
* @param upDown 镜头上移下移 0:停止 1:上移 2:下移
|
||||
* @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大
|
||||
* @param moveSpeed 镜头移动速度
|
||||
* @param zoomSpeed 镜头缩放速度
|
||||
*/
|
||||
public boolean ptzCmd(String deviceId,String channelId,int leftRight, int upDown, int inOut, int moveSpeed, int zoomSpeed);
|
||||
|
||||
/**
|
||||
* 请求预览视频流
|
||||
*
|
||||
* @param deviceId 视频设备
|
||||
* @param channelId 预览通道
|
||||
*/
|
||||
public String playStreamCmd(String deviceId,String channelId);
|
||||
|
||||
/**
|
||||
* 语音广播
|
||||
*
|
||||
* @param deviceId 视频设备
|
||||
* @param channelId 预览通道
|
||||
*/
|
||||
public String audioBroadcastCmd(String deviceId,String channelId);
|
||||
|
||||
/**
|
||||
* 音视频录像控制
|
||||
*
|
||||
* @param deviceId 视频设备
|
||||
* @param channelId 预览通道
|
||||
*/
|
||||
public String recordCmd(String deviceId,String channelId);
|
||||
|
||||
/**
|
||||
* 报警布防/撤防命令
|
||||
*
|
||||
* @param deviceId 视频设备
|
||||
*/
|
||||
public String guardCmd(String deviceId);
|
||||
|
||||
/**
|
||||
* 报警复位命令
|
||||
*
|
||||
* @param deviceId 视频设备
|
||||
*/
|
||||
public String alarmCmd(String deviceId);
|
||||
|
||||
/**
|
||||
* 强制关键帧命令,设备收到此命令应立刻发送一个IDR帧
|
||||
*
|
||||
* @param deviceId 视频设备
|
||||
* @param channelId 预览通道
|
||||
*/
|
||||
public String iFameCmd(String deviceId,String channelId);
|
||||
|
||||
/**
|
||||
* 看守位控制命令
|
||||
*
|
||||
* @param deviceId 视频设备
|
||||
*/
|
||||
public String homePositionCmd(String deviceId);
|
||||
|
||||
/**
|
||||
* 设备配置命令
|
||||
*
|
||||
* @param deviceId 视频设备
|
||||
*/
|
||||
public String deviceConfigCmd(String deviceId);
|
||||
|
||||
|
||||
/**
|
||||
* 查询设备状态
|
||||
*
|
||||
* @param device 视频设备
|
||||
*/
|
||||
public boolean deviceStatusQuery(Device device);
|
||||
|
||||
/**
|
||||
* 查询设备信息
|
||||
*
|
||||
* @param device 视频设备
|
||||
* @return
|
||||
*/
|
||||
public boolean deviceInfoQuery(Device device);
|
||||
|
||||
/**
|
||||
* 查询目录列表
|
||||
*
|
||||
* @param device 视频设备
|
||||
*/
|
||||
public boolean catalogQuery(Device device);
|
||||
|
||||
/**
|
||||
* 查询录像信息
|
||||
*
|
||||
* @param device 视频设备
|
||||
*/
|
||||
public boolean recordInfoQuery(Device device);
|
||||
|
||||
/**
|
||||
* 查询报警信息
|
||||
*
|
||||
* @param device 视频设备
|
||||
*/
|
||||
public boolean alarmInfoQuery(Device device);
|
||||
|
||||
/**
|
||||
* 查询设备配置
|
||||
*
|
||||
* @param device 视频设备
|
||||
*/
|
||||
public boolean configQuery(Device device);
|
||||
|
||||
/**
|
||||
* 查询设备预置位置
|
||||
*
|
||||
* @param device 视频设备
|
||||
*/
|
||||
public boolean presetQuery(Device device);
|
||||
|
||||
/**
|
||||
* 查询移动设备位置数据
|
||||
*
|
||||
* @param device 视频设备
|
||||
*/
|
||||
public boolean mobilePostitionQuery(Device device);
|
||||
}
|
@ -0,0 +1,111 @@
|
||||
package com.genersoft.iot.vmp.gb28181.transmit.cmd;
|
||||
|
||||
import java.text.ParseException;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import javax.sip.InvalidArgumentException;
|
||||
import javax.sip.address.Address;
|
||||
import javax.sip.address.SipURI;
|
||||
import javax.sip.header.CSeqHeader;
|
||||
import javax.sip.header.CallIdHeader;
|
||||
import javax.sip.header.ContentTypeHeader;
|
||||
import javax.sip.header.FromHeader;
|
||||
import javax.sip.header.MaxForwardsHeader;
|
||||
import javax.sip.header.ToHeader;
|
||||
import javax.sip.header.ViaHeader;
|
||||
import javax.sip.message.Request;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.genersoft.iot.vmp.conf.SipConfig;
|
||||
import com.genersoft.iot.vmp.gb28181.SipLayer;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.Device;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.Host;
|
||||
|
||||
/**
|
||||
* @Description:TODO(这里用一句话描述这个类的作用)
|
||||
* @author: songww
|
||||
* @date: 2020年5月6日 上午9:29:02
|
||||
*/
|
||||
@Component
|
||||
public class SIPRequestHeaderProvider {
|
||||
|
||||
@Autowired
|
||||
private SipLayer layer;
|
||||
|
||||
@Autowired
|
||||
private SipConfig config;
|
||||
|
||||
public Request createMessageRequest(Device device, String content, String viaTag, String fromTag, String toTag) throws ParseException, InvalidArgumentException {
|
||||
Request request = null;
|
||||
Host host = device.getHost();
|
||||
// sipuri
|
||||
SipURI requestURI = layer.getAddressFactory().createSipURI(device.getDeviceId(), host.getAddress());
|
||||
// via
|
||||
ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();
|
||||
ViaHeader viaHeader = layer.getHeaderFactory().createViaHeader(config.getSipIp(), config.getSipPort(),
|
||||
device.getTransport(), viaTag);
|
||||
viaHeaders.add(viaHeader);
|
||||
// from
|
||||
SipURI fromSipURI = layer.getAddressFactory().createSipURI(device.getDeviceId(),
|
||||
config.getSipIp() + ":" + config.getSipPort());
|
||||
Address fromAddress = layer.getAddressFactory().createAddress(fromSipURI);
|
||||
FromHeader fromHeader = layer.getHeaderFactory().createFromHeader(fromAddress, fromTag);
|
||||
// to
|
||||
SipURI toSipURI = layer.getAddressFactory().createSipURI(device.getDeviceId(), host.getAddress());
|
||||
Address toAddress = layer.getAddressFactory().createAddress(toSipURI);
|
||||
ToHeader toHeader = layer.getHeaderFactory().createToHeader(toAddress, toTag);
|
||||
// callid
|
||||
CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? layer.getTcpSipProvider().getNewCallId()
|
||||
: layer.getUdpSipProvider().getNewCallId();
|
||||
// Forwards
|
||||
MaxForwardsHeader maxForwards = layer.getHeaderFactory().createMaxForwardsHeader(70);
|
||||
// ceq
|
||||
CSeqHeader cSeqHeader = layer.getHeaderFactory().createCSeqHeader(1L, Request.MESSAGE);
|
||||
|
||||
request = layer.getMessageFactory().createRequest(requestURI, Request.MESSAGE, callIdHeader, cSeqHeader, fromHeader,
|
||||
toHeader, viaHeaders, maxForwards);
|
||||
ContentTypeHeader contentTypeHeader = layer.getHeaderFactory().createContentTypeHeader("Application", "MANSCDP+xml");
|
||||
request.setContent(content, contentTypeHeader);
|
||||
return request;
|
||||
}
|
||||
|
||||
public Request createInviteRequest(Device device, String content, String viaTag, String fromTag, String toTag) throws ParseException, InvalidArgumentException {
|
||||
Request request = null;
|
||||
Host host = device.getHost();
|
||||
//请求行
|
||||
SipURI requestLine = layer.getAddressFactory().createSipURI(device.getDeviceId(), host.getAddress());
|
||||
//via
|
||||
ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();
|
||||
ViaHeader viaHeader = layer.getHeaderFactory().createViaHeader(config.getSipIp(), config.getSipPort(), device.getTransport(), viaTag);
|
||||
viaHeader.setRPort();
|
||||
viaHeaders.add(viaHeader);
|
||||
//from
|
||||
SipURI fromSipURI = layer.getAddressFactory().createSipURI(device.getDeviceId(),config.getSipIp()+":"+config.getSipPort());
|
||||
Address fromAddress = layer.getAddressFactory().createAddress(fromSipURI);
|
||||
FromHeader fromHeader = layer.getHeaderFactory().createFromHeader(fromAddress, fromTag); //必须要有标记,否则无法创建会话,无法回应ack
|
||||
//to
|
||||
SipURI toSipURI = layer.getAddressFactory().createSipURI(device.getDeviceId(),host.getAddress());
|
||||
Address toAddress = layer.getAddressFactory().createAddress(toSipURI);
|
||||
ToHeader toHeader = layer.getHeaderFactory().createToHeader(toAddress,null);
|
||||
|
||||
//callid
|
||||
CallIdHeader callIdHeader = null;
|
||||
if(device.getTransport().equals("TCP")) {
|
||||
callIdHeader = layer.getTcpSipProvider().getNewCallId();
|
||||
}
|
||||
if(device.getTransport().equals("UDP")) {
|
||||
callIdHeader = layer.getUdpSipProvider().getNewCallId();
|
||||
}
|
||||
|
||||
//Forwards
|
||||
MaxForwardsHeader maxForwards = layer.getHeaderFactory().createMaxForwardsHeader(70);
|
||||
//ceq
|
||||
CSeqHeader cSeqHeader = layer.getHeaderFactory().createCSeqHeader(1L, Request.INVITE);
|
||||
request = layer.getMessageFactory().createRequest(requestLine, Request.INVITE, callIdHeader, cSeqHeader,fromHeader, toHeader, viaHeaders, maxForwards);
|
||||
ContentTypeHeader contentTypeHeader = layer.getHeaderFactory().createContentTypeHeader("Application", "SDP");
|
||||
request.setContent(content, contentTypeHeader);
|
||||
return request;
|
||||
}
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
package com.genersoft.iot.vmp.gb28181.transmit.cmd.impl;
|
||||
|
||||
public class PtzCmdHelper {
|
||||
/**
|
||||
*
|
||||
* @param leftRight 镜头左移右移 0:停止 1:左移 2:右移
|
||||
* @param upDown 镜头上移下移 0:停止 1:上移 2:下移
|
||||
* @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大
|
||||
* @param moveSpeed 镜头移动速度 默认 0XFF (0-255)
|
||||
* @param zoomSpeed 镜头缩放速度 默认 0X1 (0-255)
|
||||
* @return
|
||||
*/
|
||||
//云台控制发送了消息,相机会一直执行,直到其他命令或者发送了停止命令,切记要考虑这个机制
|
||||
public static String create(int leftRight, int upDown, int inOut, int moveSpeed, int zoomSpeed) {
|
||||
int cmdCode = 0;
|
||||
if (leftRight == 2) cmdCode|=0x01; // 右移
|
||||
else if(leftRight == 1) cmdCode|=0x02; // 左移
|
||||
if (upDown == 2) cmdCode|=0x04; // 下移
|
||||
else if(upDown == 1) cmdCode|=0x08; // 上移
|
||||
if (inOut == 2) cmdCode |= 0x10; // 放大
|
||||
else if(inOut == 1) cmdCode |= 0x20; // 缩小
|
||||
char[] szCmd = new char[16];
|
||||
String strTmp;
|
||||
szCmd[0] = 'A'; //字节1 A5
|
||||
szCmd[1] = '5';
|
||||
szCmd[2] = '0'; //字节2 0F
|
||||
szCmd[3] = 'F';
|
||||
szCmd[4] = '0'; //字节3 地址的低8位
|
||||
szCmd[5] = '1';
|
||||
strTmp = String.format("%02X", cmdCode);
|
||||
szCmd[6] = strTmp.charAt(0); //字节4 控制码
|
||||
szCmd[7] = strTmp.charAt(1);
|
||||
strTmp = String.format("%02X", moveSpeed);
|
||||
szCmd[8] = strTmp.charAt(0); //字节5 水平控制速度
|
||||
szCmd[9] = strTmp.charAt(1);
|
||||
szCmd[10] = strTmp.charAt(0); //字节6 垂直控制速度
|
||||
szCmd[11] = strTmp.charAt(1);
|
||||
strTmp = String.format("%X", zoomSpeed);
|
||||
szCmd[12] = strTmp.charAt(0); //字节7高4位 缩放控制速度
|
||||
szCmd[13] = '0'; //字节7低4位 地址的高4位
|
||||
//计算校验码
|
||||
int nCheck = (0XA5 + 0X0F + 0X01 + cmdCode + moveSpeed + moveSpeed + (zoomSpeed << 4 & 0XF0)) % 0X100;
|
||||
strTmp = String.format("%02X", nCheck);
|
||||
szCmd[14] = strTmp.charAt(0); //字节8 校验码
|
||||
szCmd[15] = strTmp.charAt(1);
|
||||
return String.valueOf(szCmd);
|
||||
}
|
||||
}
|
@ -0,0 +1,387 @@
|
||||
package com.genersoft.iot.vmp.gb28181.transmit.cmd.impl;
|
||||
|
||||
import java.text.ParseException;
|
||||
import java.util.Random;
|
||||
|
||||
import javax.sip.InvalidArgumentException;
|
||||
import javax.sip.SipException;
|
||||
import javax.sip.message.Request;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.genersoft.iot.vmp.conf.SipConfig;
|
||||
import com.genersoft.iot.vmp.gb28181.SipLayer;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.Device;
|
||||
import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander;
|
||||
import com.genersoft.iot.vmp.gb28181.transmit.cmd.SIPRequestHeaderProvider;
|
||||
import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
|
||||
|
||||
/**
|
||||
* @Description:设备能力接口,用于定义设备的控制、查询能力
|
||||
* @author: songww
|
||||
* @date: 2020年5月3日 下午9:22:48
|
||||
*/
|
||||
@Component
|
||||
public class SIPCommander implements ISIPCommander {
|
||||
|
||||
@Autowired
|
||||
private SipConfig config;
|
||||
|
||||
@Autowired
|
||||
private SIPRequestHeaderProvider headerProvider;
|
||||
|
||||
@Autowired
|
||||
private SipLayer sipLayer;
|
||||
|
||||
@Autowired
|
||||
private IVideoManagerStorager storager;
|
||||
|
||||
/**
|
||||
* 云台方向放控制,使用配置文件中的默认镜头移动速度
|
||||
*
|
||||
* @param deviceId 控制设备
|
||||
* @param channelId 预览通道
|
||||
* @param leftRight 镜头左移右移 0:停止 1:左移 2:右移
|
||||
* @param upDown 镜头上移下移 0:停止 1:上移 2:下移
|
||||
* @param moveSpeed 镜头移动速度
|
||||
*/
|
||||
@Override
|
||||
public boolean ptzdirectCmd(String deviceId, String channelId, int leftRight, int upDown) {
|
||||
return ptzCmd(deviceId, channelId, leftRight, upDown, 0, config.getSpeed(), 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 云台方向放控制
|
||||
*
|
||||
* @param deviceId 控制设备
|
||||
* @param channelId 预览通道
|
||||
* @param leftRight 镜头左移右移 0:停止 1:左移 2:右移
|
||||
* @param upDown 镜头上移下移 0:停止 1:上移 2:下移
|
||||
* @param moveSpeed 镜头移动速度
|
||||
*/
|
||||
@Override
|
||||
public boolean ptzdirectCmd(String deviceId, String channelId, int leftRight, int upDown, int moveSpeed) {
|
||||
return ptzCmd(deviceId, channelId, leftRight, upDown, 0, moveSpeed, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 云台缩放控制,使用配置文件中的默认镜头缩放速度
|
||||
*
|
||||
* @param deviceId 控制设备
|
||||
* @param channelId 预览通道
|
||||
* @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大
|
||||
*/
|
||||
@Override
|
||||
public boolean ptzZoomCmd(String deviceId, String channelId, int inOut) {
|
||||
return ptzCmd(deviceId, channelId, 0, 0, inOut, 0, config.getSpeed());
|
||||
}
|
||||
|
||||
/**
|
||||
* 云台缩放控制
|
||||
*
|
||||
* @param deviceId 控制设备
|
||||
* @param channelId 预览通道
|
||||
* @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大
|
||||
* @param zoomSpeed 镜头缩放速度
|
||||
*/
|
||||
@Override
|
||||
public boolean ptzZoomCmd(String deviceId, String channelId, int inOut, int zoomSpeed) {
|
||||
return ptzCmd(deviceId, channelId, 0, 0, inOut, 0, zoomSpeed);
|
||||
}
|
||||
|
||||
/**
|
||||
* 云台控制,支持方向与缩放控制
|
||||
*
|
||||
* @param deviceId 控制设备
|
||||
* @param channelId 预览通道
|
||||
* @param leftRight 镜头左移右移 0:停止 1:左移 2:右移
|
||||
* @param upDown 镜头上移下移 0:停止 1:上移 2:下移
|
||||
* @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大
|
||||
* @param moveSpeed 镜头移动速度
|
||||
* @param zoomSpeed 镜头缩放速度
|
||||
*/
|
||||
@Override
|
||||
public boolean ptzCmd(String deviceId, String channelId, int leftRight, int upDown, int inOut, int moveSpeed,
|
||||
int zoomSpeed) {
|
||||
try {
|
||||
Device device = storager.queryVideoDevice(deviceId);
|
||||
StringBuffer ptzXml = new StringBuffer(200);
|
||||
ptzXml.append("<?xml version=\"1.0\" ?>");
|
||||
ptzXml.append("<Control>");
|
||||
ptzXml.append("<CmdType>DeviceControl</CmdType>");
|
||||
ptzXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>");
|
||||
ptzXml.append("<DeviceID>" + channelId + "</DeviceID>");
|
||||
ptzXml.append("<PTZCmd>" + PtzCmdHelper.create(leftRight, upDown, inOut, moveSpeed, zoomSpeed) + "</PTZCmd>");
|
||||
ptzXml.append("<Info>");
|
||||
ptzXml.append("</Info>");
|
||||
ptzXml.append("</Control>");
|
||||
|
||||
Request request = headerProvider.createMessageRequest(device, ptzXml.toString(), "ViaPtzBranch", "FromPtzTag", "ToPtzTag");
|
||||
|
||||
transmitRequest(device.getTransport(), request);
|
||||
|
||||
return true;
|
||||
} catch (SipException | ParseException | InvalidArgumentException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 请求预览视频流
|
||||
*
|
||||
* @param deviceId 视频设备
|
||||
* @param channelId 预览通道
|
||||
*/
|
||||
@Override
|
||||
public String playStreamCmd(String deviceId, String channelId) {
|
||||
try {
|
||||
|
||||
Device device = storager.queryVideoDevice(deviceId);
|
||||
|
||||
//生成ssrc标识数据流 10位数字
|
||||
String ssrc = "";
|
||||
Random random = new Random();
|
||||
// ZLMediaServer最大识别7FFFFFFF即2147483647,所以随机数不能超过这个数
|
||||
ssrc = String.valueOf(random.nextInt(2147483647));
|
||||
//
|
||||
StringBuffer content = new StringBuffer(200);
|
||||
content.append("v=0\r\n");
|
||||
content.append("o="+channelId+" 0 0 IN IP4 "+config.getSipIp()+"\r\n");
|
||||
content.append("s=Play\r\n");
|
||||
content.append("c=IN IP4 "+config.getMediaIp()+"\r\n");
|
||||
content.append("t=0 0\r\n");
|
||||
if(device.getTransport().equals("TCP")) {
|
||||
content.append("m=video "+config.getMediaPort()+" TCP/RTP/AVP 96 98 97\r\n");
|
||||
}
|
||||
if(device.getTransport().equals("UDP")) {
|
||||
content.append("m=video "+config.getMediaPort()+" RTP/AVP 96 98 97\r\n");
|
||||
}
|
||||
content.append("a=sendrecv\r\n");
|
||||
content.append("a=rtpmap:96 PS/90000\r\n");
|
||||
content.append("a=rtpmap:98 H264/90000\r\n");
|
||||
content.append("a=rtpmap:97 MPEG4/90000\r\n");
|
||||
if(device.getTransport().equals("TCP")){
|
||||
content.append("a=setup:passive\r\n");
|
||||
content.append("a=connection:new\r\n");
|
||||
}
|
||||
content.append("y="+ssrc+"\r\n");//ssrc
|
||||
|
||||
Request request = headerProvider.createInviteRequest(device, content.toString(), null, "live", null);
|
||||
|
||||
transmitRequest(device.getTransport(), request);
|
||||
return ssrc;
|
||||
} catch ( SipException | ParseException | InvalidArgumentException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 语音广播
|
||||
*
|
||||
* @param deviceId 视频设备
|
||||
* @param channelId 预览通道
|
||||
*/
|
||||
@Override
|
||||
public String audioBroadcastCmd(String deviceId, String channelId) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 音视频录像控制
|
||||
*
|
||||
* @param deviceId 视频设备
|
||||
* @param channelId 预览通道
|
||||
*/
|
||||
@Override
|
||||
public String recordCmd(String deviceId, String channelId) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 报警布防/撤防命令
|
||||
*
|
||||
* @param deviceId 视频设备
|
||||
*/
|
||||
@Override
|
||||
public String guardCmd(String deviceId) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 报警复位命令
|
||||
*
|
||||
* @param deviceId 视频设备
|
||||
*/
|
||||
@Override
|
||||
public String alarmCmd(String deviceId) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 强制关键帧命令,设备收到此命令应立刻发送一个IDR帧
|
||||
*
|
||||
* @param deviceId 视频设备
|
||||
* @param channelId 预览通道
|
||||
*/
|
||||
@Override
|
||||
public String iFameCmd(String deviceId, String channelId) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 看守位控制命令
|
||||
*
|
||||
* @param deviceId 视频设备
|
||||
*/
|
||||
@Override
|
||||
public String homePositionCmd(String deviceId) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设备配置命令
|
||||
*
|
||||
* @param deviceId 视频设备
|
||||
*/
|
||||
@Override
|
||||
public String deviceConfigCmd(String deviceId) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询设备状态
|
||||
*
|
||||
* @param device 视频设备
|
||||
*/
|
||||
@Override
|
||||
public boolean deviceStatusQuery(Device device) {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询设备信息
|
||||
*
|
||||
* @param device 视频设备
|
||||
*/
|
||||
@Override
|
||||
public boolean deviceInfoQuery(Device device) {
|
||||
try {
|
||||
StringBuffer catalogXml = new StringBuffer(200);
|
||||
catalogXml.append("<?xml version=\"1.0\" encoding=\"GB2312\"?>");
|
||||
catalogXml.append("<Query>");
|
||||
catalogXml.append("<CmdType>DeviceInfo</CmdType>");
|
||||
catalogXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>");
|
||||
catalogXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>");
|
||||
catalogXml.append("</Query>");
|
||||
|
||||
Request request = headerProvider.createMessageRequest(device, catalogXml.toString(), "ViaDeviceInfoBranch", "FromDeviceInfoTag", "ToDeviceInfoTag");
|
||||
|
||||
transmitRequest(device.getTransport(), request);
|
||||
} catch (SipException | ParseException | InvalidArgumentException e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询目录列表
|
||||
*
|
||||
* @param device 视频设备
|
||||
*/
|
||||
@Override
|
||||
public boolean catalogQuery(Device device) {
|
||||
try {
|
||||
StringBuffer catalogXml = new StringBuffer(200);
|
||||
catalogXml.append("<?xml version=\"1.0\" encoding=\"GB2312\"?>");
|
||||
catalogXml.append("<Query>");
|
||||
catalogXml.append("<CmdType>Catalog</CmdType>");
|
||||
catalogXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>");
|
||||
catalogXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>");
|
||||
catalogXml.append("</Query>");
|
||||
|
||||
Request request = headerProvider.createMessageRequest(device, catalogXml.toString(), "ViaCatalogBranch", "FromCatalogTag", "ToCatalogTag");
|
||||
|
||||
transmitRequest(device.getTransport(), request);
|
||||
|
||||
} catch (SipException | ParseException | InvalidArgumentException e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询录像信息
|
||||
*
|
||||
* @param device 视频设备
|
||||
*/
|
||||
@Override
|
||||
public boolean recordInfoQuery(Device device) {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询报警信息
|
||||
*
|
||||
* @param device 视频设备
|
||||
*/
|
||||
@Override
|
||||
public boolean alarmInfoQuery(Device device) {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询设备配置
|
||||
*
|
||||
* @param device 视频设备
|
||||
*/
|
||||
@Override
|
||||
public boolean configQuery(Device device) {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询设备预置位置
|
||||
*
|
||||
* @param device 视频设备
|
||||
*/
|
||||
@Override
|
||||
public boolean presetQuery(Device device) {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询移动设备位置数据
|
||||
*
|
||||
* @param device 视频设备
|
||||
*/
|
||||
@Override
|
||||
public boolean mobilePostitionQuery(Device device) {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
private void transmitRequest(String transport, Request request) throws SipException {
|
||||
if(transport.equals("TCP")) {
|
||||
sipLayer.getTcpSipProvider().sendRequest(request);
|
||||
} else if(transport.equals("UDP")) {
|
||||
sipLayer.getUdpSipProvider().sendRequest(request);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package com.genersoft.iot.vmp.gb28181.transmit.request;
|
||||
|
||||
import javax.sip.RequestEvent;
|
||||
import javax.sip.ServerTransaction;
|
||||
|
||||
import com.genersoft.iot.vmp.gb28181.SipLayer;
|
||||
|
||||
/**
|
||||
* @Description:处理接收IPCamera发来的SIP协议请求消息
|
||||
* @author: songww
|
||||
* @date: 2020年5月3日 下午4:42:22
|
||||
*/
|
||||
public interface ISIPRequestProcessor {
|
||||
|
||||
public void process(RequestEvent evt, SipLayer layer, ServerTransaction transaction);
|
||||
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
package com.genersoft.iot.vmp.gb28181.transmit.request.impl;
|
||||
|
||||
import javax.sip.Dialog;
|
||||
import javax.sip.InvalidArgumentException;
|
||||
import javax.sip.RequestEvent;
|
||||
import javax.sip.ServerTransaction;
|
||||
import javax.sip.SipException;
|
||||
import javax.sip.message.Request;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.genersoft.iot.vmp.gb28181.SipLayer;
|
||||
import com.genersoft.iot.vmp.gb28181.transmit.request.ISIPRequestProcessor;
|
||||
|
||||
import gov.nist.javax.sip.header.CSeq;
|
||||
|
||||
/**
|
||||
* @Description:ACK请求处理器
|
||||
* @author: songww
|
||||
* @date: 2020年5月3日 下午5:31:45
|
||||
*/
|
||||
@Component
|
||||
public class AckRequestProcessor implements ISIPRequestProcessor {
|
||||
|
||||
/**
|
||||
* 处理 ACK请求
|
||||
*
|
||||
* @param evt
|
||||
* @param layer
|
||||
* @param transaction
|
||||
* @param config
|
||||
*/
|
||||
@Override
|
||||
public void process(RequestEvent evt, SipLayer layer, ServerTransaction transaction) {
|
||||
Request request = evt.getRequest();
|
||||
Dialog dialog = evt.getDialog();
|
||||
try {
|
||||
Request ackRequest = null;
|
||||
CSeq csReq = (CSeq) request.getHeader(CSeq.NAME);
|
||||
ackRequest = dialog.createAck(csReq.getSeqNumber());
|
||||
dialog.sendAck(ackRequest);
|
||||
System.out.println("send ack to callee:" + ackRequest.toString());
|
||||
} catch (SipException e) {
|
||||
e.printStackTrace();
|
||||
} catch (InvalidArgumentException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
package com.genersoft.iot.vmp.gb28181.transmit.request.impl;
|
||||
|
||||
import javax.sip.RequestEvent;
|
||||
import javax.sip.ServerTransaction;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.genersoft.iot.vmp.gb28181.SipLayer;
|
||||
import com.genersoft.iot.vmp.gb28181.transmit.request.ISIPRequestProcessor;
|
||||
|
||||
/**
|
||||
* @Description: BYE请求处理器
|
||||
* @author: songww
|
||||
* @date: 2020年5月3日 下午5:32:05
|
||||
*/
|
||||
@Component
|
||||
public class ByeRequestProcessor implements ISIPRequestProcessor {
|
||||
|
||||
/**
|
||||
* 处理BYE请求
|
||||
*
|
||||
* @param evt
|
||||
* @param layer
|
||||
* @param transaction
|
||||
* @param config
|
||||
*/
|
||||
@Override
|
||||
public void process(RequestEvent evt, SipLayer layer, ServerTransaction transaction) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
package com.genersoft.iot.vmp.gb28181.transmit.request.impl;
|
||||
|
||||
import javax.sip.RequestEvent;
|
||||
import javax.sip.ServerTransaction;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.genersoft.iot.vmp.gb28181.SipLayer;
|
||||
import com.genersoft.iot.vmp.gb28181.transmit.request.ISIPRequestProcessor;
|
||||
|
||||
/**
|
||||
* @Description:CANCEL请求处理器
|
||||
* @author: songww
|
||||
* @date: 2020年5月3日 下午5:32:23
|
||||
*/
|
||||
@Component
|
||||
public class CancelRequestProcessor implements ISIPRequestProcessor {
|
||||
|
||||
/**
|
||||
* 处理CANCEL请求
|
||||
*
|
||||
* @param evt
|
||||
* @param layer
|
||||
* @param transaction
|
||||
* @param config
|
||||
*/
|
||||
@Override
|
||||
public void process(RequestEvent evt, SipLayer layer, ServerTransaction transaction) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,77 @@
|
||||
package com.genersoft.iot.vmp.gb28181.transmit.request.impl;
|
||||
|
||||
import javax.sip.RequestEvent;
|
||||
import javax.sip.ServerTransaction;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.genersoft.iot.vmp.gb28181.SipLayer;
|
||||
import com.genersoft.iot.vmp.gb28181.transmit.request.ISIPRequestProcessor;
|
||||
|
||||
/**
|
||||
* @Description:处理INVITE请求
|
||||
* @author: songww
|
||||
* @date: 2020年5月3日 下午4:43:52
|
||||
*/
|
||||
@Component
|
||||
public class InviteRequestProcessor implements ISIPRequestProcessor {
|
||||
|
||||
/**
|
||||
* 处理invite请求
|
||||
*
|
||||
* @param request
|
||||
* 请求消息
|
||||
*/
|
||||
@Override
|
||||
public void process(RequestEvent evt, SipLayer layer, ServerTransaction transaction) {
|
||||
// TODO Auto-generated method stub
|
||||
// Request request = requestEvent.getRequest();
|
||||
//
|
||||
// try {
|
||||
// // 发送100 Trying
|
||||
// ServerTransaction serverTransaction = getServerTransaction(requestEvent);
|
||||
// // 查询目标地址
|
||||
// URI reqUri = request.getRequestURI();
|
||||
// URI contactURI = currUser.get(reqUri);
|
||||
//
|
||||
// System.out.println("processInvite rqStr=" + reqUri + " contact=" + contactURI);
|
||||
//
|
||||
// // 根据Request uri来路由,后续的响应消息通过VIA来路由
|
||||
// Request cliReq = messageFactory.createRequest(request.toString());
|
||||
// cliReq.setRequestURI(contactURI);
|
||||
//
|
||||
// HeaderFactory headerFactory = SipFactory.getInstance().createHeaderFactory();
|
||||
// Via callerVia = (Via) request.getHeader(Via.NAME);
|
||||
// Via via = (Via) headerFactory.createViaHeader(SIPMain.ip, SIPMain.port, "UDP",
|
||||
// callerVia.getBranch() + "sipphone");
|
||||
//
|
||||
// // FIXME 需要测试是否能够通过设置VIA头域来修改VIA头域值
|
||||
// cliReq.removeHeader(Via.NAME);
|
||||
// cliReq.addHeader(via);
|
||||
//
|
||||
// // 更新contact的地址
|
||||
// ContactHeader contactHeader = headerFactory.createContactHeader();
|
||||
// Address address = SipFactory.getInstance().createAddressFactory()
|
||||
// .createAddress("sip:sipsoft@" + SIPMain.ip + ":" + SIPMain.port);
|
||||
// contactHeader.setAddress(address);
|
||||
// contactHeader.setExpires(3600);
|
||||
// cliReq.setHeader(contactHeader);
|
||||
//
|
||||
// clientTransactionId = sipProvider.getNewClientTransaction(cliReq);
|
||||
// clientTransactionId.sendRequest();
|
||||
//
|
||||
// System.out.println("processInvite clientTransactionId=" + clientTransactionId.toString());
|
||||
//
|
||||
// System.out.println("send invite to callee: " + cliReq);
|
||||
// } catch (TransactionUnavailableException e1) {
|
||||
// e1.printStackTrace();
|
||||
// } catch (SipException e) {
|
||||
// e.printStackTrace();
|
||||
// } catch (ParseException e) {
|
||||
// e.printStackTrace();
|
||||
// } catch (Exception e) {
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,239 @@
|
||||
package com.genersoft.iot.vmp.gb28181.transmit.request.impl;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.text.ParseException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
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 org.dom4j.Document;
|
||||
import org.dom4j.DocumentException;
|
||||
import org.dom4j.Element;
|
||||
import org.dom4j.io.SAXReader;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.genersoft.iot.vmp.common.VideoManagerConstants;
|
||||
import com.genersoft.iot.vmp.gb28181.SipLayer;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.Device;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
|
||||
import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
|
||||
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.utils.XmlUtil;
|
||||
import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
|
||||
|
||||
/**
|
||||
* @Description:MESSAGE请求处理器
|
||||
* @author: songww
|
||||
* @date: 2020年5月3日 下午5:32:41
|
||||
*/
|
||||
@Component
|
||||
public class MessageRequestProcessor implements ISIPRequestProcessor {
|
||||
|
||||
private ServerTransaction transaction;
|
||||
|
||||
private SipLayer layer;
|
||||
|
||||
@Autowired
|
||||
private SIPCommander cmder;
|
||||
|
||||
@Autowired
|
||||
private IVideoManagerStorager storager;
|
||||
|
||||
@Autowired
|
||||
private EventPublisher publisher;
|
||||
|
||||
/**
|
||||
* 处理MESSAGE请求
|
||||
*
|
||||
* @param evt
|
||||
* @param layer
|
||||
* @param transaction
|
||||
*/
|
||||
@Override
|
||||
public void process(RequestEvent evt, SipLayer layer, ServerTransaction transaction) {
|
||||
|
||||
this.layer = layer;
|
||||
this.transaction = transaction;
|
||||
|
||||
Request request = evt.getRequest();
|
||||
|
||||
if (new String(request.getRawContent()).contains("<CmdType>Keepalive</CmdType>")) {
|
||||
processMessageKeepAlive(evt);
|
||||
} else if (new String(request.getRawContent()).contains("<CmdType>Catalog</CmdType>")) {
|
||||
processMessageCatalogList(evt);
|
||||
} else if (new String(request.getRawContent()).contains("<CmdType>DeviceInfo</CmdType>")) {
|
||||
processMessageDeviceInfo(evt);
|
||||
} else if (new String(request.getRawContent()).contains("<CmdType>Alarm</CmdType>")) {
|
||||
processMessageAlarm(evt);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/***
|
||||
* 收到catalog设备目录列表请求 处理
|
||||
* @param evt
|
||||
*/
|
||||
private void processMessageCatalogList(RequestEvent evt) {
|
||||
try {
|
||||
Request request = evt.getRequest();
|
||||
SAXReader reader = new SAXReader();
|
||||
reader.setEncoding("GB2312");
|
||||
Document xml = reader.read(new ByteArrayInputStream(request.getRawContent()));
|
||||
Element rootElement = xml.getRootElement();
|
||||
Element deviceIdElement = rootElement.element("DeviceID");
|
||||
String deviceId = deviceIdElement.getText().toString();
|
||||
Element deviceListElement = rootElement.element("DeviceList");
|
||||
if (deviceListElement == null) {
|
||||
return;
|
||||
}
|
||||
Iterator<Element> deviceListIterator = deviceListElement.elementIterator();
|
||||
if (deviceListIterator != null) {
|
||||
Device device = storager.queryVideoDevice(deviceId);
|
||||
if (device == null) {
|
||||
return;
|
||||
}
|
||||
Map<String, DeviceChannel> channelMap = device.getChannelMap();
|
||||
if (channelMap == null) {
|
||||
channelMap = new HashMap<String, DeviceChannel>(5);
|
||||
device.setChannelMap(channelMap);
|
||||
}
|
||||
// 遍历DeviceList
|
||||
while (deviceListIterator.hasNext()) {
|
||||
Element itemDevice = deviceListIterator.next();
|
||||
Element channelDeviceElement = itemDevice.element("DeviceID");
|
||||
if (channelDeviceElement == null) {
|
||||
continue;
|
||||
}
|
||||
String channelDeviceId = channelDeviceElement.getText().toString();
|
||||
Element channdelNameElement = itemDevice.element("Name");
|
||||
String channelName = channdelNameElement != null ? channdelNameElement.getText().toString() : "";
|
||||
Element statusElement = itemDevice.element("Status");
|
||||
String status = statusElement != null ? statusElement.getText().toString() : "ON";
|
||||
DeviceChannel deviceChannel = channelMap.containsKey(channelDeviceId) ? channelMap.get(channelDeviceId) : new DeviceChannel();
|
||||
deviceChannel.setName(channelName);
|
||||
deviceChannel.setChannelId(channelDeviceId);
|
||||
if(status.equals("ON")) {
|
||||
deviceChannel.setStatus(1);
|
||||
}
|
||||
if(status.equals("OFF")) {
|
||||
deviceChannel.setStatus(0);
|
||||
}
|
||||
|
||||
deviceChannel.setManufacture(XmlUtil.getText(itemDevice,"Manufacturer"));
|
||||
deviceChannel.setModel(XmlUtil.getText(itemDevice,"Model"));
|
||||
deviceChannel.setOwner(XmlUtil.getText(itemDevice,"Owner"));
|
||||
deviceChannel.setCivilCode(XmlUtil.getText(itemDevice,"CivilCode"));
|
||||
deviceChannel.setBlock(XmlUtil.getText(itemDevice,"Block"));
|
||||
deviceChannel.setAddress(XmlUtil.getText(itemDevice,"Address"));
|
||||
deviceChannel.setParental(itemDevice.element("Parental") == null? 0:Integer.parseInt(XmlUtil.getText(itemDevice,"Parental")));
|
||||
deviceChannel.setParentId(XmlUtil.getText(itemDevice,"ParentId"));
|
||||
deviceChannel.setSafetyWay(itemDevice.element("SafetyWay") == null? 0:Integer.parseInt(XmlUtil.getText(itemDevice,"SafetyWay")));
|
||||
deviceChannel.setRegisterWay(itemDevice.element("RegisterWay") == null? 1:Integer.parseInt(XmlUtil.getText(itemDevice,"RegisterWay")));
|
||||
deviceChannel.setCertNum(XmlUtil.getText(itemDevice,"CertNum"));
|
||||
deviceChannel.setCertifiable(itemDevice.element("Certifiable") == null? 0:Integer.parseInt(XmlUtil.getText(itemDevice,"Certifiable")));
|
||||
deviceChannel.setErrCode(itemDevice.element("ErrCode") == null? 0:Integer.parseInt(XmlUtil.getText(itemDevice,"ErrCode")));
|
||||
deviceChannel.setEndTime(XmlUtil.getText(itemDevice,"EndTime"));
|
||||
deviceChannel.setSecrecy(XmlUtil.getText(itemDevice,"Secrecy"));
|
||||
deviceChannel.setIpAddress(XmlUtil.getText(itemDevice,"IPAddress"));
|
||||
deviceChannel.setPort(itemDevice.element("Port") == null? 0:Integer.parseInt(XmlUtil.getText(itemDevice,"Port")));
|
||||
deviceChannel.setPassword(XmlUtil.getText(itemDevice,"Password"));
|
||||
deviceChannel.setLongitude(itemDevice.element("Longitude") == null? 0.00:Double.parseDouble(XmlUtil.getText(itemDevice,"Longitude")));
|
||||
deviceChannel.setLatitude(itemDevice.element("Latitude") == null? 0.00:Double.parseDouble(XmlUtil.getText(itemDevice,"Latitude")));
|
||||
channelMap.put(channelDeviceId, deviceChannel);
|
||||
}
|
||||
// 更新
|
||||
storager.update(device);
|
||||
}
|
||||
} catch (DocumentException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/***
|
||||
* 收到deviceInfo设备信息请求 处理
|
||||
* @param evt
|
||||
*/
|
||||
private void processMessageDeviceInfo(RequestEvent evt) {
|
||||
try {
|
||||
Request request = evt.getRequest();
|
||||
SAXReader reader = new SAXReader();
|
||||
// reader.setEncoding("GB2312");
|
||||
Document xml = reader.read(new ByteArrayInputStream(request.getRawContent()));
|
||||
Element rootElement = xml.getRootElement();
|
||||
Element deviceIdElement = rootElement.element("DeviceID");
|
||||
String deviceId = deviceIdElement.getText().toString();
|
||||
|
||||
Device device = storager.queryVideoDevice(deviceId);
|
||||
if (device == null) {
|
||||
return;
|
||||
}
|
||||
device.setName(XmlUtil.getText(rootElement,"DeviceName"));
|
||||
device.setManufacturer(XmlUtil.getText(rootElement,"Manufacturer"));
|
||||
device.setModel(XmlUtil.getText(rootElement,"Model"));
|
||||
device.setFirmware(XmlUtil.getText(rootElement,"Firmware"));
|
||||
storager.update(device);
|
||||
cmder.catalogQuery(device);
|
||||
} catch (DocumentException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/***
|
||||
* 收到alarm设备报警信息 处理
|
||||
* @param evt
|
||||
*/
|
||||
private void processMessageAlarm(RequestEvent evt) {
|
||||
try {
|
||||
Request request = evt.getRequest();
|
||||
SAXReader reader = new SAXReader();
|
||||
// reader.setEncoding("GB2312");
|
||||
Document xml = reader.read(new ByteArrayInputStream(request.getRawContent()));
|
||||
Element rootElement = xml.getRootElement();
|
||||
Element deviceIdElement = rootElement.element("DeviceID");
|
||||
String deviceId = deviceIdElement.getText().toString();
|
||||
|
||||
Device device = storager.queryVideoDevice(deviceId);
|
||||
if (device == null) {
|
||||
return;
|
||||
}
|
||||
device.setName(XmlUtil.getText(rootElement,"DeviceName"));
|
||||
device.setManufacturer(XmlUtil.getText(rootElement,"Manufacturer"));
|
||||
device.setModel(XmlUtil.getText(rootElement,"Model"));
|
||||
device.setFirmware(XmlUtil.getText(rootElement,"Firmware"));
|
||||
storager.update(device);
|
||||
cmder.catalogQuery(device);
|
||||
} catch (DocumentException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/***
|
||||
* 收到keepalive请求 处理
|
||||
* @param evt
|
||||
*/
|
||||
private void processMessageKeepAlive(RequestEvent evt){
|
||||
try {
|
||||
Request request = evt.getRequest();
|
||||
Response response = layer.getMessageFactory().createResponse(Response.OK,request);
|
||||
SAXReader reader = new SAXReader();
|
||||
Document xml = reader.read(new ByteArrayInputStream(request.getRawContent()));
|
||||
// reader.setEncoding("GB2312");
|
||||
Element rootElement = xml.getRootElement();
|
||||
Element deviceIdElement = rootElement.element("DeviceID");
|
||||
transaction.sendResponse(response);
|
||||
publisher.onlineEventPublish(deviceIdElement.getText(), VideoManagerConstants.EVENT_ONLINE_KEEPLIVE);
|
||||
} catch (ParseException | SipException | InvalidArgumentException | DocumentException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
package com.genersoft.iot.vmp.gb28181.transmit.request.impl;
|
||||
|
||||
import javax.sip.RequestEvent;
|
||||
import javax.sip.ServerTransaction;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.genersoft.iot.vmp.gb28181.SipLayer;
|
||||
import com.genersoft.iot.vmp.gb28181.transmit.request.ISIPRequestProcessor;
|
||||
|
||||
/**
|
||||
* @Description:暂不支持的消息请求处理器
|
||||
* @author: songww
|
||||
* @date: 2020年5月3日 下午5:32:59
|
||||
*/
|
||||
@Component
|
||||
public class OtherRequestProcessor implements ISIPRequestProcessor {
|
||||
|
||||
/**
|
||||
* <p>Title: process</p>
|
||||
* <p>Description: </p>
|
||||
* @param evt
|
||||
* @param layer
|
||||
* @param transaction
|
||||
* @param config
|
||||
*/
|
||||
@Override
|
||||
public void process(RequestEvent evt, SipLayer layer, ServerTransaction transaction) {
|
||||
System.out.println("no support the method! Method:" + evt.getRequest().getMethod());
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,163 @@
|
||||
package com.genersoft.iot.vmp.gb28181.transmit.request.impl;
|
||||
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.text.ParseException;
|
||||
import java.util.Calendar;
|
||||
import java.util.Locale;
|
||||
|
||||
import javax.sip.InvalidArgumentException;
|
||||
import javax.sip.RequestEvent;
|
||||
import javax.sip.ServerTransaction;
|
||||
import javax.sip.SipException;
|
||||
import javax.sip.header.AuthorizationHeader;
|
||||
import javax.sip.header.ContactHeader;
|
||||
import javax.sip.header.ExpiresHeader;
|
||||
import javax.sip.header.FromHeader;
|
||||
import javax.sip.header.ViaHeader;
|
||||
import javax.sip.message.Request;
|
||||
import javax.sip.message.Response;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.genersoft.iot.vmp.common.VideoManagerConstants;
|
||||
import com.genersoft.iot.vmp.conf.SipConfig;
|
||||
import com.genersoft.iot.vmp.gb28181.SipLayer;
|
||||
import com.genersoft.iot.vmp.gb28181.auth.DigestServerAuthenticationHelper;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.Device;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.Host;
|
||||
import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
|
||||
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
|
||||
import com.genersoft.iot.vmp.gb28181.transmit.request.ISIPRequestProcessor;
|
||||
import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
|
||||
|
||||
import gov.nist.javax.sip.address.AddressImpl;
|
||||
import gov.nist.javax.sip.address.SipUri;
|
||||
import gov.nist.javax.sip.header.Expires;
|
||||
|
||||
/**
|
||||
* @Description:收到注册请求 处理
|
||||
* @author: songww
|
||||
* @date: 2020年5月3日 下午4:47:25
|
||||
*/
|
||||
@Component
|
||||
public class RegisterRequestProcessor implements ISIPRequestProcessor {
|
||||
|
||||
@Autowired
|
||||
private SipConfig config;
|
||||
|
||||
@Autowired
|
||||
private SIPCommander cmder;
|
||||
|
||||
@Autowired
|
||||
private IVideoManagerStorager storager;
|
||||
|
||||
@Autowired
|
||||
private EventPublisher publisher;
|
||||
|
||||
/***
|
||||
* 收到注册请求 处理
|
||||
*
|
||||
* @param request
|
||||
* 请求消息
|
||||
*/
|
||||
@Override
|
||||
public void process(RequestEvent evt, SipLayer layer, ServerTransaction transaction) {
|
||||
try {
|
||||
System.out.println("收到注册请求,开始处理");
|
||||
Request request = evt.getRequest();
|
||||
|
||||
Response response = null;
|
||||
boolean passwordCorrect = false;
|
||||
// 注册标志 0:未携带授权头或者密码错误 1:注册成功 2:注销成功
|
||||
int registerFlag = 0;
|
||||
Device device = null;
|
||||
AuthorizationHeader authorhead = (AuthorizationHeader) request.getHeader(AuthorizationHeader.NAME);
|
||||
// 校验密码是否正确
|
||||
if (authorhead != null) {
|
||||
passwordCorrect = new DigestServerAuthenticationHelper().doAuthenticatePlainTextPassword(request,
|
||||
config.getSipPassword());
|
||||
}
|
||||
|
||||
// 未携带授权头或者密码错误 回复401
|
||||
if (authorhead == null || !passwordCorrect) {
|
||||
|
||||
if (authorhead == null) {
|
||||
System.out.println("未携带授权头 回复401");
|
||||
} else if (!passwordCorrect) {
|
||||
System.out.println("密码错误 回复401");
|
||||
}
|
||||
response = layer.getMessageFactory().createResponse(Response.UNAUTHORIZED, request);
|
||||
new DigestServerAuthenticationHelper().generateChallenge(layer.getHeaderFactory(), response, config.getSipDomain());
|
||||
}
|
||||
// 携带授权头并且密码正确
|
||||
else if (passwordCorrect) {
|
||||
response = layer.getMessageFactory().createResponse(Response.OK, request);
|
||||
// 添加date头
|
||||
response.addHeader(layer.getHeaderFactory().createDateHeader(Calendar.getInstance(Locale.ENGLISH)));
|
||||
ExpiresHeader expiresHeader = (ExpiresHeader) request.getHeader(Expires.NAME);
|
||||
// 添加Contact头
|
||||
response.addHeader(request.getHeader(ContactHeader.NAME));
|
||||
// 添加Expires头
|
||||
response.addHeader(request.getExpires());
|
||||
|
||||
// 1.获取到通信地址等信息,保存到Redis
|
||||
FromHeader fromHeader = (FromHeader) request.getHeader(FromHeader.NAME);
|
||||
ViaHeader viaHeader = (ViaHeader) request.getHeader(ViaHeader.NAME);
|
||||
String received = viaHeader.getReceived();
|
||||
int rPort = viaHeader.getRPort();
|
||||
// 本地模拟设备 received 为空 rPort 为 -1
|
||||
// 解析本地地址替代
|
||||
if (StringUtils.isEmpty(received) || rPort == -1) {
|
||||
received = viaHeader.getHost();
|
||||
rPort = viaHeader.getPort();
|
||||
}
|
||||
//
|
||||
Host host = new Host();
|
||||
host.setIp(received);
|
||||
host.setPort(rPort);
|
||||
host.setAddress(received.concat(":").concat(String.valueOf(rPort)));
|
||||
AddressImpl address = (AddressImpl) fromHeader.getAddress();
|
||||
SipUri uri = (SipUri) address.getURI();
|
||||
String deviceId = uri.getUser();
|
||||
device = new Device();
|
||||
device.setDeviceId(deviceId);
|
||||
device.setHost(host);
|
||||
// 注销成功
|
||||
if (expiresHeader != null && expiresHeader.getExpires() == 0) {
|
||||
registerFlag = 2;
|
||||
}
|
||||
// 注册成功
|
||||
else {
|
||||
registerFlag = 1;
|
||||
// 判断TCP还是UDP
|
||||
boolean isTcp = false;
|
||||
ViaHeader reqViaHeader = (ViaHeader) request.getHeader(ViaHeader.NAME);
|
||||
String transport = reqViaHeader.getTransport();
|
||||
if (transport.equals("TCP")) {
|
||||
isTcp = true;
|
||||
}
|
||||
device.setTransport(isTcp ? "TCP" : "UDP");
|
||||
}
|
||||
}
|
||||
transaction.sendResponse(response);
|
||||
// 注册成功
|
||||
// 保存到redis
|
||||
// 下发catelog查询目录
|
||||
if (registerFlag == 1 && device != null) {
|
||||
System.out.println("注册成功! deviceId:" + device.getDeviceId());
|
||||
storager.update(device);
|
||||
publisher.onlineEventPublish(device.getDeviceId(), VideoManagerConstants.EVENT_ONLINE_REGISTER);
|
||||
cmder.deviceInfoQuery(device);
|
||||
} else if (registerFlag == 2) {
|
||||
System.out.println("注销成功! deviceId:" + device.getDeviceId());
|
||||
publisher.outlineEventPublish(device.getDeviceId(), VideoManagerConstants.EVENT_OUTLINE_UNREGISTER);
|
||||
}
|
||||
} catch (SipException | InvalidArgumentException | NoSuchAlgorithmException | ParseException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
package com.genersoft.iot.vmp.gb28181.transmit.request.impl;
|
||||
|
||||
import java.text.ParseException;
|
||||
|
||||
import javax.sip.InvalidArgumentException;
|
||||
import javax.sip.RequestEvent;
|
||||
import javax.sip.ServerTransaction;
|
||||
import javax.sip.SipException;
|
||||
import javax.sip.header.ExpiresHeader;
|
||||
import javax.sip.message.Request;
|
||||
import javax.sip.message.Response;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.genersoft.iot.vmp.gb28181.SipLayer;
|
||||
import com.genersoft.iot.vmp.gb28181.transmit.request.ISIPRequestProcessor;
|
||||
|
||||
/**
|
||||
* @Description:SUBSCRIBE请求处理器
|
||||
* @author: songww
|
||||
* @date: 2020年5月3日 下午5:31:20
|
||||
*/
|
||||
@Component
|
||||
public class SubscribeRequestProcessor implements ISIPRequestProcessor {
|
||||
|
||||
/**
|
||||
* 处理SUBSCRIBE请求
|
||||
*
|
||||
* @param evt
|
||||
* @param layer
|
||||
* @param transaction
|
||||
* @param config
|
||||
*/
|
||||
@Override
|
||||
public void process(RequestEvent evt, SipLayer layer, ServerTransaction transaction) {
|
||||
Request request = evt.getRequest();
|
||||
|
||||
try {
|
||||
Response response = null;
|
||||
response = layer.getMessageFactory().createResponse(200, request);
|
||||
if (response != null) {
|
||||
ExpiresHeader expireHeader = layer.getHeaderFactory().createExpiresHeader(30);
|
||||
response.setExpires(expireHeader);
|
||||
}
|
||||
System.out.println("response : " + response.toString());
|
||||
|
||||
if (transaction != null) {
|
||||
transaction.sendResponse(response);
|
||||
transaction.terminate();
|
||||
} else {
|
||||
System.out.println("processRequest serverTransactionId is null.");
|
||||
}
|
||||
|
||||
} catch (ParseException e) {
|
||||
e.printStackTrace();
|
||||
} catch (SipException e) {
|
||||
e.printStackTrace();
|
||||
} catch (InvalidArgumentException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package com.genersoft.iot.vmp.gb28181.transmit.response;
|
||||
|
||||
import javax.sip.ResponseEvent;
|
||||
|
||||
import com.genersoft.iot.vmp.conf.SipConfig;
|
||||
import com.genersoft.iot.vmp.gb28181.SipLayer;
|
||||
|
||||
/**
|
||||
* @Description:处理接收IPCamera发来的SIP协议响应消息
|
||||
* @author: songww
|
||||
* @date: 2020年5月3日 下午4:42:22
|
||||
*/
|
||||
public interface ISIPResponseProcessor {
|
||||
|
||||
public void process(ResponseEvent evt, SipLayer layer, SipConfig config);
|
||||
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
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: songww
|
||||
* @date: 2020年5月3日 下午5:32:05
|
||||
*/
|
||||
@Component
|
||||
public class ByeResponseProcessor implements ISIPResponseProcessor {
|
||||
|
||||
/**
|
||||
* 处理BYE响应
|
||||
*
|
||||
* @param evt
|
||||
* @param layer
|
||||
* @param transaction
|
||||
* @param config
|
||||
*/
|
||||
@Override
|
||||
public void process(ResponseEvent evt, SipLayer layer, SipConfig config) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
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: songww
|
||||
* @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
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
package com.genersoft.iot.vmp.gb28181.transmit.response.impl;
|
||||
|
||||
import javax.sip.Dialog;
|
||||
import javax.sip.InvalidArgumentException;
|
||||
import javax.sip.ResponseEvent;
|
||||
import javax.sip.SipException;
|
||||
import javax.sip.message.Request;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.genersoft.iot.vmp.conf.SipConfig;
|
||||
import com.genersoft.iot.vmp.gb28181.SipLayer;
|
||||
import com.genersoft.iot.vmp.gb28181.transmit.response.ISIPResponseProcessor;
|
||||
|
||||
/**
|
||||
* @Description:处理INVITE响应
|
||||
* @author: songww
|
||||
* @date: 2020年5月3日 下午4:43:52
|
||||
*/
|
||||
@Component
|
||||
public class InviteResponseProcessor implements ISIPResponseProcessor {
|
||||
|
||||
/**
|
||||
* 处理invite响应
|
||||
*
|
||||
* @param request
|
||||
* 响应消息
|
||||
*/
|
||||
@Override
|
||||
public void process(ResponseEvent evt, SipLayer layer, SipConfig config) {
|
||||
try {
|
||||
Dialog dialog = evt.getDialog();
|
||||
Request reqAck =dialog.createAck(1L);
|
||||
dialog.sendAck(reqAck);
|
||||
} catch (InvalidArgumentException | SipException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
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: songww
|
||||
* @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
|
||||
|
||||
}
|
||||
|
||||
}
|
121
src/main/java/com/genersoft/iot/vmp/gb28181/utils/XmlUtil.java
Normal file
121
src/main/java/com/genersoft/iot/vmp/gb28181/utils/XmlUtil.java
Normal file
@ -0,0 +1,121 @@
|
||||
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 org.dom4j.Attribute;
|
||||
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;
|
||||
|
||||
/**
|
||||
* 基于dom4j的工具包
|
||||
*
|
||||
*
|
||||
*/
|
||||
public class XmlUtil
|
||||
{
|
||||
/**
|
||||
* 日志服务
|
||||
*/
|
||||
private static Logger LOG = LoggerFactory.getLogger(XmlUtil.class);
|
||||
|
||||
/**
|
||||
* 解析XML为Document对象
|
||||
*
|
||||
* @param xml
|
||||
* 被解析的XMl
|
||||
* @return Document
|
||||
*/
|
||||
public static Element parseXml(String xml)
|
||||
{
|
||||
Document document = null;
|
||||
//
|
||||
StringReader sr = new StringReader(xml);
|
||||
SAXReader saxReader = new SAXReader();
|
||||
try
|
||||
{
|
||||
document = saxReader.read(sr);
|
||||
}
|
||||
catch (DocumentException e)
|
||||
{
|
||||
LOG.error("解析失败", e);
|
||||
}
|
||||
return null == document ? null : document.getRootElement();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取element对象的text的值
|
||||
*
|
||||
* @param em
|
||||
* 节点的对象
|
||||
* @param tag
|
||||
* 节点的tag
|
||||
* @return 节点
|
||||
*/
|
||||
public static String getText(Element em, String tag)
|
||||
{
|
||||
if (null == em)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
Element e = em.element(tag);
|
||||
//
|
||||
return null == e ? null : e.getText();
|
||||
}
|
||||
|
||||
/**
|
||||
* 递归解析xml节点,适用于 多节点数据
|
||||
*
|
||||
* @param node
|
||||
* node
|
||||
* @param nodeName
|
||||
* nodeName
|
||||
* @return List<Map<String, Object>>
|
||||
*/
|
||||
public static List<Map<String, Object>> listNodes(Element node, String nodeName)
|
||||
{
|
||||
if (null == node)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
// 初始化返回
|
||||
List<Map<String, Object>> listMap = new ArrayList<Map<String, Object>>();
|
||||
// 首先获取当前节点的所有属性节点
|
||||
List<Attribute> list = node.attributes();
|
||||
|
||||
Map<String, Object> map = null;
|
||||
// 遍历属性节点
|
||||
for (Attribute attribute : list)
|
||||
{
|
||||
if (nodeName.equals(node.getName()))
|
||||
{
|
||||
if (null == map)
|
||||
{
|
||||
map = new HashMap<String, Object>();
|
||||
listMap.add(map);
|
||||
}
|
||||
// 取到的节点属性放到map中
|
||||
map.put(attribute.getName(), attribute.getValue());
|
||||
}
|
||||
|
||||
}
|
||||
// 遍历当前节点下的所有节点 ,nodeName 要解析的节点名称
|
||||
// 使用递归
|
||||
Iterator<Element> iterator = node.elementIterator();
|
||||
while (iterator.hasNext())
|
||||
{
|
||||
Element e = iterator.next();
|
||||
listMap.addAll(listNodes(e, nodeName));
|
||||
}
|
||||
return listMap;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,77 @@
|
||||
package com.genersoft.iot.vmp.storager;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.genersoft.iot.vmp.gb28181.bean.Device;
|
||||
|
||||
/**
|
||||
* @Description:视频设备数据存储接口
|
||||
* @author: songww
|
||||
* @date: 2020年5月6日 下午2:14:31
|
||||
*/
|
||||
public interface IVideoManagerStorager {
|
||||
|
||||
/**
|
||||
* 根据设备ID判断设备是否存在
|
||||
*
|
||||
* @param deviceId 设备ID
|
||||
* @return true:存在 false:不存在
|
||||
*/
|
||||
public boolean exists(String deviceId);
|
||||
|
||||
/**
|
||||
* 视频设备创建
|
||||
*
|
||||
* @param device 设备对象
|
||||
* @return true:创建成功 false:创建失败
|
||||
*/
|
||||
public boolean create(Device device);
|
||||
|
||||
/**
|
||||
* 视频设备更新
|
||||
*
|
||||
* @param device 设备对象
|
||||
* @return true:创建成功 false:创建失败
|
||||
*/
|
||||
public boolean update(Device device);
|
||||
|
||||
/**
|
||||
* 获取设备
|
||||
*
|
||||
* @param deviceId 设备ID
|
||||
* @return DShadow 设备对象
|
||||
*/
|
||||
public Device queryVideoDevice(String deviceId);
|
||||
|
||||
/**
|
||||
* 获取多个设备
|
||||
*
|
||||
* @param deviceIds 设备ID数组
|
||||
* @return List<Device> 设备对象数组
|
||||
*/
|
||||
public List<Device> queryVideoDeviceList(String[] deviceIds);
|
||||
|
||||
/**
|
||||
* 删除设备
|
||||
*
|
||||
* @param deviceId 设备ID
|
||||
* @return true:删除成功 false:删除失败
|
||||
*/
|
||||
public boolean delete(String deviceId);
|
||||
|
||||
/**
|
||||
* 更新设备在线
|
||||
*
|
||||
* @param deviceId 设备ID
|
||||
* @return true:更新成功 false:更新失败
|
||||
*/
|
||||
public boolean online(String deviceId);
|
||||
|
||||
/**
|
||||
* 更新设备离线
|
||||
*
|
||||
* @param deviceId 设备ID
|
||||
* @return true:更新成功 false:更新失败
|
||||
*/
|
||||
public boolean outline(String deviceId);
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
package com.genersoft.iot.vmp.storager;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.genersoft.iot.vmp.conf.VManagerConfig;
|
||||
|
||||
/**
|
||||
* @Description:视频设备数据存储工厂,根据存储策略,返回对应的存储器
|
||||
* @author: songww
|
||||
* @date: 2020年5月6日 下午2:15:16
|
||||
*/
|
||||
@Component
|
||||
public class VideoManagerStoragerFactory {
|
||||
|
||||
@Autowired
|
||||
private VManagerConfig vmConfig;
|
||||
|
||||
@Autowired
|
||||
private IVideoManagerStorager jdbcStorager;
|
||||
|
||||
@Autowired
|
||||
private IVideoManagerStorager redisStorager;
|
||||
|
||||
@Bean("storager")
|
||||
public IVideoManagerStorager getStorager() {
|
||||
if ("redis".equals(vmConfig.getDatabase().toLowerCase())) {
|
||||
return redisStorager;
|
||||
} else if ("jdbc".equals(vmConfig.getDatabase().toLowerCase())) {
|
||||
return jdbcStorager;
|
||||
}
|
||||
return redisStorager;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,116 @@
|
||||
package com.genersoft.iot.vmp.storager.jdbc;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.genersoft.iot.vmp.common.VideoManagerConstants;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.Device;
|
||||
import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
|
||||
|
||||
/**
|
||||
* @Description:视频设备数据存储-jdbc实现
|
||||
* @author: songww
|
||||
* @date: 2020年5月6日 下午2:28:12
|
||||
*/
|
||||
@Component("jdbcStorager")
|
||||
public class VideoManagerJdbcStoragerImpl implements IVideoManagerStorager {
|
||||
|
||||
/**
|
||||
* 根据设备ID判断设备是否存在
|
||||
*
|
||||
* @param deviceId 设备ID
|
||||
* @return true:存在 false:不存在
|
||||
*/
|
||||
@Override
|
||||
public boolean exists(String deviceId) {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 视频设备创建
|
||||
*
|
||||
* @param device 设备对象
|
||||
* @return true:创建成功 false:创建失败
|
||||
*/
|
||||
@Override
|
||||
public boolean create(Device device) {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 视频设备更新
|
||||
*
|
||||
* @param device 设备对象
|
||||
* @return true:更新成功 false:更新失败
|
||||
*/
|
||||
@Override
|
||||
public boolean update(Device device) {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取设备
|
||||
*
|
||||
* @param deviceId 设备ID
|
||||
* @return Device 设备对象
|
||||
*/
|
||||
@Override
|
||||
public Device queryVideoDevice(String deviceId) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取多个设备
|
||||
*
|
||||
* @param deviceIds 设备ID数组
|
||||
* @return List<Device> 设备对象数组
|
||||
*/
|
||||
@Override
|
||||
public List<Device> queryVideoDeviceList(String[] deviceIds) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除设备
|
||||
*
|
||||
* @param deviceId 设备ID
|
||||
* @return true:删除成功 false:删除失败
|
||||
*/
|
||||
@Override
|
||||
public boolean delete(String deviceId) {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新设备在线
|
||||
*
|
||||
* @param deviceId 设备ID
|
||||
* @return true:更新成功 false:更新失败
|
||||
*/
|
||||
@Override
|
||||
public boolean online(String deviceId) {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新设备离线
|
||||
*
|
||||
* @param deviceId 设备ID
|
||||
* @return true:更新成功 false:更新失败
|
||||
*/
|
||||
@Override
|
||||
public boolean outline(String deviceId) {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,129 @@
|
||||
package com.genersoft.iot.vmp.storager.redis;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.genersoft.iot.vmp.common.VideoManagerConstants;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.Device;
|
||||
import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
|
||||
import com.genersoft.iot.vmp.utils.redis.RedisUtil;
|
||||
|
||||
/**
|
||||
* @Description:视频设备数据存储-redis实现
|
||||
* @author: songww
|
||||
* @date: 2020年5月6日 下午2:31:42
|
||||
*/
|
||||
@Component("redisStorager")
|
||||
public class VideoManagerRedisStoragerImpl implements IVideoManagerStorager {
|
||||
|
||||
@Autowired
|
||||
private RedisUtil redis;
|
||||
|
||||
/**
|
||||
* 根据设备ID判断设备是否存在
|
||||
*
|
||||
* @param deviceId 设备ID
|
||||
* @return true:存在 false:不存在
|
||||
*/
|
||||
@Override
|
||||
public boolean exists(String deviceId) {
|
||||
return redis.hasKey(VideoManagerConstants.CACHEKEY_PREFIX+deviceId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 视频设备创建
|
||||
*
|
||||
* @param device 设备对象
|
||||
* @return true:创建成功 false:创建失败
|
||||
*/
|
||||
@Override
|
||||
public boolean create(Device device) {
|
||||
return redis.set(VideoManagerConstants.CACHEKEY_PREFIX+device.getDeviceId(), device);
|
||||
}
|
||||
|
||||
/**
|
||||
* 视频设备更新
|
||||
*
|
||||
* @param device 设备对象
|
||||
* @return true:更新成功 false:更新失败
|
||||
*/
|
||||
@Override
|
||||
public boolean update(Device device) {
|
||||
return redis.set(VideoManagerConstants.CACHEKEY_PREFIX+device.getDeviceId(), device);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取设备
|
||||
*
|
||||
* @param deviceId 设备ID
|
||||
* @return Device 设备对象
|
||||
*/
|
||||
@Override
|
||||
public Device queryVideoDevice(String deviceId) {
|
||||
return (Device)redis.get(VideoManagerConstants.CACHEKEY_PREFIX+deviceId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取多个设备
|
||||
*
|
||||
* @param deviceIds 设备ID数组
|
||||
* @return List<Device> 设备对象数组
|
||||
*/
|
||||
@Override
|
||||
public List<Device> queryVideoDeviceList(String[] deviceIds) {
|
||||
List<Device> devices = new ArrayList<>();
|
||||
if (deviceIds == null || deviceIds.length == 0) {
|
||||
List<Object> deviceIdList = redis.keys(VideoManagerConstants.CACHEKEY_PREFIX+"*");
|
||||
for (int i = 0; i < deviceIdList.size(); i++) {
|
||||
devices.add((Device)redis.get((String)deviceIdList.get(i)));
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < deviceIds.length; i++) {
|
||||
devices.add((Device)redis.get(VideoManagerConstants.CACHEKEY_PREFIX+deviceIds[i]));
|
||||
}
|
||||
}
|
||||
return devices;
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除设备
|
||||
*
|
||||
* @param deviceId 设备ID
|
||||
* @return true:删除成功 false:删除失败
|
||||
*/
|
||||
@Override
|
||||
public boolean delete(String deviceId) {
|
||||
redis.del(VideoManagerConstants.CACHEKEY_PREFIX+deviceId);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新设备在线
|
||||
*
|
||||
* @param deviceId 设备ID
|
||||
* @return true:更新成功 false:更新失败
|
||||
*/
|
||||
@Override
|
||||
public boolean online(String deviceId) {
|
||||
Device device = (Device)redis.get(VideoManagerConstants.CACHEKEY_PREFIX+deviceId);
|
||||
device.setOnline(1);
|
||||
return redis.set(VideoManagerConstants.CACHEKEY_PREFIX+device.getDeviceId(), device);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新设备离线
|
||||
*
|
||||
* @param deviceId 设备ID
|
||||
* @return true:更新成功 false:更新失败
|
||||
*/
|
||||
@Override
|
||||
public boolean outline(String deviceId) {
|
||||
Device device = (Device)redis.get(VideoManagerConstants.CACHEKEY_PREFIX+deviceId);
|
||||
device.setOnline(0);
|
||||
return redis.set(VideoManagerConstants.CACHEKEY_PREFIX+device.getDeviceId(), device);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
package com.genersoft.iot.vmp.utils.redis;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
import org.springframework.data.redis.serializer.RedisSerializer;
|
||||
import org.springframework.data.redis.serializer.SerializationException;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.serializer.SerializerFeature;
|
||||
|
||||
/**
|
||||
* @Description:使用fastjson实现redis的序列化
|
||||
* @author: songww
|
||||
* @date: 2020年5月6日 下午8:40:11
|
||||
*/
|
||||
public class FastJsonRedisSerializer<T> implements RedisSerializer<T> {
|
||||
|
||||
public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
|
||||
|
||||
private Class<T> clazz;
|
||||
|
||||
public FastJsonRedisSerializer(Class<T> clazz) {
|
||||
super();
|
||||
this.clazz = clazz;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] serialize(T t) throws SerializationException {
|
||||
if (t == null) {
|
||||
return new byte[0];
|
||||
}
|
||||
return JSON.toJSONString(t, SerializerFeature.WriteClassName).getBytes(DEFAULT_CHARSET);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T deserialize(byte[] bytes) throws SerializationException {
|
||||
if (bytes == null || bytes.length <= 0) {
|
||||
return null;
|
||||
}
|
||||
String str = new String(bytes, DEFAULT_CHARSET);
|
||||
return (T) JSON.parseObject(str, clazz);
|
||||
}
|
||||
}
|
557
src/main/java/com/genersoft/iot/vmp/utils/redis/RedisUtil.java
Normal file
557
src/main/java/com/genersoft/iot/vmp/utils/redis/RedisUtil.java
Normal file
@ -0,0 +1,557 @@
|
||||
package com.genersoft.iot.vmp.utils.redis;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
/**
|
||||
* @Description:Redis工具类
|
||||
* @author: songww
|
||||
* @date: 2020年5月6日 下午8:27:29
|
||||
*/
|
||||
@Component
|
||||
public class RedisUtil {
|
||||
|
||||
@Autowired
|
||||
private RedisTemplate redisTemplate;
|
||||
|
||||
/**
|
||||
* 指定缓存失效时间
|
||||
* @param key 键
|
||||
* @param time 时间(秒)
|
||||
* @return true / false
|
||||
*/
|
||||
public boolean expire(String key, long time) {
|
||||
try {
|
||||
if (time > 0) {
|
||||
redisTemplate.expire(key, time, TimeUnit.SECONDS);
|
||||
}
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据 key 获取过期时间
|
||||
* @param key 键
|
||||
* @return
|
||||
*/
|
||||
public long getExpire(String key) {
|
||||
return redisTemplate.getExpire(key, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断 key 是否存在
|
||||
* @param key 键
|
||||
* @return true / false
|
||||
*/
|
||||
public boolean hasKey(String key) {
|
||||
try {
|
||||
return redisTemplate.hasKey(key);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除缓存
|
||||
* @SuppressWarnings("unchecked") 忽略类型转换警告
|
||||
* @param key 键(一个或者多个)
|
||||
*/
|
||||
public void del(String... key) {
|
||||
if (key != null && key.length > 0) {
|
||||
if (key.length == 1) {
|
||||
redisTemplate.delete(key[0]);
|
||||
} else {
|
||||
// 传入一个 Collection<String> 集合
|
||||
redisTemplate.delete(CollectionUtils.arrayToList(key));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ============================== String ==============================
|
||||
|
||||
/**
|
||||
* 普通缓存获取
|
||||
* @param key 键
|
||||
* @return 值
|
||||
*/
|
||||
public Object get(String key) {
|
||||
return key == null ? null : redisTemplate.opsForValue().get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 普通缓存放入
|
||||
* @param key 键
|
||||
* @param value 值
|
||||
* @return true / false
|
||||
*/
|
||||
public boolean set(String key, Object value) {
|
||||
try {
|
||||
redisTemplate.opsForValue().set(key, value);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 普通缓存放入并设置时间
|
||||
* @param key 键
|
||||
* @param value 值
|
||||
* @param time 时间(秒),如果 time < 0 则设置无限时间
|
||||
* @return true / false
|
||||
*/
|
||||
public boolean set(String key, Object value, long time) {
|
||||
try {
|
||||
if (time > 0) {
|
||||
redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
|
||||
} else {
|
||||
set(key, value);
|
||||
}
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 递增
|
||||
* @param key 键
|
||||
* @param delta 递增大小
|
||||
* @return
|
||||
*/
|
||||
public long incr(String key, long delta) {
|
||||
if (delta < 0) {
|
||||
throw new RuntimeException("递增因子必须大于 0");
|
||||
}
|
||||
return redisTemplate.opsForValue().increment(key, delta);
|
||||
}
|
||||
|
||||
/**
|
||||
* 递减
|
||||
* @param key 键
|
||||
* @param delta 递减大小
|
||||
* @return
|
||||
*/
|
||||
public long decr(String key, long delta) {
|
||||
if (delta < 0) {
|
||||
throw new RuntimeException("递减因子必须大于 0");
|
||||
}
|
||||
return redisTemplate.opsForValue().increment(key, delta);
|
||||
}
|
||||
|
||||
// ============================== Map ==============================
|
||||
|
||||
/**
|
||||
* HashGet
|
||||
* @param key 键(no null)
|
||||
* @param item 项(no null)
|
||||
* @return 值
|
||||
*/
|
||||
public Object hget(String key, String item) {
|
||||
return redisTemplate.opsForHash().get(key, item);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 key 对应的 map
|
||||
* @param key 键(no null)
|
||||
* @return 对应的多个键值
|
||||
*/
|
||||
public Map<Object, Object> hmget(String key) {
|
||||
return redisTemplate.opsForHash().entries(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* HashSet
|
||||
* @param key 键
|
||||
* @param map 值
|
||||
* @return true / false
|
||||
*/
|
||||
public boolean hmset(String key, Map<Object, Object> map) {
|
||||
try {
|
||||
redisTemplate.opsForHash().putAll(key, map);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* HashSet 并设置时间
|
||||
* @param key 键
|
||||
* @param map 值
|
||||
* @param time 时间
|
||||
* @return true / false
|
||||
*/
|
||||
public boolean hmset(String key, Map<Object, Object> map, long time) {
|
||||
try {
|
||||
redisTemplate.opsForHash().putAll(key, map);
|
||||
if (time > 0) {
|
||||
expire(key, time);
|
||||
}
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 向一张 Hash表 中放入数据,如不存在则创建
|
||||
* @param key 键
|
||||
* @param item 项
|
||||
* @param value 值
|
||||
* @return true / false
|
||||
*/
|
||||
public boolean hset(String key, String item, Object value) {
|
||||
try {
|
||||
redisTemplate.opsForHash().put(key, item, value);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 向一张 Hash表 中放入数据,并设置时间,如不存在则创建
|
||||
* @param key 键
|
||||
* @param item 项
|
||||
* @param value 值
|
||||
* @param time 时间(如果原来的 Hash表 设置了时间,这里会覆盖)
|
||||
* @return true / false
|
||||
*/
|
||||
public boolean hset(String key, String item, Object value, long time) {
|
||||
try {
|
||||
redisTemplate.opsForHash().put(key, item, value);
|
||||
if (time > 0) {
|
||||
expire(key, time);
|
||||
}
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除 Hash表 中的值
|
||||
* @param key 键
|
||||
* @param item 项(可以多个,no null)
|
||||
*/
|
||||
public void hdel(String key, Object... item) {
|
||||
redisTemplate.opsForHash().delete(key, item);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断 Hash表 中是否有该键的值
|
||||
* @param key 键(no null)
|
||||
* @param item 值(no null)
|
||||
* @return true / false
|
||||
*/
|
||||
public boolean hHasKey(String key, String item) {
|
||||
return redisTemplate.opsForHash().hasKey(key, item);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hash递增,如果不存在则创建一个,并把新增的值返回
|
||||
* @param key 键
|
||||
* @param item 项
|
||||
* @param by 递增大小 > 0
|
||||
* @return
|
||||
*/
|
||||
public Double hincr(String key, String item, Double by) {
|
||||
return redisTemplate.opsForHash().increment(key, item, by);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hash递减
|
||||
* @param key 键
|
||||
* @param item 项
|
||||
* @param by 递减大小
|
||||
* @return
|
||||
*/
|
||||
public Double hdecr(String key, String item, Double by) {
|
||||
return redisTemplate.opsForHash().increment(key, item, -by);
|
||||
}
|
||||
|
||||
// ============================== Set ==============================
|
||||
|
||||
/**
|
||||
* 根据 key 获取 set 中的所有值
|
||||
* @param key 键
|
||||
* @return 值
|
||||
*/
|
||||
public Set<Object> sGet(String key) {
|
||||
try {
|
||||
return redisTemplate.opsForSet().members(key);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从键为 key 的 set 中,根据 value 查询是否存在
|
||||
* @param key 键
|
||||
* @param value 值
|
||||
* @return true / false
|
||||
*/
|
||||
public boolean sHasKey(String key, Object value) {
|
||||
try {
|
||||
return redisTemplate.opsForSet().isMember(key, value);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将数据放入 set缓存
|
||||
* @param key 键值
|
||||
* @param values 值(可以多个)
|
||||
* @return 成功个数
|
||||
*/
|
||||
public long sSet(String key, Object... values) {
|
||||
try {
|
||||
return redisTemplate.opsForSet().add(key, values);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将数据放入 set缓存,并设置时间
|
||||
* @param key 键
|
||||
* @param time 时间
|
||||
* @param values 值(可以多个)
|
||||
* @return 成功放入个数
|
||||
*/
|
||||
public long sSet(String key, long time, Object... values) {
|
||||
try {
|
||||
long count = redisTemplate.opsForSet().add(key, values);
|
||||
if (time > 0) {
|
||||
expire(key, time);
|
||||
}
|
||||
return count;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 set缓存的长度
|
||||
* @param key 键
|
||||
* @return 长度
|
||||
*/
|
||||
public long sGetSetSize(String key) {
|
||||
try {
|
||||
return redisTemplate.opsForSet().size(key);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除 set缓存中,值为 value 的
|
||||
* @param key 键
|
||||
* @param values 值
|
||||
* @return 成功移除个数
|
||||
*/
|
||||
public long setRemove(String key, Object... values) {
|
||||
try {
|
||||
return redisTemplate.opsForSet().remove(key, values);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// ============================== List ==============================
|
||||
|
||||
/**
|
||||
* 获取 list缓存的内容
|
||||
* @param key 键
|
||||
* @param start 开始
|
||||
* @param end 结束(0 到 -1 代表所有值)
|
||||
* @return
|
||||
*/
|
||||
public List<Object> lGet(String key, long start, long end) {
|
||||
try {
|
||||
return redisTemplate.opsForList().range(key, start, end);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 list缓存的长度
|
||||
* @param key 键
|
||||
* @return 长度
|
||||
*/
|
||||
public long lGetListSize(String key) {
|
||||
try {
|
||||
return redisTemplate.opsForList().size(key);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据索引 index 获取键为 key 的 list 中的元素
|
||||
* @param key 键
|
||||
* @param index 索引
|
||||
* 当 index >= 0 时 {0:表头, 1:第二个元素}
|
||||
* 当 index < 0 时 {-1:表尾, -2:倒数第二个元素}
|
||||
* @return 值
|
||||
*/
|
||||
public Object lGetIndex(String key, long index) {
|
||||
try {
|
||||
return redisTemplate.opsForList().index(key, index);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将值 value 插入键为 key 的 list 中,如果 list 不存在则创建空 list
|
||||
* @param key 键
|
||||
* @param value 值
|
||||
* @return true / false
|
||||
*/
|
||||
public boolean lSet(String key, Object value) {
|
||||
try {
|
||||
redisTemplate.opsForList().rightPush(key, value);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将值 value 插入键为 key 的 list 中,并设置时间
|
||||
* @param key 键
|
||||
* @param value 值
|
||||
* @param time 时间
|
||||
* @return true / false
|
||||
*/
|
||||
public boolean lSet(String key, Object value, long time) {
|
||||
try {
|
||||
redisTemplate.opsForList().rightPush(key, value);
|
||||
if (time > 0) {
|
||||
expire(key, time);
|
||||
}
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将 values 插入键为 key 的 list 中
|
||||
* @param key 键
|
||||
* @param values 值
|
||||
* @return true / false
|
||||
*/
|
||||
public boolean lSetList(String key, List<Object> values) {
|
||||
try {
|
||||
redisTemplate.opsForList().rightPushAll(key, values);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将 values 插入键为 key 的 list 中,并设置时间
|
||||
* @param key 键
|
||||
* @param values 值
|
||||
* @param time 时间
|
||||
* @return true / false
|
||||
*/
|
||||
public boolean lSetList(String key, List<Object> values, long time) {
|
||||
try {
|
||||
redisTemplate.opsForList().rightPushAll(key, values);
|
||||
if (time > 0) {
|
||||
expire(key, time);
|
||||
}
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据索引 index 修改键为 key 的值
|
||||
* @param key 键
|
||||
* @param index 索引
|
||||
* @param value 值
|
||||
* @return true / false
|
||||
*/
|
||||
public boolean lUpdateIndex(String key, long index, Object value) {
|
||||
try {
|
||||
redisTemplate.opsForList().set(key, index, value);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 在键为 key 的 list 中删除值为 value 的元素
|
||||
* @param key 键
|
||||
* @param count 如果 count == 0 则删除 list 中所有值为 value 的元素
|
||||
* 如果 count > 0 则删除 list 中最左边那个值为 value 的元素
|
||||
* 如果 count < 0 则删除 list 中最右边那个值为 value 的元素
|
||||
* @param value
|
||||
* @return
|
||||
*/
|
||||
public long lRemove(String key, long count, Object value) {
|
||||
try {
|
||||
return redisTemplate.opsForList().remove(key, count, value);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 模糊查询
|
||||
* @param key 键
|
||||
* @return true / false
|
||||
*/
|
||||
public List<Object> keys(String key) {
|
||||
try {
|
||||
Set<String> set = redisTemplate.keys(key);
|
||||
return new ArrayList<>(set);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
package com.genersoft.iot.vmp.vmanager.device;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.genersoft.iot.vmp.gb28181.bean.Device;
|
||||
import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api")
|
||||
public class DeviceController {
|
||||
|
||||
private final static Logger logger = LoggerFactory.getLogger(DeviceController.class);
|
||||
|
||||
@Autowired
|
||||
private IVideoManagerStorager storager;
|
||||
|
||||
@GetMapping("/devices/{deviceId}")
|
||||
public ResponseEntity<List<Device>> devices(@PathVariable String deviceId){
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("查询视频设备API调用,deviceId:" + deviceId);
|
||||
}
|
||||
|
||||
List<Device> deviceList = new ArrayList<>();
|
||||
deviceList.add(storager.queryVideoDevice(deviceId));
|
||||
return new ResponseEntity<>(deviceList,HttpStatus.OK);
|
||||
}
|
||||
|
||||
@GetMapping("/devices")
|
||||
public ResponseEntity<List<Device>> devices(){
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("查询所有视频设备API调用");
|
||||
}
|
||||
|
||||
List<Device> deviceList = storager.queryVideoDeviceList(null);
|
||||
return new ResponseEntity<>(deviceList,HttpStatus.OK);
|
||||
}
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
package com.genersoft.iot.vmp.vmanager.play;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api")
|
||||
public class PlayController {
|
||||
|
||||
private final static Logger logger = LoggerFactory.getLogger(PlayController.class);
|
||||
|
||||
@Autowired
|
||||
private SIPCommander cmder;
|
||||
|
||||
@GetMapping("/play/{deviceId}_{channelId}")
|
||||
public ResponseEntity<String> play(@PathVariable String deviceId,@PathVariable String channelId){
|
||||
|
||||
String ssrc = cmder.playStreamCmd(deviceId, channelId);
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug(String.format("设备预览 API调用,deviceId:%s ,channelId:%s",deviceId, channelId));
|
||||
logger.debug("设备预览 API调用,ssrc:"+ssrc+",ZLMedia streamId:"+Integer.toHexString(Integer.parseInt(ssrc)));
|
||||
}
|
||||
|
||||
if(ssrc!=null) {
|
||||
return new ResponseEntity<String>(ssrc,HttpStatus.OK);
|
||||
} else {
|
||||
logger.warn("设备预览API调用失败!");
|
||||
return new ResponseEntity<String>(HttpStatus.INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
package com.genersoft.iot.vmp.vmanager.ptz;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api")
|
||||
public class PtzController {
|
||||
|
||||
private final static Logger logger = LoggerFactory.getLogger(PtzController.class);
|
||||
|
||||
@Autowired
|
||||
private SIPCommander cmder;
|
||||
|
||||
/***
|
||||
* http://localhost:8080/api/ptz/34020000001320000002_34020000001320000008?leftRight=1&upDown=0&inOut=0&moveSpeed=50&zoomSpeed=0
|
||||
* @param deviceId
|
||||
* @param channelId
|
||||
* @param leftRight
|
||||
* @param upDown
|
||||
* @param inOut
|
||||
* @param moveSpeed
|
||||
* @param zoomSpeed
|
||||
* @return
|
||||
*/
|
||||
@GetMapping("/ptz/{deviceId}_{channelId}")
|
||||
public ResponseEntity<String> ptz(@PathVariable String deviceId,@PathVariable String channelId,int leftRight, int upDown, int inOut, int moveSpeed, int zoomSpeed){
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug(String.format("设备云台控制 API调用,deviceId:%s ,channelId:%s ,leftRight:%d ,upDown:%d ,inOut:%d ,moveSpeed:%d ,zoomSpeed:%d",deviceId, channelId, leftRight, upDown, inOut, moveSpeed, zoomSpeed));
|
||||
}
|
||||
|
||||
cmder.ptzCmd(deviceId, channelId, leftRight, upDown, inOut, moveSpeed, zoomSpeed);
|
||||
return new ResponseEntity<String>("success",HttpStatus.OK);
|
||||
}
|
||||
}
|
36
src/main/resources/application.yml
Normal file
36
src/main/resources/application.yml
Normal file
@ -0,0 +1,36 @@
|
||||
spring:
|
||||
application:
|
||||
name: wvp
|
||||
# 数据存储方式,支持redis、jdbc
|
||||
database: redis
|
||||
redis:
|
||||
# Redis服务器IP
|
||||
host: 127.0.0.1
|
||||
#端口号
|
||||
port: 6379
|
||||
datebase: 0
|
||||
#访问密码,若你的redis服务器没有设置密码,就不需要用密码去连接
|
||||
password:
|
||||
#超时时间
|
||||
timeout: 10000
|
||||
datasource:
|
||||
name: wcp
|
||||
url: jdbc:mysql://127.0.0.1:3306/wcp?useUnicode=true&characterEncoding=UTF8&rewriteBatchedStatements=true
|
||||
username: root
|
||||
password: 123456
|
||||
type: com.alibaba.druid.pool.DruidDataSource
|
||||
driver-class-name: com.mysql.jdbc.Driver
|
||||
server:
|
||||
port: 8080
|
||||
sip:
|
||||
# 本地服务地址
|
||||
ip: 192.168.0.3
|
||||
server_id: 34020000002000000001
|
||||
port: 5060
|
||||
domain: 34020000
|
||||
# 暂时使用统一密码,后续改为一机一密
|
||||
password: admin
|
||||
media:
|
||||
# ZLMediaServer IP
|
||||
ip: 192.168.0.4
|
||||
port: 10000
|
Loading…
Reference in New Issue
Block a user