Commit 70091f29f2c3c3f974ffc2cc8f140db9f992ca0e

Authored by songww
0 parents

初始提交

Showing 48 changed files with 4698 additions and 0 deletions
pom.xml 0 → 100644
  1 +++ a/pom.xml
  1 +<?xml version="1.0"?>
  2 +<project
  3 + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
  4 + xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  5 + <modelVersion>4.0.0</modelVersion>
  6 + <parent>
  7 + <groupId>org.springframework.boot</groupId>
  8 + <artifactId>spring-boot-starter-parent</artifactId>
  9 + <version>1.5.10.RELEASE</version>
  10 + </parent>
  11 +
  12 + <groupId>com.genersoft</groupId>
  13 + <artifactId>wvp</artifactId>
  14 + <name>web video platform</name>
  15 +
  16 + <properties>
  17 + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  18 +
  19 + <hystrix.version>1.5.12</hystrix.version>
  20 + <!-- 依赖版本 -->
  21 + <mapper.version>3.4.0</mapper.version>
  22 + <mybatis.version>3.3.1</mybatis.version>
  23 + <mybatis.spring.version>1.2.4</mybatis.spring.version>
  24 + <pagehelper.version>4.1.1</pagehelper.version>
  25 + <snippetsDirectory>${project.build.directory}/generated-snippets</snippetsDirectory>
  26 + <asciidoctor.input.directory>${project.basedir}/docs/asciidoc</asciidoctor.input.directory>
  27 + <generated.asciidoc.directory>${project.build.directory}/asciidoc</generated.asciidoc.directory>
  28 + <asciidoctor.html.output.directory>${project.build.directory}/asciidoc/html</asciidoctor.html.output.directory>
  29 + <asciidoctor.pdf.output.directory>${project.build.directory}/asciidoc/pdf</asciidoctor.pdf.output.directory>
  30 + <gson.version>2.8.0</gson.version>
  31 + <jedis.version>3.0.1</jedis.version>
  32 + <jsonlib.version>2.4</jsonlib.version>
  33 + </properties>
  34 +
  35 + <dependencies>
  36 + <dependency>
  37 + <groupId>org.springframework.boot</groupId>
  38 + <artifactId>spring-boot-starter-jdbc</artifactId>
  39 + </dependency>
  40 + <dependency>
  41 + <groupId>org.springframework.boot</groupId>
  42 + <artifactId>spring-boot-starter-undertow</artifactId>
  43 + </dependency>
  44 + <dependency>
  45 + <groupId>org.springframework.boot</groupId>
  46 + <artifactId>spring-boot-starter-web</artifactId>
  47 + </dependency>
  48 + <dependency>
  49 + <groupId>org.springframework</groupId>
  50 + <artifactId>spring-context</artifactId>
  51 + </dependency>
  52 +
  53 +
  54 + <!-- druid -->
  55 + <dependency>
  56 + <groupId>com.alibaba</groupId>
  57 + <artifactId>druid</artifactId>
  58 + <version>1.0.11</version>
  59 + </dependency>
  60 + <dependency>
  61 + <groupId>mysql</groupId>
  62 + <artifactId>mysql-connector-java</artifactId>
  63 + <version>5.1.30</version>
  64 + </dependency>
  65 +
  66 + <!--Mybatis -->
  67 + <dependency>
  68 + <groupId>org.mybatis</groupId>
  69 + <artifactId>mybatis</artifactId>
  70 + <version>${mybatis.version}</version>
  71 + </dependency>
  72 + <dependency>
  73 + <groupId>org.mybatis</groupId>
  74 + <artifactId>mybatis-spring</artifactId>
  75 + <version>${mybatis.spring.version}</version>
  76 + </dependency>
  77 +
  78 + <!--分页插件 -->
  79 + <dependency>
  80 + <groupId>com.github.pagehelper</groupId>
  81 + <artifactId>pagehelper</artifactId>
  82 + <version>${pagehelper.version}</version>
  83 + </dependency>
  84 +
  85 + <!--通用Mapper -->
  86 + <dependency>
  87 + <groupId>tk.mybatis</groupId>
  88 + <artifactId>mapper</artifactId>
  89 + <version>${mapper.version}</version>
  90 + </dependency>
  91 + <dependency>
  92 + <groupId>org.apache.commons</groupId>
  93 + <artifactId>commons-lang3</artifactId>
  94 + <version>3.4</version>
  95 + </dependency>
  96 + <!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
  97 + <dependency>
  98 + <groupId>com.alibaba</groupId>
  99 + <artifactId>fastjson</artifactId>
  100 + <version>1.2.33</version>
  101 + </dependency>
  102 +
  103 + <!--Swagger2 -->
  104 + <!--在线文档 -->
  105 + <dependency>
  106 + <groupId>io.springfox</groupId>
  107 + <artifactId>springfox-swagger2</artifactId>
  108 + <version>2.6.1</version>
  109 + </dependency>
  110 + <dependency>
  111 + <groupId>io.springfox</groupId>
  112 + <artifactId>springfox-swagger-ui</artifactId>
  113 + <version>2.6.1</version>
  114 + </dependency>
  115 +
  116 + <!-- 日志相关 -->
  117 + <dependency>
  118 + <groupId>org.springframework.boot</groupId>
  119 + <artifactId>spring-boot-starter-aop</artifactId>
  120 + </dependency>
  121 +
  122 + <dependency>
  123 + <groupId>javax.sip</groupId>
  124 + <artifactId>jain-sip-ri</artifactId>
  125 + <version>1.3.0-91</version>
  126 + <scope>provided</scope>
  127 + </dependency>
  128 + <dependency>
  129 + <groupId>org.dom4j</groupId>
  130 + <artifactId>dom4j</artifactId>
  131 + <version>2.1.1</version>
  132 + </dependency>
  133 + <dependency>
  134 + <groupId>com.google.code.gson</groupId>
  135 + <artifactId>gson</artifactId>
  136 + </dependency>
  137 + <dependency>
  138 + <groupId>org.springframework.data</groupId>
  139 + <artifactId>spring-data-redis</artifactId>
  140 + <version>1.8.4.RELEASE</version>
  141 + </dependency>
  142 + <dependency>
  143 + <groupId>redis.clients</groupId>
  144 + <artifactId>jedis</artifactId>
  145 + <version>2.9.0</version>
  146 + </dependency>
  147 +
  148 + </dependencies>
  149 +
  150 + <build>
  151 + <plugins>
  152 +
  153 + <plugin>
  154 + <groupId>org.springframework.boot</groupId>
  155 + <artifactId>spring-boot-maven-plugin</artifactId>
  156 + </plugin>
  157 + <plugin>
  158 + <groupId>org.apache.maven.plugins</groupId>
  159 + <artifactId>maven-compiler-plugin</artifactId>
  160 + <configuration>
  161 + <source>1.8</source>
  162 + <target>1.8</target>
  163 + </configuration>
  164 + </plugin>
  165 +
  166 + <plugin>
  167 + <groupId>org.apache.maven.plugins</groupId>
  168 + <artifactId>maven-surefire-plugin</artifactId>
  169 + </plugin>
  170 +
  171 + </plugins>
  172 + </build>
  173 +</project>
src/main/java/com/genersoft/iot/vmp/VManageBootstrap.java 0 → 100644
  1 +++ a/src/main/java/com/genersoft/iot/vmp/VManageBootstrap.java
  1 +package com.genersoft.iot.vmp;
  2 +
  3 +import java.util.logging.LogManager;
  4 +
  5 +import org.springframework.boot.SpringApplication;
  6 +import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
  7 +import org.springframework.boot.autoconfigure.SpringBootApplication;
  8 +
  9 +@SpringBootApplication
  10 +//@EnableEurekaClient
  11 +//@EnableTransactionManagement
  12 +//@EnableFeignClients(basePackages = { "com.genersoft.iot.vmp", "org.integrain" })
  13 +//@ServletComponentScan("com.genersoft.iot.vmp")
  14 +@EnableAutoConfiguration
  15 +public class VManageBootstrap extends LogManager {
  16 + public static void main(String[] args) {
  17 + SpringApplication.run(VManageBootstrap.class, args);
  18 + }
  19 +
  20 +}
src/main/java/com/genersoft/iot/vmp/common/VideoManagerConstants.java 0 → 100644
  1 +++ a/src/main/java/com/genersoft/iot/vmp/common/VideoManagerConstants.java
  1 +package com.genersoft.iot.vmp.common;
  2 +
  3 +/**
  4 + * @Description:TODO(这里用一句话描述这个类的作用)
  5 + * @author: songww
  6 + * @date: 2019年5月30日 下午3:04:04
  7 + *
  8 + */
  9 +public class VideoManagerConstants {
  10 +
  11 + public static final String CACHEKEY_PREFIX = "VMP_deviceId_";
  12 +
  13 + public static final String KEEPLIVEKEY_PREFIX = "VMP_keeplive_";
  14 +
  15 + public static final String EVENT_ONLINE_REGISTER = "1";
  16 +
  17 + public static final String EVENT_ONLINE_KEEPLIVE = "2";
  18 +
  19 + public static final String EVENT_OUTLINE_UNREGISTER = "1";
  20 +
  21 + public static final String EVENT_OUTLINE_TIMEOUT = "2";
  22 +}
src/main/java/com/genersoft/iot/vmp/conf/RedisConfig.java 0 → 100644
  1 +++ a/src/main/java/com/genersoft/iot/vmp/conf/RedisConfig.java
  1 +package com.genersoft.iot.vmp.conf;
  2 +
  3 +import org.springframework.cache.annotation.CachingConfigurerSupport;
  4 +import org.springframework.context.annotation.Bean;
  5 +import org.springframework.context.annotation.Configuration;
  6 +import org.springframework.data.redis.connection.RedisConnectionFactory;
  7 +import org.springframework.data.redis.core.RedisTemplate;
  8 +import org.springframework.data.redis.listener.RedisMessageListenerContainer;
  9 +import org.springframework.data.redis.serializer.StringRedisSerializer;
  10 +
  11 +import com.alibaba.fastjson.parser.ParserConfig;
  12 +import com.genersoft.iot.vmp.utils.redis.FastJsonRedisSerializer;
  13 +
  14 +/**
  15 + * @Description:Redis中间件配置类
  16 + * @author: songww
  17 + * @date: 2019年5月30日 上午10:58:25
  18 + *
  19 + */
  20 +@Configuration
  21 +// @EnableCaching
  22 +public class RedisConfig extends CachingConfigurerSupport {
  23 +
  24 + @Bean("redisTemplate")
  25 + public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
  26 + RedisTemplate<Object, Object> template = new RedisTemplate<>();
  27 + template.setConnectionFactory(redisConnectionFactory);
  28 + ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
  29 + FastJsonRedisSerializer<Object> serializer = new FastJsonRedisSerializer<Object>(Object.class);
  30 + // value值的序列化采用fastJsonRedisSerializer
  31 + template.setValueSerializer(serializer);
  32 + template.setHashValueSerializer(serializer);
  33 + // key的序列化采用StringRedisSerializer
  34 + template.setKeySerializer(new StringRedisSerializer());
  35 + template.setHashKeySerializer(new StringRedisSerializer());
  36 +
  37 + template.setConnectionFactory(redisConnectionFactory);
  38 + return template;
  39 + }
  40 +
  41 + /**
  42 + * redis消息监听器容器 可以添加多个监听不同话题的redis监听器,只需要把消息监听器和相应的消息订阅处理器绑定,该消息监听器
  43 + * 通过反射技术调用消息订阅处理器的相关方法进行一些业务处理
  44 + *
  45 + * @param connectionFactory
  46 + * @param listenerAdapter
  47 + * @return
  48 + */
  49 + @Bean
  50 + RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory) {
  51 +
  52 + RedisMessageListenerContainer container = new RedisMessageListenerContainer();
  53 + container.setConnectionFactory(connectionFactory);
  54 + return container;
  55 + }
  56 +// @Bean
  57 +// RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory,
  58 +// MessageListenerAdapter listenerAdapter) {
  59 +//
  60 +// RedisMessageListenerContainer container = new RedisMessageListenerContainer();
  61 +// container.setConnectionFactory(connectionFactory);
  62 +// // 订阅了一个叫通道
  63 +// container.addMessageListener(listenerAdapter, new PatternTopic(VideoManagerConstants.KEEPLIVEKEY_PREFIX+"*"));
  64 +// // 这个container 可以添加多个 messageListener
  65 +// return container;
  66 +// }
  67 +
  68 +// /**
  69 +// * 消息监听器适配器,绑定消息处理器,利用反射技术调用消息处理器的业务方法
  70 +// * @param receiver
  71 +// * @return
  72 +// */
  73 +// @Bean
  74 +// MessageListenerAdapter listenerAdapter(MessageReceiver receiver) {
  75 +// //这个地方 是给messageListenerAdapter 传入一个消息接受的处理器,利用反射的方法调用“receiveMessage”
  76 +// //也有好几个重载方法,这边默认调用处理器的方法 叫handleMessage 可以自己到源码里面看
  77 +// return new MessageListenerAdapter(receiver, "receiveMessage");
  78 +// }
  79 +}
src/main/java/com/genersoft/iot/vmp/conf/SipConfig.java 0 → 100644
  1 +++ a/src/main/java/com/genersoft/iot/vmp/conf/SipConfig.java
  1 +package com.genersoft.iot.vmp.conf;
  2 +
  3 +import org.springframework.beans.factory.annotation.Value;
  4 +import org.springframework.context.annotation.Configuration;
  5 +
  6 +@Configuration
  7 +public class SipConfig {
  8 +
  9 + @Value("${sip.ip}")
  10 + String sipIp;
  11 + @Value("${sip.port}")
  12 + Integer sipPort;
  13 + @Value("${sip.domain}")
  14 + String sipDomain;
  15 + @Value("${sip.password}")
  16 + String sipPassword;
  17 + @Value("${media.ip}")
  18 + String mediaIp;
  19 +
  20 + @Value("${media.port}")
  21 + Integer mediaPort;
  22 +
  23 + @Value("${sip.ptz.speed:50}")
  24 + Integer speed;
  25 +
  26 + public String getSipIp() {
  27 + return sipIp;
  28 + }
  29 +
  30 + public void setSipIp(String sipIp) {
  31 + this.sipIp = sipIp;
  32 + }
  33 +
  34 + public Integer getSipPort() {
  35 + return sipPort;
  36 + }
  37 +
  38 + public void setSipPort(Integer sipPort) {
  39 + this.sipPort = sipPort;
  40 + }
  41 +
  42 + public String getSipDomain() {
  43 + return sipDomain;
  44 + }
  45 +
  46 + public void setSipDomain(String sipDomain) {
  47 + this.sipDomain = sipDomain;
  48 + }
  49 +
  50 + public String getSipPassword() {
  51 + return sipPassword;
  52 + }
  53 +
  54 + public void setSipPassword(String sipPassword) {
  55 + this.sipPassword = sipPassword;
  56 + }
  57 +
  58 + public String getMediaIp() {
  59 + return mediaIp;
  60 + }
  61 +
  62 + public void setMediaIp(String mediaIp) {
  63 + this.mediaIp = mediaIp;
  64 + }
  65 +
  66 + public Integer getMediaPort() {
  67 + return mediaPort;
  68 + }
  69 +
  70 + public void setMediaPort(Integer mediaPort) {
  71 + this.mediaPort = mediaPort;
  72 + }
  73 +
  74 + public Integer getSpeed() {
  75 + return speed;
  76 + }
  77 +
  78 + public void setSpeed(Integer speed) {
  79 + this.speed = speed;
  80 + }
  81 +
  82 +
  83 +}
src/main/java/com/genersoft/iot/vmp/conf/VManagerConfig.java 0 → 100644
  1 +++ a/src/main/java/com/genersoft/iot/vmp/conf/VManagerConfig.java
  1 +package com.genersoft.iot.vmp.conf;
  2 +
  3 +import org.springframework.beans.factory.annotation.Value;
  4 +import org.springframework.context.annotation.Configuration;
  5 +
  6 +/**
  7 + * @Description:TODO(这里用一句话描述这个类的作用)
  8 + * @author: songww
  9 + * @date: 2020年5月6日 下午2:46:00
  10 + */
  11 +@Configuration("vmConfig")
  12 +public class VManagerConfig {
  13 +
  14 + @Value("${spring.application.database:redis}")
  15 + private String database;
  16 +
  17 + public String getDatabase() {
  18 + return database;
  19 + }
  20 +
  21 + public void setDatabase(String database) {
  22 + this.database = database;
  23 + }
  24 +
  25 +}
src/main/java/com/genersoft/iot/vmp/gb28181/SipLayer.java 0 → 100644
  1 +++ a/src/main/java/com/genersoft/iot/vmp/gb28181/SipLayer.java
  1 +package com.genersoft.iot.vmp.gb28181;
  2 +
  3 +import java.util.Properties;
  4 +
  5 +import javax.sip.DialogTerminatedEvent;
  6 +import javax.sip.IOExceptionEvent;
  7 +import javax.sip.ListeningPoint;
  8 +import javax.sip.RequestEvent;
  9 +import javax.sip.ResponseEvent;
  10 +import javax.sip.ServerTransaction;
  11 +import javax.sip.SipFactory;
  12 +import javax.sip.SipListener;
  13 +import javax.sip.SipProvider;
  14 +import javax.sip.SipStack;
  15 +import javax.sip.TimeoutEvent;
  16 +import javax.sip.TransactionAlreadyExistsException;
  17 +import javax.sip.TransactionTerminatedEvent;
  18 +import javax.sip.TransactionUnavailableException;
  19 +import javax.sip.address.AddressFactory;
  20 +import javax.sip.header.HeaderFactory;
  21 +import javax.sip.header.ViaHeader;
  22 +import javax.sip.message.MessageFactory;
  23 +import javax.sip.message.Request;
  24 +import javax.sip.message.Response;
  25 +
  26 +import org.slf4j.Logger;
  27 +import org.slf4j.LoggerFactory;
  28 +import org.springframework.beans.factory.annotation.Autowired;
  29 +import org.springframework.context.annotation.Bean;
  30 +import org.springframework.stereotype.Component;
  31 +
  32 +import com.genersoft.iot.vmp.conf.SipConfig;
  33 +import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorFactory;
  34 +import com.genersoft.iot.vmp.gb28181.transmit.request.ISIPRequestProcessor;
  35 +import com.genersoft.iot.vmp.gb28181.transmit.response.ISIPResponseProcessor;
  36 +
  37 +import gov.nist.javax.sip.SipStackImpl;
  38 +
  39 +@Component
  40 +public class SipLayer implements SipListener{
  41 +
  42 + private final static Logger logger = LoggerFactory.getLogger(SipLayer.class);
  43 +
  44 + @Autowired
  45 + private SipConfig config;
  46 +
  47 + private SipProvider tcpSipProvider;
  48 +
  49 + private SipProvider udpSipProvider;
  50 +
  51 + @Autowired
  52 + private SIPProcessorFactory processorFactory;
  53 +
  54 + private SipStack sipStack;
  55 +
  56 + private AddressFactory addressFactory;
  57 + private HeaderFactory headerFactory;
  58 + private MessageFactory messageFactory;
  59 +
  60 + @Bean
  61 + private boolean initSipServer() throws Exception {
  62 + SipFactory sipFactory = SipFactory.getInstance();
  63 + sipFactory.setPathName("gov.nist");
  64 + headerFactory = sipFactory.createHeaderFactory();
  65 + addressFactory = sipFactory.createAddressFactory();
  66 + messageFactory = sipFactory.createMessageFactory();
  67 +
  68 + Properties properties = new Properties();
  69 + properties.setProperty("javax.sip.STACK_NAME", "GB28181_SIP");
  70 + properties.setProperty("javax.sip.IP_ADDRESS", config.getSipIp());
  71 + /**
  72 + * sip_server_log.log 和 sip_debug_log.log public static final int TRACE_NONE =
  73 + * 0; public static final int TRACE_MESSAGES = 16; public static final int
  74 + * TRACE_EXCEPTION = 17; public static final int TRACE_DEBUG = 32;
  75 + */
  76 + properties.setProperty("gov.nist.javax.sip.TRACE_LEVEL", "16");
  77 + properties.setProperty("gov.nist.javax.sip.SERVER_LOG", "sip_server_log");
  78 + properties.setProperty("gov.nist.javax.sip.DEBUG_LOG", "sip_debug_log");
  79 + sipStack = (SipStackImpl) sipFactory.createSipStack(properties);
  80 +
  81 + try {
  82 + startTcpListener();
  83 + startUdpListener();
  84 + } catch (Exception e) {
  85 + logger.error("Sip Server 启动失败! port {"+config.getSipPort()+"}");
  86 + e.printStackTrace();
  87 + throw e;
  88 + }
  89 + logger.info("Sip Server 启动成功 port {"+config.getSipPort()+"}");
  90 + return true;
  91 + }
  92 +
  93 + private void startTcpListener() throws Exception {
  94 + ListeningPoint tcpListeningPoint = sipStack.createListeningPoint(config.getSipIp(), config.getSipPort(), "TCP");
  95 + tcpSipProvider = sipStack.createSipProvider(tcpListeningPoint);
  96 + tcpSipProvider.addSipListener(this);
  97 + }
  98 +
  99 + private void startUdpListener() throws Exception {
  100 + ListeningPoint udpListeningPoint = sipStack.createListeningPoint(config.getSipIp(), config.getSipPort(), "UDP");
  101 + udpSipProvider = sipStack.createSipProvider(udpListeningPoint);
  102 + udpSipProvider.addSipListener(this);
  103 + }
  104 +
  105 + /**
  106 + * SIP服务端接收消息的方法 Content 里面是GBK编码 This method is called by the SIP stack when a
  107 + * new request arrives.
  108 + */
  109 + @Override
  110 + public void processRequest(RequestEvent evt) {
  111 + ISIPRequestProcessor processor = processorFactory.createRequestProcessor(evt);
  112 + processor.process(evt, this, getServerTransaction(evt));
  113 + }
  114 +
  115 + @Override
  116 + public void processResponse(ResponseEvent evt) {
  117 + Response response = evt.getResponse();
  118 + int status = response.getStatusCode();
  119 + if ((status >= 200) && (status < 300)) { // Success!
  120 + ISIPResponseProcessor processor = processorFactory.createResponseProcessor(evt);
  121 + processor.process(evt,this,config);
  122 + } else {
  123 + logger.warn("接收到失败的response响应!status:"+status+",message:"+response.getContent().toString());
  124 + }
  125 + //trying不会回复
  126 + if(status == Response.TRYING){
  127 +
  128 + }
  129 + }
  130 +
  131 + /**
  132 + * <p>Title: processTimeout</p>
  133 + * <p>Description: </p>
  134 + * @param timeoutEvent
  135 + */
  136 + @Override
  137 + public void processTimeout(TimeoutEvent timeoutEvent) {
  138 + // TODO Auto-generated method stub
  139 +
  140 + }
  141 +
  142 + /**
  143 + * <p>Title: processIOException</p>
  144 + * <p>Description: </p>
  145 + * @param exceptionEvent
  146 + */
  147 + @Override
  148 + public void processIOException(IOExceptionEvent exceptionEvent) {
  149 + // TODO Auto-generated method stub
  150 +
  151 + }
  152 +
  153 + /**
  154 + * <p>Title: processTransactionTerminated</p>
  155 + * <p>Description: </p>
  156 + * @param transactionTerminatedEvent
  157 + */
  158 + @Override
  159 + public void processTransactionTerminated(TransactionTerminatedEvent transactionTerminatedEvent) {
  160 + // TODO Auto-generated method stub
  161 +
  162 + }
  163 +
  164 + /**
  165 + * <p>Title: processDialogTerminated</p>
  166 + * <p>Description: </p>
  167 + * @param dialogTerminatedEvent
  168 + */
  169 + @Override
  170 + public void processDialogTerminated(DialogTerminatedEvent dialogTerminatedEvent) {
  171 + // TODO Auto-generated method stub
  172 +
  173 + }
  174 +
  175 + private ServerTransaction getServerTransaction(RequestEvent evt) {
  176 + Request request = evt.getRequest();
  177 + ServerTransaction serverTransaction = evt.getServerTransaction();
  178 + // 判断TCP还是UDP
  179 + boolean isTcp = false;
  180 + ViaHeader reqViaHeader = (ViaHeader) request.getHeader(ViaHeader.NAME);
  181 + String transport = reqViaHeader.getTransport();
  182 + if (transport.equals("TCP")) {
  183 + isTcp = true;
  184 + }
  185 +
  186 + if (serverTransaction == null) {
  187 + try {
  188 + if (isTcp) {
  189 + serverTransaction = tcpSipProvider.getNewServerTransaction(request);
  190 + } else {
  191 + serverTransaction = udpSipProvider.getNewServerTransaction(request);
  192 + }
  193 + } catch (TransactionAlreadyExistsException e) {
  194 + e.printStackTrace();
  195 + } catch (TransactionUnavailableException e) {
  196 + e.printStackTrace();
  197 + }
  198 + }
  199 + return serverTransaction;
  200 + }
  201 +
  202 +
  203 + public AddressFactory getAddressFactory() {
  204 + return addressFactory;
  205 + }
  206 +
  207 + public HeaderFactory getHeaderFactory() {
  208 + return headerFactory;
  209 + }
  210 +
  211 + public MessageFactory getMessageFactory() {
  212 + return messageFactory;
  213 + }
  214 +
  215 + public SipProvider getTcpSipProvider() {
  216 + return tcpSipProvider;
  217 + }
  218 +
  219 + public SipProvider getUdpSipProvider() {
  220 + return udpSipProvider;
  221 + }
  222 +
  223 +}
src/main/java/com/genersoft/iot/vmp/gb28181/auth/DigestServerAuthenticationHelper.java 0 → 100644
  1 +++ a/src/main/java/com/genersoft/iot/vmp/gb28181/auth/DigestServerAuthenticationHelper.java
  1 +/*
  2 +* Conditions Of Use
  3 +*
  4 +* This software was developed by employees of the National Institute of
  5 +* Standards and Technology (NIST), an agency of the Federal Government.
  6 +* Pursuant to title 15 Untied States Code Section 105, works of NIST
  7 +* employees are not subject to copyright protection in the United States
  8 +* and are considered to be in the public domain. As a result, a formal
  9 +* license is not needed to use the software.
  10 +*
  11 +* This software is provided by NIST as a service and is expressly
  12 +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED
  13 +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF
  14 +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT
  15 +* AND DATA ACCURACY. NIST does not warrant or make any representations
  16 +* regarding the use of the software or the results thereof, including but
  17 +* not limited to the correctness, accuracy, reliability or usefulness of
  18 +* the software.
  19 +*
  20 +* Permission to use this software is contingent upon your acceptance
  21 +* of the terms of this agreement
  22 +*
  23 +* .
  24 +*
  25 +*/
  26 +package com.genersoft.iot.vmp.gb28181.auth;
  27 +
  28 +import java.security.MessageDigest;
  29 +import java.security.NoSuchAlgorithmException;
  30 +import java.util.Date;
  31 +import java.util.Random;
  32 +
  33 +import javax.sip.address.URI;
  34 +import javax.sip.header.AuthorizationHeader;
  35 +import javax.sip.header.HeaderFactory;
  36 +import javax.sip.header.WWWAuthenticateHeader;
  37 +import javax.sip.message.Request;
  38 +import javax.sip.message.Response;
  39 +
  40 +import gov.nist.core.InternalErrorHandler;
  41 +
  42 +/**
  43 + * Implements the HTTP digest authentication method server side functionality.
  44 + *
  45 + * @author M. Ranganathan
  46 + * @author Marc Bednarek
  47 + */
  48 +
  49 +public class DigestServerAuthenticationHelper {
  50 +
  51 + private MessageDigest messageDigest;
  52 +
  53 + public static final String DEFAULT_ALGORITHM = "MD5";
  54 + public static final String DEFAULT_SCHEME = "Digest";
  55 +
  56 +
  57 +
  58 +
  59 + /** to hex converter */
  60 + private static final char[] toHex = { '0', '1', '2', '3', '4', '5', '6',
  61 + '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
  62 +
  63 + /**
  64 + * Default constructor.
  65 + * @throws NoSuchAlgorithmException
  66 + */
  67 + public DigestServerAuthenticationHelper()
  68 + throws NoSuchAlgorithmException {
  69 + messageDigest = MessageDigest.getInstance(DEFAULT_ALGORITHM);
  70 + }
  71 +
  72 + public static String toHexString(byte b[]) {
  73 + int pos = 0;
  74 + char[] c = new char[b.length * 2];
  75 + for (int i = 0; i < b.length; i++) {
  76 + c[pos++] = toHex[(b[i] >> 4) & 0x0F];
  77 + c[pos++] = toHex[b[i] & 0x0f];
  78 + }
  79 + return new String(c);
  80 + }
  81 +
  82 + /**
  83 + * Generate the challenge string.
  84 + *
  85 + * @return a generated nonce.
  86 + */
  87 + private String generateNonce() {
  88 + // Get the time of day and run MD5 over it.
  89 + Date date = new Date();
  90 + long time = date.getTime();
  91 + Random rand = new Random();
  92 + long pad = rand.nextLong();
  93 + String nonceString = (new Long(time)).toString()
  94 + + (new Long(pad)).toString();
  95 + byte mdbytes[] = messageDigest.digest(nonceString.getBytes());
  96 + // Convert the mdbytes array into a hex string.
  97 + return toHexString(mdbytes);
  98 + }
  99 +
  100 + public Response generateChallenge(HeaderFactory headerFactory, Response response, String realm) {
  101 + try {
  102 + WWWAuthenticateHeader proxyAuthenticate = headerFactory
  103 + .createWWWAuthenticateHeader(DEFAULT_SCHEME);
  104 + proxyAuthenticate.setParameter("realm", realm);
  105 + proxyAuthenticate.setParameter("nonce", generateNonce());
  106 + proxyAuthenticate.setParameter("opaque", "");
  107 + proxyAuthenticate.setParameter("stale", "FALSE");
  108 + proxyAuthenticate.setParameter("algorithm", DEFAULT_ALGORITHM);
  109 + response.setHeader(proxyAuthenticate);
  110 + } catch (Exception ex) {
  111 + InternalErrorHandler.handleException(ex);
  112 + }
  113 + return response;
  114 + }
  115 + /**
  116 + * Authenticate the inbound request.
  117 + *
  118 + * @param request - the request to authenticate.
  119 + * @param hashedPassword -- the MD5 hashed string of username:realm:plaintext password.
  120 + *
  121 + * @return true if authentication succeded and false otherwise.
  122 + */
  123 + public boolean doAuthenticateHashedPassword(Request request, String hashedPassword) {
  124 + AuthorizationHeader authHeader = (AuthorizationHeader) request.getHeader(AuthorizationHeader.NAME);
  125 + if ( authHeader == null ) return false;
  126 + String realm = authHeader.getRealm();
  127 + String username = authHeader.getUsername();
  128 +
  129 + if ( username == null || realm == null ) {
  130 + return false;
  131 + }
  132 +
  133 + String nonce = authHeader.getNonce();
  134 + URI uri = authHeader.getURI();
  135 + if (uri == null) {
  136 + return false;
  137 + }
  138 +
  139 +
  140 +
  141 + String A2 = request.getMethod().toUpperCase() + ":" + uri.toString();
  142 + String HA1 = hashedPassword;
  143 +
  144 +
  145 + byte[] mdbytes = messageDigest.digest(A2.getBytes());
  146 + String HA2 = toHexString(mdbytes);
  147 +
  148 + String cnonce = authHeader.getCNonce();
  149 + String KD = HA1 + ":" + nonce;
  150 + if (cnonce != null) {
  151 + KD += ":" + cnonce;
  152 + }
  153 + KD += ":" + HA2;
  154 + mdbytes = messageDigest.digest(KD.getBytes());
  155 + String mdString = toHexString(mdbytes);
  156 + String response = authHeader.getResponse();
  157 +
  158 +
  159 + return mdString.equals(response);
  160 + }
  161 +
  162 + /**
  163 + * Authenticate the inbound request given plain text password.
  164 + *
  165 + * @param request - the request to authenticate.
  166 + * @param pass -- the plain text password.
  167 + *
  168 + * @return true if authentication succeded and false otherwise.
  169 + */
  170 + public boolean doAuthenticatePlainTextPassword(Request request, String pass) {
  171 + AuthorizationHeader authHeader = (AuthorizationHeader) request.getHeader(AuthorizationHeader.NAME);
  172 + if ( authHeader == null ) return false;
  173 + String realm = authHeader.getRealm();
  174 + String username = authHeader.getUsername();
  175 +
  176 +
  177 + if ( username == null || realm == null ) {
  178 + return false;
  179 + }
  180 +
  181 +
  182 + String nonce = authHeader.getNonce();
  183 + URI uri = authHeader.getURI();
  184 + if (uri == null) {
  185 + return false;
  186 + }
  187 +
  188 +
  189 + String A1 = username + ":" + realm + ":" + pass;
  190 + String A2 = request.getMethod().toUpperCase() + ":" + uri.toString();
  191 + byte mdbytes[] = messageDigest.digest(A1.getBytes());
  192 + String HA1 = toHexString(mdbytes);
  193 +
  194 +
  195 + mdbytes = messageDigest.digest(A2.getBytes());
  196 + String HA2 = toHexString(mdbytes);
  197 +
  198 + String cnonce = authHeader.getCNonce();
  199 + String KD = HA1 + ":" + nonce;
  200 + if (cnonce != null) {
  201 + KD += ":" + cnonce;
  202 + }
  203 + KD += ":" + HA2;
  204 + mdbytes = messageDigest.digest(KD.getBytes());
  205 + String mdString = toHexString(mdbytes);
  206 + String response = authHeader.getResponse();
  207 + return mdString.equals(response);
  208 +
  209 + }
  210 +
  211 +}
src/main/java/com/genersoft/iot/vmp/gb28181/bean/Device.java 0 → 100644
  1 +++ a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/Device.java
  1 +package com.genersoft.iot.vmp.gb28181.bean;
  2 +
  3 +import java.util.Map;
  4 +
  5 +
  6 +public class Device {
  7 +
  8 + /**
  9 + * 设备Id
  10 + */
  11 + private String deviceId;
  12 +
  13 + /**
  14 + * 设备名
  15 + */
  16 + private String name;
  17 +
  18 + /**
  19 + * 生产厂商
  20 + */
  21 + private String manufacturer;
  22 +
  23 + /**
  24 + * 型号
  25 + */
  26 + private String model;
  27 +
  28 + /**
  29 + * 固件版本
  30 + */
  31 + private String firmware;
  32 +
  33 + /**
  34 + * 传输协议
  35 + * UDP/TCP
  36 + */
  37 + private String transport;
  38 +
  39 + /**
  40 + * wan地址
  41 + */
  42 + private Host host;
  43 +
  44 + /**
  45 + * 在线
  46 + */
  47 + private int online;
  48 +
  49 + /**
  50 + * 通道列表
  51 + */
  52 + private Map<String,DeviceChannel> channelMap;
  53 +
  54 +
  55 + public String getDeviceId() {
  56 + return deviceId;
  57 + }
  58 +
  59 + public void setDeviceId(String deviceId) {
  60 + this.deviceId = deviceId;
  61 + }
  62 +
  63 + public String getName() {
  64 + return name;
  65 + }
  66 +
  67 + public void setName(String name) {
  68 + this.name = name;
  69 + }
  70 +
  71 + public String getTransport() {
  72 + return transport;
  73 + }
  74 +
  75 + public void setTransport(String transport) {
  76 + this.transport = transport;
  77 + }
  78 +
  79 + public Host getHost() {
  80 + return host;
  81 + }
  82 +
  83 + public void setHost(Host host) {
  84 + this.host = host;
  85 + }
  86 +
  87 + public Map<String, DeviceChannel> getChannelMap() {
  88 + return channelMap;
  89 + }
  90 +
  91 + public void setChannelMap(Map<String, DeviceChannel> channelMap) {
  92 + this.channelMap = channelMap;
  93 + }
  94 +
  95 + public String getManufacturer() {
  96 + return manufacturer;
  97 + }
  98 +
  99 + public void setManufacturer(String manufacturer) {
  100 + this.manufacturer = manufacturer;
  101 + }
  102 +
  103 + public String getModel() {
  104 + return model;
  105 + }
  106 +
  107 + public void setModel(String model) {
  108 + this.model = model;
  109 + }
  110 +
  111 + public String getFirmware() {
  112 + return firmware;
  113 + }
  114 +
  115 + public void setFirmware(String firmware) {
  116 + this.firmware = firmware;
  117 + }
  118 +
  119 + public int getOnline() {
  120 + return online;
  121 + }
  122 +
  123 + public void setOnline(int online) {
  124 + this.online = online;
  125 + }
  126 +}
src/main/java/com/genersoft/iot/vmp/gb28181/bean/DeviceAlarm.java 0 → 100644
  1 +++ a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/DeviceAlarm.java
  1 +package com.genersoft.iot.vmp.gb28181.bean;
  2 +
  3 +public class DeviceAlarm {
  4 +
  5 + /**
  6 + * 设备Id
  7 + */
  8 + private String deviceId;
  9 +
  10 + /**
  11 + * 报警级别, 1为一级警情, 2为二级警情, 3为三级警情, 4为四级 警情-
  12 + */
  13 + private String alarmPriorit;
  14 +
  15 + /**
  16 + * 报警方式 , 1为电话报警, 2为设备报警, 3为短信报警, 4为 GPS报警, 5为视频报警, 6为设备故障报警,
  17 + * 7其他报警;可以为直接组合如12为电话报警或 设备报警-
  18 + */
  19 + private String alarmMethod;
  20 +
  21 + /**
  22 + * 报警时间
  23 + */
  24 + private String alarmTime;
  25 +
  26 + /**
  27 + * 报警内容描述
  28 + */
  29 + private String alarmDescription;
  30 +
  31 + /**
  32 + * 经度
  33 + */
  34 + private double longitude;
  35 +
  36 + /**
  37 + * 纬度
  38 + */
  39 + private double latitude;
  40 +
  41 + /**
  42 + * 报警类型
  43 + */
  44 + private String alarmType;
  45 +
  46 + public String getDeviceId() {
  47 + return deviceId;
  48 + }
  49 +
  50 + public void setDeviceId(String deviceId) {
  51 + this.deviceId = deviceId;
  52 + }
  53 +
  54 + public String getAlarmPriorit() {
  55 + return alarmPriorit;
  56 + }
  57 +
  58 + public void setAlarmPriorit(String alarmPriorit) {
  59 + this.alarmPriorit = alarmPriorit;
  60 + }
  61 +
  62 + public String getAlarmMethod() {
  63 + return alarmMethod;
  64 + }
  65 +
  66 + public void setAlarmMethod(String alarmMethod) {
  67 + this.alarmMethod = alarmMethod;
  68 + }
  69 +
  70 + public String getAlarmTime() {
  71 + return alarmTime;
  72 + }
  73 +
  74 + public void setAlarmTime(String alarmTime) {
  75 + this.alarmTime = alarmTime;
  76 + }
  77 +
  78 + public String getAlarmDescription() {
  79 + return alarmDescription;
  80 + }
  81 +
  82 + public void setAlarmDescription(String alarmDescription) {
  83 + this.alarmDescription = alarmDescription;
  84 + }
  85 +
  86 + public double getLongitude() {
  87 + return longitude;
  88 + }
  89 +
  90 + public void setLongitude(double longitude) {
  91 + this.longitude = longitude;
  92 + }
  93 +
  94 + public double getLatitude() {
  95 + return latitude;
  96 + }
  97 +
  98 + public void setLatitude(double latitude) {
  99 + this.latitude = latitude;
  100 + }
  101 +
  102 + public String getAlarmType() {
  103 + return alarmType;
  104 + }
  105 +
  106 + public void setAlarmType(String alarmType) {
  107 + this.alarmType = alarmType;
  108 + }
  109 +
  110 +}
src/main/java/com/genersoft/iot/vmp/gb28181/bean/DeviceChannel.java 0 → 100644
  1 +++ a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/DeviceChannel.java
  1 +package com.genersoft.iot.vmp.gb28181.bean;
  2 +
  3 +public class DeviceChannel {
  4 +
  5 + /**
  6 + * 通道id
  7 + */
  8 + private String channelId;
  9 +
  10 + /**
  11 + * 通道名
  12 + */
  13 + private String name;
  14 +
  15 + /**
  16 + * 生产厂商
  17 + */
  18 + private String manufacture;
  19 +
  20 + /**
  21 + * 型号
  22 + */
  23 + private String model;
  24 +
  25 + /**
  26 + * 设备归属
  27 + */
  28 + private String owner;
  29 +
  30 + /**
  31 + * 行政区域
  32 + */
  33 + private String civilCode;
  34 +
  35 + /**
  36 + * 警区
  37 + */
  38 + private String block;
  39 +
  40 + /**
  41 + * 安装地址
  42 + */
  43 + private String address;
  44 +
  45 + /**
  46 + * 是否有子设备 1有, 0没有
  47 + */
  48 + private int parental;
  49 +
  50 + /**
  51 + * 父级id
  52 + */
  53 + private String parentId;
  54 +
  55 + /**
  56 + * 信令安全模式 缺省为0; 0:不采用; 2: S/MIME签名方式; 3: S/ MIME加密签名同时采用方式; 4:数字摘要方式
  57 + */
  58 + private int safetyWay;
  59 +
  60 + /**
  61 + * 注册方式 缺省为1;1:符合IETFRFC3261标准的认证注册模 式; 2:基于口令的双向认证注册模式; 3:基于数字证书的双向认证注册模式
  62 + */
  63 + private int registerWay;
  64 +
  65 + /**
  66 + * 证书序列号
  67 + */
  68 + private String certNum;
  69 +
  70 + /**
  71 + * 证书有效标识 缺省为0;证书有效标识:0:无效1: 有效
  72 + */
  73 + private int certifiable;
  74 +
  75 + /**
  76 + * 证书无效原因码
  77 + */
  78 + private int errCode;
  79 +
  80 + /**
  81 + * 证书终止有效期
  82 + */
  83 + private String endTime;
  84 +
  85 + /**
  86 + * 保密属性 缺省为0; 0:不涉密, 1:涉密
  87 + */
  88 + private String secrecy;
  89 +
  90 + /**
  91 + * IP地址
  92 + */
  93 + private String ipAddress;
  94 +
  95 + /**
  96 + * 端口号
  97 + */
  98 + private int port;
  99 +
  100 + /**
  101 + * 密码
  102 + */
  103 + private String password;
  104 +
  105 + /**
  106 + * 在线/离线
  107 + * 1在线,0离线
  108 + * 默认在线
  109 + * 信令:
  110 + * <Status>ON</Status>
  111 + * <Status>OFF</Status>
  112 + * 遇到过NVR下的IPC下发信令可以推流, 但是 Status 响应 OFF
  113 + */
  114 + private int status;
  115 +
  116 + /**
  117 + * 经度
  118 + */
  119 + private double longitude;
  120 +
  121 + /**
  122 + * 纬度
  123 + */
  124 + private double latitude;
  125 +
  126 + public String getChannelId() {
  127 + return channelId;
  128 + }
  129 +
  130 + public void setChannelId(String channelId) {
  131 + this.channelId = channelId;
  132 + }
  133 +
  134 + public String getName() {
  135 + return name;
  136 + }
  137 +
  138 + public void setName(String name) {
  139 + this.name = name;
  140 + }
  141 +
  142 + public int getStatus() {
  143 + return status;
  144 + }
  145 +
  146 + public void setStatus(int status) {
  147 + this.status = status;
  148 + }
  149 +
  150 + public String getManufacture() {
  151 + return manufacture;
  152 + }
  153 +
  154 + public void setManufacture(String manufacture) {
  155 + this.manufacture = manufacture;
  156 + }
  157 +
  158 + public String getModel() {
  159 + return model;
  160 + }
  161 +
  162 + public void setModel(String model) {
  163 + this.model = model;
  164 + }
  165 +
  166 + public String getOwner() {
  167 + return owner;
  168 + }
  169 +
  170 + public void setOwner(String owner) {
  171 + this.owner = owner;
  172 + }
  173 +
  174 + public String getCivilCode() {
  175 + return civilCode;
  176 + }
  177 +
  178 + public void setCivilCode(String civilCode) {
  179 + this.civilCode = civilCode;
  180 + }
  181 +
  182 + public String getBlock() {
  183 + return block;
  184 + }
  185 +
  186 + public void setBlock(String block) {
  187 + this.block = block;
  188 + }
  189 +
  190 + public String getAddress() {
  191 + return address;
  192 + }
  193 +
  194 + public void setAddress(String address) {
  195 + this.address = address;
  196 + }
  197 +
  198 + public int getParental() {
  199 + return parental;
  200 + }
  201 +
  202 + public void setParental(int parental) {
  203 + this.parental = parental;
  204 + }
  205 +
  206 + public String getParentId() {
  207 + return parentId;
  208 + }
  209 +
  210 + public void setParentId(String parentId) {
  211 + this.parentId = parentId;
  212 + }
  213 +
  214 + public int getSafetyWay() {
  215 + return safetyWay;
  216 + }
  217 +
  218 + public void setSafetyWay(int safetyWay) {
  219 + this.safetyWay = safetyWay;
  220 + }
  221 +
  222 + public int getRegisterWay() {
  223 + return registerWay;
  224 + }
  225 +
  226 + public void setRegisterWay(int registerWay) {
  227 + this.registerWay = registerWay;
  228 + }
  229 +
  230 + public String getCertNum() {
  231 + return certNum;
  232 + }
  233 +
  234 + public void setCertNum(String certNum) {
  235 + this.certNum = certNum;
  236 + }
  237 +
  238 + public int getCertifiable() {
  239 + return certifiable;
  240 + }
  241 +
  242 + public void setCertifiable(int certifiable) {
  243 + this.certifiable = certifiable;
  244 + }
  245 +
  246 + public int getErrCode() {
  247 + return errCode;
  248 + }
  249 +
  250 + public void setErrCode(int errCode) {
  251 + this.errCode = errCode;
  252 + }
  253 +
  254 + public String getEndTime() {
  255 + return endTime;
  256 + }
  257 +
  258 + public void setEndTime(String endTime) {
  259 + this.endTime = endTime;
  260 + }
  261 +
  262 + public String getSecrecy() {
  263 + return secrecy;
  264 + }
  265 +
  266 + public void setSecrecy(String secrecy) {
  267 + this.secrecy = secrecy;
  268 + }
  269 +
  270 + public String getIpAddress() {
  271 + return ipAddress;
  272 + }
  273 +
  274 + public void setIpAddress(String ipAddress) {
  275 + this.ipAddress = ipAddress;
  276 + }
  277 +
  278 + public int getPort() {
  279 + return port;
  280 + }
  281 +
  282 + public void setPort(int port) {
  283 + this.port = port;
  284 + }
  285 +
  286 + public String getPassword() {
  287 + return password;
  288 + }
  289 +
  290 + public void setPassword(String password) {
  291 + this.password = password;
  292 + }
  293 +
  294 + public double getLongitude() {
  295 + return longitude;
  296 + }
  297 +
  298 + public void setLongitude(double longitude) {
  299 + this.longitude = longitude;
  300 + }
  301 +
  302 + public double getLatitude() {
  303 + return latitude;
  304 + }
  305 +
  306 + public void setLatitude(double latitude) {
  307 + this.latitude = latitude;
  308 + }
  309 +}
src/main/java/com/genersoft/iot/vmp/gb28181/bean/Host.java 0 → 100644
  1 +++ a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/Host.java
  1 +package com.genersoft.iot.vmp.gb28181.bean;
  2 +
  3 +public class Host {
  4 +
  5 + private String ip;
  6 + private int port;
  7 + private String address;
  8 +
  9 + public String getIp() {
  10 + return ip;
  11 + }
  12 + public void setIp(String ip) {
  13 + this.ip = ip;
  14 + }
  15 + public int getPort() {
  16 + return port;
  17 + }
  18 + public void setPort(int port) {
  19 + this.port = port;
  20 + }
  21 + public String getAddress() {
  22 + return address;
  23 + }
  24 + public void setAddress(String address) {
  25 + this.address = address;
  26 + }
  27 +
  28 +
  29 +
  30 +}
src/main/java/com/genersoft/iot/vmp/gb28181/event/EventPublisher.java 0 → 100644
  1 +++ a/src/main/java/com/genersoft/iot/vmp/gb28181/event/EventPublisher.java
  1 +package com.genersoft.iot.vmp.gb28181.event;
  2 +
  3 +import org.springframework.beans.factory.annotation.Autowired;
  4 +import org.springframework.context.ApplicationEventPublisher;
  5 +import org.springframework.stereotype.Component;
  6 +
  7 +import com.genersoft.iot.vmp.gb28181.event.online.OnlineEvent;
  8 +import com.genersoft.iot.vmp.gb28181.event.outline.OutlineEvent;
  9 +
  10 +/**
  11 + * @Description:Event事件通知推送器,支持推送在线事件、离线事件
  12 + * @author: songww
  13 + * @date: 2020年5月6日 上午11:30:50
  14 + */
  15 +@Component
  16 +public class EventPublisher {
  17 +
  18 + @Autowired
  19 + private ApplicationEventPublisher applicationEventPublisher;
  20 +
  21 + public void onlineEventPublish(String deviceId, String from) {
  22 + OnlineEvent onEvent = new OnlineEvent(this);
  23 + onEvent.setDeviceId(deviceId);
  24 + onEvent.setFrom(from);
  25 + applicationEventPublisher.publishEvent(onEvent);
  26 + }
  27 +
  28 + public void outlineEventPublish(String deviceId, String from){
  29 + OutlineEvent outEvent = new OutlineEvent(this);
  30 + outEvent.setDeviceId(deviceId);
  31 + outEvent.setFrom(from);
  32 + applicationEventPublisher.publishEvent(outEvent);
  33 + }
  34 +}
src/main/java/com/genersoft/iot/vmp/gb28181/event/online/OnlineEvent.java 0 → 100644
  1 +++ a/src/main/java/com/genersoft/iot/vmp/gb28181/event/online/OnlineEvent.java
  1 +package com.genersoft.iot.vmp.gb28181.event.online;
  2 +
  3 +import org.springframework.context.ApplicationEvent;
  4 +
  5 +/**
  6 + * @Description:TODO(这里用一句话描述这个类的作用)
  7 + * @author: songww
  8 + * @date: 2020年5月6日 上午11:32:56
  9 + */
  10 +public class OnlineEvent extends ApplicationEvent {
  11 +
  12 + /**
  13 + * @Title: OnlineEvent
  14 + * @Description: TODO(这里用一句话描述这个方法的作用)
  15 + * @param: @param source
  16 + * @throws
  17 + */
  18 + public OnlineEvent(Object source) {
  19 + super(source);
  20 + }
  21 +
  22 + private String deviceId;
  23 +
  24 + private String from;
  25 +
  26 + public String getDeviceId() {
  27 + return deviceId;
  28 + }
  29 +
  30 + public void setDeviceId(String deviceId) {
  31 + this.deviceId = deviceId;
  32 + }
  33 +
  34 + public String getFrom() {
  35 + return from;
  36 + }
  37 +
  38 + public void setFrom(String from) {
  39 + this.from = from;
  40 + }
  41 +
  42 +}
src/main/java/com/genersoft/iot/vmp/gb28181/event/online/OnlineEventListener.java 0 → 100644
  1 +++ a/src/main/java/com/genersoft/iot/vmp/gb28181/event/online/OnlineEventListener.java
  1 +package com.genersoft.iot.vmp.gb28181.event.online;
  2 +
  3 +import org.slf4j.Logger;
  4 +import org.slf4j.LoggerFactory;
  5 +import org.springframework.beans.factory.annotation.Autowired;
  6 +import org.springframework.context.ApplicationListener;
  7 +import org.springframework.stereotype.Component;
  8 +
  9 +import com.genersoft.iot.vmp.common.VideoManagerConstants;
  10 +import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
  11 +import com.genersoft.iot.vmp.utils.redis.RedisUtil;
  12 +
  13 +/**
  14 + * @Description: 在线事件监听器,监听到离线后,修改设备离在线状态。 设备在线有两个来源:
  15 + * 1、设备主动注销,发送注销指令,{@link com.genersoft.iot.vmp.gb28181.transmit.request.impl.RegisterRequestProcessor}
  16 + * 2、设备未知原因离线,心跳超时,{@link com.genersoft.iot.vmp.gb28181.transmit.request.impl.MessageRequestProcessor}
  17 + * @author: songww
  18 + * @date: 2020年5月6日 下午1:51:23
  19 + */
  20 +@Component
  21 +public class OnlineEventListener implements ApplicationListener<OnlineEvent> {
  22 +
  23 + private final static Logger logger = LoggerFactory.getLogger(OnlineEventListener.class);
  24 +
  25 + @Autowired
  26 + private IVideoManagerStorager storager;
  27 +
  28 + @Autowired
  29 + private RedisUtil redis;
  30 +
  31 + @Override
  32 + public void onApplicationEvent(OnlineEvent event) {
  33 +
  34 + if (logger.isDebugEnabled()) {
  35 + logger.debug("设备离线事件触发,deviceId:" + event.getDeviceId() + ",from:" + event.getFrom());
  36 + }
  37 +
  38 + String key = VideoManagerConstants.KEEPLIVEKEY_PREFIX + event.getDeviceId();
  39 + boolean needUpdateStorager = false;
  40 +
  41 + switch (event.getFrom()) {
  42 + // 注册时触发的在线事件,先在redis中增加超时超时监听
  43 + case VideoManagerConstants.EVENT_ONLINE_REGISTER:
  44 + // TODO 超时时间暂时写死为180秒
  45 + redis.set(key, event.getDeviceId(), 180);
  46 + needUpdateStorager = true;
  47 + break;
  48 + // 设备主动发送心跳触发的离线事件
  49 + case VideoManagerConstants.EVENT_ONLINE_KEEPLIVE:
  50 + boolean exist = redis.hasKey(key);
  51 + // 先判断是否还存在,当设备先心跳超时后又发送心跳时,redis没有监听,需要增加
  52 + if (!exist) {
  53 + needUpdateStorager = true;
  54 + redis.set(key, event.getDeviceId(), 180);
  55 + } else {
  56 + redis.expire(key, 180);
  57 + }
  58 + break;
  59 + }
  60 +
  61 + if (needUpdateStorager) {
  62 + // 处理离线监听
  63 + storager.online(event.getDeviceId());
  64 + }
  65 + }
  66 +}
src/main/java/com/genersoft/iot/vmp/gb28181/event/outline/KeepliveTimeoutListener.java 0 → 100644
  1 +++ a/src/main/java/com/genersoft/iot/vmp/gb28181/event/outline/KeepliveTimeoutListener.java
  1 +package com.genersoft.iot.vmp.gb28181.event.outline;
  2 +
  3 +import org.springframework.beans.factory.annotation.Autowired;
  4 +import org.springframework.data.redis.connection.Message;
  5 +import org.springframework.data.redis.listener.KeyExpirationEventMessageListener;
  6 +import org.springframework.data.redis.listener.RedisMessageListenerContainer;
  7 +import org.springframework.stereotype.Component;
  8 +
  9 +import com.genersoft.iot.vmp.common.VideoManagerConstants;
  10 +import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
  11 +
  12 +/**
  13 + * @Description:设备心跳超时监听,借助redis过期特性,进行监听,监听到说明设备心跳超时,发送离线事件
  14 + * @author: songww
  15 + * @date: 2020年5月6日 上午11:35:46
  16 + */
  17 +@Component
  18 +public class KeepliveTimeoutListener extends KeyExpirationEventMessageListener {
  19 +
  20 + @Autowired
  21 + private EventPublisher publisher;
  22 +
  23 + public KeepliveTimeoutListener(RedisMessageListenerContainer listenerContainer) {
  24 + super(listenerContainer);
  25 + }
  26 +
  27 + /**
  28 + * 监听失效的key,key格式为keeplive_deviceId
  29 + * @param message
  30 + * @param pattern
  31 + */
  32 + @Override
  33 + public void onMessage(Message message, byte[] pattern) {
  34 + // 获取失效的key
  35 + String expiredKey = message.toString();
  36 + if(!expiredKey.startsWith(VideoManagerConstants.KEEPLIVEKEY_PREFIX)){
  37 + System.out.println("收到redis过期监听,但开头不是"+VideoManagerConstants.KEEPLIVEKEY_PREFIX+",忽略");
  38 + return;
  39 + }
  40 +
  41 + String deviceId = expiredKey.substring(VideoManagerConstants.KEEPLIVEKEY_PREFIX.length(),expiredKey.length());
  42 + publisher.outlineEventPublish(deviceId, VideoManagerConstants.EVENT_OUTLINE_TIMEOUT);
  43 + }
  44 +}
src/main/java/com/genersoft/iot/vmp/gb28181/event/outline/OutlineEvent.java 0 → 100644
  1 +++ a/src/main/java/com/genersoft/iot/vmp/gb28181/event/outline/OutlineEvent.java
  1 +package com.genersoft.iot.vmp.gb28181.event.outline;
  2 +
  3 +import org.springframework.context.ApplicationEvent;
  4 +
  5 +/**
  6 + * @Description:TODO(这里用一句话描述这个类的作用)
  7 + * @author: songww
  8 + * @date: 2020年5月6日 上午11:33:13
  9 + */
  10 +public class OutlineEvent extends ApplicationEvent {
  11 +
  12 + /**
  13 + * @Title: OutlineEvent
  14 + * @Description: TODO(这里用一句话描述这个方法的作用)
  15 + * @param: @param source
  16 + * @throws
  17 + */
  18 + public OutlineEvent(Object source) {
  19 + super(source);
  20 + }
  21 +
  22 + private String deviceId;
  23 +
  24 + private String from;
  25 +
  26 + public String getDeviceId() {
  27 + return deviceId;
  28 + }
  29 +
  30 + public void setDeviceId(String deviceId) {
  31 + this.deviceId = deviceId;
  32 + }
  33 +
  34 + public String getFrom() {
  35 + return from;
  36 + }
  37 +
  38 + public void setFrom(String from) {
  39 + this.from = from;
  40 + }
  41 +}
src/main/java/com/genersoft/iot/vmp/gb28181/event/outline/OutlineEventListener.java 0 → 100644
  1 +++ a/src/main/java/com/genersoft/iot/vmp/gb28181/event/outline/OutlineEventListener.java
  1 +package com.genersoft.iot.vmp.gb28181.event.outline;
  2 +
  3 +import org.slf4j.Logger;
  4 +import org.slf4j.LoggerFactory;
  5 +import org.springframework.beans.factory.annotation.Autowired;
  6 +import org.springframework.context.ApplicationListener;
  7 +import org.springframework.stereotype.Component;
  8 +
  9 +import com.genersoft.iot.vmp.common.VideoManagerConstants;
  10 +import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
  11 +import com.genersoft.iot.vmp.utils.redis.RedisUtil;
  12 +
  13 +/**
  14 + * @Description: 离线事件监听器,监听到离线后,修改设备离在线状态。 设备离线有两个来源:
  15 + * 1、设备主动注销,发送注销指令,{@link com.genersoft.iot.vmp.gb28181.transmit.request.impl.RegisterRequestProcessor}
  16 + * 2、设备未知原因离线,心跳超时,{@link com.genersoft.iot.vmp.gb28181.event.outline.OutlineEventListener}
  17 + * @author: songww
  18 + * @date: 2020年5月6日 下午1:51:23
  19 + */
  20 +@Component
  21 +public class OutlineEventListener implements ApplicationListener<OutlineEvent> {
  22 +
  23 + private final static Logger logger = LoggerFactory.getLogger(OutlineEventListener.class);
  24 +
  25 + @Autowired
  26 + private IVideoManagerStorager storager;
  27 +
  28 + @Autowired
  29 + private RedisUtil redis;
  30 +
  31 + @Override
  32 + public void onApplicationEvent(OutlineEvent event) {
  33 +
  34 + if (logger.isDebugEnabled()) {
  35 + logger.debug("设备离线事件触发,deviceId:" + event.getDeviceId() + ",from:" + event.getFrom());
  36 + }
  37 +
  38 + String key = VideoManagerConstants.KEEPLIVEKEY_PREFIX + event.getDeviceId();
  39 +
  40 + switch (event.getFrom()) {
  41 + // 心跳超时触发的离线事件,说明redis中已删除,无需处理
  42 + case VideoManagerConstants.EVENT_OUTLINE_TIMEOUT:
  43 + break;
  44 + // 设备主动注销触发的离线事件,需要删除redis中的超时监听
  45 + case VideoManagerConstants.EVENT_OUTLINE_UNREGISTER:
  46 + redis.del(key);
  47 + break;
  48 + default:
  49 + boolean exist = redis.hasKey(key);
  50 + if (exist) {
  51 + redis.del(key);
  52 + }
  53 + }
  54 +
  55 + // 处理离线监听
  56 + storager.outline(event.getDeviceId());
  57 + }
  58 +}
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPProcessorFactory.java 0 → 100644
  1 +++ a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPProcessorFactory.java
  1 +package com.genersoft.iot.vmp.gb28181.transmit;
  2 +
  3 +import javax.sip.RequestEvent;
  4 +import javax.sip.ResponseEvent;
  5 +import javax.sip.header.CSeqHeader;
  6 +import javax.sip.message.Request;
  7 +import javax.sip.message.Response;
  8 +
  9 +import org.springframework.beans.factory.annotation.Autowired;
  10 +import org.springframework.stereotype.Component;
  11 +
  12 +import com.genersoft.iot.vmp.gb28181.transmit.request.ISIPRequestProcessor;
  13 +import com.genersoft.iot.vmp.gb28181.transmit.request.impl.AckRequestProcessor;
  14 +import com.genersoft.iot.vmp.gb28181.transmit.request.impl.ByeRequestProcessor;
  15 +import com.genersoft.iot.vmp.gb28181.transmit.request.impl.CancelRequestProcessor;
  16 +import com.genersoft.iot.vmp.gb28181.transmit.request.impl.InviteRequestProcessor;
  17 +import com.genersoft.iot.vmp.gb28181.transmit.request.impl.MessageRequestProcessor;
  18 +import com.genersoft.iot.vmp.gb28181.transmit.request.impl.OtherRequestProcessor;
  19 +import com.genersoft.iot.vmp.gb28181.transmit.request.impl.RegisterRequestProcessor;
  20 +import com.genersoft.iot.vmp.gb28181.transmit.request.impl.SubscribeRequestProcessor;
  21 +import com.genersoft.iot.vmp.gb28181.transmit.response.ISIPResponseProcessor;
  22 +import com.genersoft.iot.vmp.gb28181.transmit.response.impl.ByeResponseProcessor;
  23 +import com.genersoft.iot.vmp.gb28181.transmit.response.impl.CancelResponseProcessor;
  24 +import com.genersoft.iot.vmp.gb28181.transmit.response.impl.InviteResponseProcessor;
  25 +import com.genersoft.iot.vmp.gb28181.transmit.response.impl.OtherResponseProcessor;
  26 +
  27 +/**
  28 + * @Description:TODO(这里用一句话描述这个类的作用)
  29 + * @author: songww
  30 + * @date: 2020年5月3日 下午4:24:37
  31 + */
  32 +@Component
  33 +public class SIPProcessorFactory {
  34 +
  35 + @Autowired
  36 + private InviteRequestProcessor inviteRequestProcessor;
  37 +
  38 + @Autowired
  39 + private RegisterRequestProcessor registerRequestProcessor;
  40 +
  41 + @Autowired
  42 + private SubscribeRequestProcessor subscribeRequestProcessor;
  43 +
  44 + @Autowired
  45 + private AckRequestProcessor ackRequestProcessor;
  46 +
  47 + @Autowired
  48 + private ByeRequestProcessor byeRequestProcessor;
  49 +
  50 + @Autowired
  51 + private CancelRequestProcessor cancelRequestProcessor;
  52 +
  53 + @Autowired
  54 + private MessageRequestProcessor messageRequestProcessor;
  55 +
  56 + @Autowired
  57 + private OtherRequestProcessor otherRequestProcessor;
  58 +
  59 + @Autowired
  60 + private InviteResponseProcessor inviteResponseProcessor;
  61 +
  62 + @Autowired
  63 + private ByeResponseProcessor byeResponseProcessor;
  64 +
  65 + @Autowired
  66 + private CancelResponseProcessor cancelResponseProcessor;
  67 +
  68 + @Autowired
  69 + private OtherResponseProcessor otherResponseProcessor;
  70 +
  71 +
  72 + public ISIPRequestProcessor createRequestProcessor(RequestEvent evt) {
  73 + Request request = evt.getRequest();
  74 + String method = request.getMethod();
  75 +
  76 + if (Request.INVITE.equals(method)) {
  77 + return inviteRequestProcessor;
  78 + } else if (Request.REGISTER.equals(method)) {
  79 + return registerRequestProcessor;
  80 + } else if (Request.SUBSCRIBE.equals(method)) {
  81 + return subscribeRequestProcessor;
  82 + } else if (Request.ACK.equals(method)) {
  83 + return ackRequestProcessor;
  84 + } else if (Request.BYE.equals(method)) {
  85 + return byeRequestProcessor;
  86 + } else if (Request.CANCEL.equals(method)) {
  87 + return cancelRequestProcessor;
  88 + } else if (Request.MESSAGE.equals(method)) {
  89 + return messageRequestProcessor;
  90 + } else {
  91 + return otherRequestProcessor;
  92 + }
  93 + }
  94 +
  95 + public ISIPResponseProcessor createResponseProcessor(ResponseEvent evt) {
  96 + Response response = evt.getResponse();
  97 + CSeqHeader cseqHeader = (CSeqHeader) response.getHeader(CSeqHeader.NAME);
  98 + String method = cseqHeader.getMethod();
  99 + if(Request.INVITE.equals(method)){
  100 + return inviteResponseProcessor;
  101 + } else if (Request.BYE.equals(method)) {
  102 + return byeResponseProcessor;
  103 + } else if (Request.CANCEL.equals(method)) {
  104 + return cancelResponseProcessor;
  105 + } else {
  106 + return otherResponseProcessor;
  107 + }
  108 + }
  109 +
  110 +}
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java 0 → 100644
  1 +++ a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java
  1 +package com.genersoft.iot.vmp.gb28181.transmit.cmd;
  2 +
  3 +import com.genersoft.iot.vmp.gb28181.bean.Device;
  4 +
  5 +/**
  6 + * @Description:设备能力接口,用于定义设备的控制、查询能力
  7 + * @author: songww
  8 + * @date: 2020年5月3日 下午9:16:34
  9 + */
  10 +public interface ISIPCommander {
  11 +
  12 + /**
  13 + * 云台方向放控制,使用配置文件中的默认镜头移动速度
  14 + *
  15 + * @param deviceId 控制设备
  16 + * @param channelId 预览通道
  17 + * @param leftRight 镜头左移右移 0:停止 1:左移 2:右移
  18 + * @param upDown 镜头上移下移 0:停止 1:上移 2:下移
  19 + * @param moveSpeed 镜头移动速度
  20 + */
  21 + public boolean ptzdirectCmd(String deviceId,String channelId,int leftRight, int upDown);
  22 +
  23 + /**
  24 + * 云台方向放控制
  25 + *
  26 + * @param deviceId 控制设备
  27 + * @param channelId 预览通道
  28 + * @param leftRight 镜头左移右移 0:停止 1:左移 2:右移
  29 + * @param upDown 镜头上移下移 0:停止 1:上移 2:下移
  30 + * @param moveSpeed 镜头移动速度
  31 + */
  32 + public boolean ptzdirectCmd(String deviceId,String channelId,int leftRight, int upDown, int moveSpeed);
  33 +
  34 + /**
  35 + * 云台缩放控制,使用配置文件中的默认镜头缩放速度
  36 + *
  37 + * @param deviceId 控制设备
  38 + * @param channelId 预览通道
  39 + * @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大
  40 + */
  41 + public boolean ptzZoomCmd(String deviceId,String channelId,int inOut);
  42 +
  43 + /**
  44 + * 云台缩放控制
  45 + *
  46 + * @param deviceId 控制设备
  47 + * @param channelId 预览通道
  48 + * @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大
  49 + * @param zoomSpeed 镜头缩放速度
  50 + */
  51 + public boolean ptzZoomCmd(String deviceId,String channelId,int inOut, int moveSpeed);
  52 +
  53 + /**
  54 + * 云台控制,支持方向与缩放控制
  55 + *
  56 + * @param deviceId 控制设备
  57 + * @param channelId 预览通道
  58 + * @param leftRight 镜头左移右移 0:停止 1:左移 2:右移
  59 + * @param upDown 镜头上移下移 0:停止 1:上移 2:下移
  60 + * @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大
  61 + * @param moveSpeed 镜头移动速度
  62 + * @param zoomSpeed 镜头缩放速度
  63 + */
  64 + public boolean ptzCmd(String deviceId,String channelId,int leftRight, int upDown, int inOut, int moveSpeed, int zoomSpeed);
  65 +
  66 + /**
  67 + * 请求预览视频流
  68 + *
  69 + * @param deviceId 视频设备
  70 + * @param channelId 预览通道
  71 + */
  72 + public String playStreamCmd(String deviceId,String channelId);
  73 +
  74 + /**
  75 + * 语音广播
  76 + *
  77 + * @param deviceId 视频设备
  78 + * @param channelId 预览通道
  79 + */
  80 + public String audioBroadcastCmd(String deviceId,String channelId);
  81 +
  82 + /**
  83 + * 音视频录像控制
  84 + *
  85 + * @param deviceId 视频设备
  86 + * @param channelId 预览通道
  87 + */
  88 + public String recordCmd(String deviceId,String channelId);
  89 +
  90 + /**
  91 + * 报警布防/撤防命令
  92 + *
  93 + * @param deviceId 视频设备
  94 + */
  95 + public String guardCmd(String deviceId);
  96 +
  97 + /**
  98 + * 报警复位命令
  99 + *
  100 + * @param deviceId 视频设备
  101 + */
  102 + public String alarmCmd(String deviceId);
  103 +
  104 + /**
  105 + * 强制关键帧命令,设备收到此命令应立刻发送一个IDR帧
  106 + *
  107 + * @param deviceId 视频设备
  108 + * @param channelId 预览通道
  109 + */
  110 + public String iFameCmd(String deviceId,String channelId);
  111 +
  112 + /**
  113 + * 看守位控制命令
  114 + *
  115 + * @param deviceId 视频设备
  116 + */
  117 + public String homePositionCmd(String deviceId);
  118 +
  119 + /**
  120 + * 设备配置命令
  121 + *
  122 + * @param deviceId 视频设备
  123 + */
  124 + public String deviceConfigCmd(String deviceId);
  125 +
  126 +
  127 + /**
  128 + * 查询设备状态
  129 + *
  130 + * @param device 视频设备
  131 + */
  132 + public boolean deviceStatusQuery(Device device);
  133 +
  134 + /**
  135 + * 查询设备信息
  136 + *
  137 + * @param device 视频设备
  138 + * @return
  139 + */
  140 + public boolean deviceInfoQuery(Device device);
  141 +
  142 + /**
  143 + * 查询目录列表
  144 + *
  145 + * @param device 视频设备
  146 + */
  147 + public boolean catalogQuery(Device device);
  148 +
  149 + /**
  150 + * 查询录像信息
  151 + *
  152 + * @param device 视频设备
  153 + */
  154 + public boolean recordInfoQuery(Device device);
  155 +
  156 + /**
  157 + * 查询报警信息
  158 + *
  159 + * @param device 视频设备
  160 + */
  161 + public boolean alarmInfoQuery(Device device);
  162 +
  163 + /**
  164 + * 查询设备配置
  165 + *
  166 + * @param device 视频设备
  167 + */
  168 + public boolean configQuery(Device device);
  169 +
  170 + /**
  171 + * 查询设备预置位置
  172 + *
  173 + * @param device 视频设备
  174 + */
  175 + public boolean presetQuery(Device device);
  176 +
  177 + /**
  178 + * 查询移动设备位置数据
  179 + *
  180 + * @param device 视频设备
  181 + */
  182 + public boolean mobilePostitionQuery(Device device);
  183 +}
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderProvider.java 0 → 100644
  1 +++ a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderProvider.java
  1 +package com.genersoft.iot.vmp.gb28181.transmit.cmd;
  2 +
  3 +import java.text.ParseException;
  4 +import java.util.ArrayList;
  5 +
  6 +import javax.sip.InvalidArgumentException;
  7 +import javax.sip.address.Address;
  8 +import javax.sip.address.SipURI;
  9 +import javax.sip.header.CSeqHeader;
  10 +import javax.sip.header.CallIdHeader;
  11 +import javax.sip.header.ContentTypeHeader;
  12 +import javax.sip.header.FromHeader;
  13 +import javax.sip.header.MaxForwardsHeader;
  14 +import javax.sip.header.ToHeader;
  15 +import javax.sip.header.ViaHeader;
  16 +import javax.sip.message.Request;
  17 +
  18 +import org.springframework.beans.factory.annotation.Autowired;
  19 +import org.springframework.stereotype.Component;
  20 +
  21 +import com.genersoft.iot.vmp.conf.SipConfig;
  22 +import com.genersoft.iot.vmp.gb28181.SipLayer;
  23 +import com.genersoft.iot.vmp.gb28181.bean.Device;
  24 +import com.genersoft.iot.vmp.gb28181.bean.Host;
  25 +
  26 +/**
  27 + * @Description:TODO(这里用一句话描述这个类的作用)
  28 + * @author: songww
  29 + * @date: 2020年5月6日 上午9:29:02
  30 + */
  31 +@Component
  32 +public class SIPRequestHeaderProvider {
  33 +
  34 + @Autowired
  35 + private SipLayer layer;
  36 +
  37 + @Autowired
  38 + private SipConfig config;
  39 +
  40 + public Request createMessageRequest(Device device, String content, String viaTag, String fromTag, String toTag) throws ParseException, InvalidArgumentException {
  41 + Request request = null;
  42 + Host host = device.getHost();
  43 + // sipuri
  44 + SipURI requestURI = layer.getAddressFactory().createSipURI(device.getDeviceId(), host.getAddress());
  45 + // via
  46 + ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();
  47 + ViaHeader viaHeader = layer.getHeaderFactory().createViaHeader(config.getSipIp(), config.getSipPort(),
  48 + device.getTransport(), viaTag);
  49 + viaHeaders.add(viaHeader);
  50 + // from
  51 + SipURI fromSipURI = layer.getAddressFactory().createSipURI(device.getDeviceId(),
  52 + config.getSipIp() + ":" + config.getSipPort());
  53 + Address fromAddress = layer.getAddressFactory().createAddress(fromSipURI);
  54 + FromHeader fromHeader = layer.getHeaderFactory().createFromHeader(fromAddress, fromTag);
  55 + // to
  56 + SipURI toSipURI = layer.getAddressFactory().createSipURI(device.getDeviceId(), host.getAddress());
  57 + Address toAddress = layer.getAddressFactory().createAddress(toSipURI);
  58 + ToHeader toHeader = layer.getHeaderFactory().createToHeader(toAddress, toTag);
  59 + // callid
  60 + CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? layer.getTcpSipProvider().getNewCallId()
  61 + : layer.getUdpSipProvider().getNewCallId();
  62 + // Forwards
  63 + MaxForwardsHeader maxForwards = layer.getHeaderFactory().createMaxForwardsHeader(70);
  64 + // ceq
  65 + CSeqHeader cSeqHeader = layer.getHeaderFactory().createCSeqHeader(1L, Request.MESSAGE);
  66 +
  67 + request = layer.getMessageFactory().createRequest(requestURI, Request.MESSAGE, callIdHeader, cSeqHeader, fromHeader,
  68 + toHeader, viaHeaders, maxForwards);
  69 + ContentTypeHeader contentTypeHeader = layer.getHeaderFactory().createContentTypeHeader("Application", "MANSCDP+xml");
  70 + request.setContent(content, contentTypeHeader);
  71 + return request;
  72 + }
  73 +
  74 + public Request createInviteRequest(Device device, String content, String viaTag, String fromTag, String toTag) throws ParseException, InvalidArgumentException {
  75 + Request request = null;
  76 + Host host = device.getHost();
  77 + //请求行
  78 + SipURI requestLine = layer.getAddressFactory().createSipURI(device.getDeviceId(), host.getAddress());
  79 + //via
  80 + ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();
  81 + ViaHeader viaHeader = layer.getHeaderFactory().createViaHeader(config.getSipIp(), config.getSipPort(), device.getTransport(), viaTag);
  82 + viaHeader.setRPort();
  83 + viaHeaders.add(viaHeader);
  84 + //from
  85 + SipURI fromSipURI = layer.getAddressFactory().createSipURI(device.getDeviceId(),config.getSipIp()+":"+config.getSipPort());
  86 + Address fromAddress = layer.getAddressFactory().createAddress(fromSipURI);
  87 + FromHeader fromHeader = layer.getHeaderFactory().createFromHeader(fromAddress, fromTag); //必须要有标记,否则无法创建会话,无法回应ack
  88 + //to
  89 + SipURI toSipURI = layer.getAddressFactory().createSipURI(device.getDeviceId(),host.getAddress());
  90 + Address toAddress = layer.getAddressFactory().createAddress(toSipURI);
  91 + ToHeader toHeader = layer.getHeaderFactory().createToHeader(toAddress,null);
  92 +
  93 + //callid
  94 + CallIdHeader callIdHeader = null;
  95 + if(device.getTransport().equals("TCP")) {
  96 + callIdHeader = layer.getTcpSipProvider().getNewCallId();
  97 + }
  98 + if(device.getTransport().equals("UDP")) {
  99 + callIdHeader = layer.getUdpSipProvider().getNewCallId();
  100 + }
  101 +
  102 + //Forwards
  103 + MaxForwardsHeader maxForwards = layer.getHeaderFactory().createMaxForwardsHeader(70);
  104 + //ceq
  105 + CSeqHeader cSeqHeader = layer.getHeaderFactory().createCSeqHeader(1L, Request.INVITE);
  106 + request = layer.getMessageFactory().createRequest(requestLine, Request.INVITE, callIdHeader, cSeqHeader,fromHeader, toHeader, viaHeaders, maxForwards);
  107 + ContentTypeHeader contentTypeHeader = layer.getHeaderFactory().createContentTypeHeader("Application", "SDP");
  108 + request.setContent(content, contentTypeHeader);
  109 + return request;
  110 + }
  111 +}
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/PtzCmdHelper.java 0 → 100644
  1 +++ a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/PtzCmdHelper.java
  1 +package com.genersoft.iot.vmp.gb28181.transmit.cmd.impl;
  2 +
  3 +public class PtzCmdHelper {
  4 + /**
  5 + *
  6 + * @param leftRight 镜头左移右移 0:停止 1:左移 2:右移
  7 + * @param upDown 镜头上移下移 0:停止 1:上移 2:下移
  8 + * @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大
  9 + * @param moveSpeed 镜头移动速度 默认 0XFF (0-255)
  10 + * @param zoomSpeed 镜头缩放速度 默认 0X1 (0-255)
  11 + * @return
  12 + */
  13 + //云台控制发送了消息,相机会一直执行,直到其他命令或者发送了停止命令,切记要考虑这个机制
  14 + public static String create(int leftRight, int upDown, int inOut, int moveSpeed, int zoomSpeed) {
  15 + int cmdCode = 0;
  16 + if (leftRight == 2) cmdCode|=0x01; // 右移
  17 + else if(leftRight == 1) cmdCode|=0x02; // 左移
  18 + if (upDown == 2) cmdCode|=0x04; // 下移
  19 + else if(upDown == 1) cmdCode|=0x08; // 上移
  20 + if (inOut == 2) cmdCode |= 0x10; // 放大
  21 + else if(inOut == 1) cmdCode |= 0x20; // 缩小
  22 + char[] szCmd = new char[16];
  23 + String strTmp;
  24 + szCmd[0] = 'A'; //字节1 A5
  25 + szCmd[1] = '5';
  26 + szCmd[2] = '0'; //字节2 0F
  27 + szCmd[3] = 'F';
  28 + szCmd[4] = '0'; //字节3 地址的低8位
  29 + szCmd[5] = '1';
  30 + strTmp = String.format("%02X", cmdCode);
  31 + szCmd[6] = strTmp.charAt(0); //字节4 控制码
  32 + szCmd[7] = strTmp.charAt(1);
  33 + strTmp = String.format("%02X", moveSpeed);
  34 + szCmd[8] = strTmp.charAt(0); //字节5 水平控制速度
  35 + szCmd[9] = strTmp.charAt(1);
  36 + szCmd[10] = strTmp.charAt(0); //字节6 垂直控制速度
  37 + szCmd[11] = strTmp.charAt(1);
  38 + strTmp = String.format("%X", zoomSpeed);
  39 + szCmd[12] = strTmp.charAt(0); //字节7高4位 缩放控制速度
  40 + szCmd[13] = '0'; //字节7低4位 地址的高4位
  41 + //计算校验码
  42 + int nCheck = (0XA5 + 0X0F + 0X01 + cmdCode + moveSpeed + moveSpeed + (zoomSpeed << 4 & 0XF0)) % 0X100;
  43 + strTmp = String.format("%02X", nCheck);
  44 + szCmd[14] = strTmp.charAt(0); //字节8 校验码
  45 + szCmd[15] = strTmp.charAt(1);
  46 + return String.valueOf(szCmd);
  47 + }
  48 +}
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java 0 → 100644
  1 +++ a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java
  1 +package com.genersoft.iot.vmp.gb28181.transmit.cmd.impl;
  2 +
  3 +import java.text.ParseException;
  4 +import java.util.Random;
  5 +
  6 +import javax.sip.InvalidArgumentException;
  7 +import javax.sip.SipException;
  8 +import javax.sip.message.Request;
  9 +
  10 +import org.springframework.beans.factory.annotation.Autowired;
  11 +import org.springframework.stereotype.Component;
  12 +
  13 +import com.genersoft.iot.vmp.conf.SipConfig;
  14 +import com.genersoft.iot.vmp.gb28181.SipLayer;
  15 +import com.genersoft.iot.vmp.gb28181.bean.Device;
  16 +import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander;
  17 +import com.genersoft.iot.vmp.gb28181.transmit.cmd.SIPRequestHeaderProvider;
  18 +import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
  19 +
  20 +/**
  21 + * @Description:设备能力接口,用于定义设备的控制、查询能力
  22 + * @author: songww
  23 + * @date: 2020年5月3日 下午9:22:48
  24 + */
  25 +@Component
  26 +public class SIPCommander implements ISIPCommander {
  27 +
  28 + @Autowired
  29 + private SipConfig config;
  30 +
  31 + @Autowired
  32 + private SIPRequestHeaderProvider headerProvider;
  33 +
  34 + @Autowired
  35 + private SipLayer sipLayer;
  36 +
  37 + @Autowired
  38 + private IVideoManagerStorager storager;
  39 +
  40 + /**
  41 + * 云台方向放控制,使用配置文件中的默认镜头移动速度
  42 + *
  43 + * @param deviceId 控制设备
  44 + * @param channelId 预览通道
  45 + * @param leftRight 镜头左移右移 0:停止 1:左移 2:右移
  46 + * @param upDown 镜头上移下移 0:停止 1:上移 2:下移
  47 + * @param moveSpeed 镜头移动速度
  48 + */
  49 + @Override
  50 + public boolean ptzdirectCmd(String deviceId, String channelId, int leftRight, int upDown) {
  51 + return ptzCmd(deviceId, channelId, leftRight, upDown, 0, config.getSpeed(), 0);
  52 + }
  53 +
  54 + /**
  55 + * 云台方向放控制
  56 + *
  57 + * @param deviceId 控制设备
  58 + * @param channelId 预览通道
  59 + * @param leftRight 镜头左移右移 0:停止 1:左移 2:右移
  60 + * @param upDown 镜头上移下移 0:停止 1:上移 2:下移
  61 + * @param moveSpeed 镜头移动速度
  62 + */
  63 + @Override
  64 + public boolean ptzdirectCmd(String deviceId, String channelId, int leftRight, int upDown, int moveSpeed) {
  65 + return ptzCmd(deviceId, channelId, leftRight, upDown, 0, moveSpeed, 0);
  66 + }
  67 +
  68 + /**
  69 + * 云台缩放控制,使用配置文件中的默认镜头缩放速度
  70 + *
  71 + * @param deviceId 控制设备
  72 + * @param channelId 预览通道
  73 + * @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大
  74 + */
  75 + @Override
  76 + public boolean ptzZoomCmd(String deviceId, String channelId, int inOut) {
  77 + return ptzCmd(deviceId, channelId, 0, 0, inOut, 0, config.getSpeed());
  78 + }
  79 +
  80 + /**
  81 + * 云台缩放控制
  82 + *
  83 + * @param deviceId 控制设备
  84 + * @param channelId 预览通道
  85 + * @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大
  86 + * @param zoomSpeed 镜头缩放速度
  87 + */
  88 + @Override
  89 + public boolean ptzZoomCmd(String deviceId, String channelId, int inOut, int zoomSpeed) {
  90 + return ptzCmd(deviceId, channelId, 0, 0, inOut, 0, zoomSpeed);
  91 + }
  92 +
  93 + /**
  94 + * 云台控制,支持方向与缩放控制
  95 + *
  96 + * @param deviceId 控制设备
  97 + * @param channelId 预览通道
  98 + * @param leftRight 镜头左移右移 0:停止 1:左移 2:右移
  99 + * @param upDown 镜头上移下移 0:停止 1:上移 2:下移
  100 + * @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大
  101 + * @param moveSpeed 镜头移动速度
  102 + * @param zoomSpeed 镜头缩放速度
  103 + */
  104 + @Override
  105 + public boolean ptzCmd(String deviceId, String channelId, int leftRight, int upDown, int inOut, int moveSpeed,
  106 + int zoomSpeed) {
  107 + try {
  108 + Device device = storager.queryVideoDevice(deviceId);
  109 + StringBuffer ptzXml = new StringBuffer(200);
  110 + ptzXml.append("<?xml version=\"1.0\" ?>");
  111 + ptzXml.append("<Control>");
  112 + ptzXml.append("<CmdType>DeviceControl</CmdType>");
  113 + ptzXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>");
  114 + ptzXml.append("<DeviceID>" + channelId + "</DeviceID>");
  115 + ptzXml.append("<PTZCmd>" + PtzCmdHelper.create(leftRight, upDown, inOut, moveSpeed, zoomSpeed) + "</PTZCmd>");
  116 + ptzXml.append("<Info>");
  117 + ptzXml.append("</Info>");
  118 + ptzXml.append("</Control>");
  119 +
  120 + Request request = headerProvider.createMessageRequest(device, ptzXml.toString(), "ViaPtzBranch", "FromPtzTag", "ToPtzTag");
  121 +
  122 + transmitRequest(device.getTransport(), request);
  123 +
  124 + return true;
  125 + } catch (SipException | ParseException | InvalidArgumentException e) {
  126 + e.printStackTrace();
  127 + }
  128 + return false;
  129 + }
  130 +
  131 + /**
  132 + * 请求预览视频流
  133 + *
  134 + * @param deviceId 视频设备
  135 + * @param channelId 预览通道
  136 + */
  137 + @Override
  138 + public String playStreamCmd(String deviceId, String channelId) {
  139 + try {
  140 +
  141 + Device device = storager.queryVideoDevice(deviceId);
  142 +
  143 + //生成ssrc标识数据流 10位数字
  144 + String ssrc = "";
  145 + Random random = new Random();
  146 + // ZLMediaServer最大识别7FFFFFFF即2147483647,所以随机数不能超过这个数
  147 + ssrc = String.valueOf(random.nextInt(2147483647));
  148 + //
  149 + StringBuffer content = new StringBuffer(200);
  150 + content.append("v=0\r\n");
  151 + content.append("o="+channelId+" 0 0 IN IP4 "+config.getSipIp()+"\r\n");
  152 + content.append("s=Play\r\n");
  153 + content.append("c=IN IP4 "+config.getMediaIp()+"\r\n");
  154 + content.append("t=0 0\r\n");
  155 + if(device.getTransport().equals("TCP")) {
  156 + content.append("m=video "+config.getMediaPort()+" TCP/RTP/AVP 96 98 97\r\n");
  157 + }
  158 + if(device.getTransport().equals("UDP")) {
  159 + content.append("m=video "+config.getMediaPort()+" RTP/AVP 96 98 97\r\n");
  160 + }
  161 + content.append("a=sendrecv\r\n");
  162 + content.append("a=rtpmap:96 PS/90000\r\n");
  163 + content.append("a=rtpmap:98 H264/90000\r\n");
  164 + content.append("a=rtpmap:97 MPEG4/90000\r\n");
  165 + if(device.getTransport().equals("TCP")){
  166 + content.append("a=setup:passive\r\n");
  167 + content.append("a=connection:new\r\n");
  168 + }
  169 + content.append("y="+ssrc+"\r\n");//ssrc
  170 +
  171 + Request request = headerProvider.createInviteRequest(device, content.toString(), null, "live", null);
  172 +
  173 + transmitRequest(device.getTransport(), request);
  174 + return ssrc;
  175 + } catch ( SipException | ParseException | InvalidArgumentException e) {
  176 + e.printStackTrace();
  177 + return null;
  178 + }
  179 + }
  180 +
  181 + /**
  182 + * 语音广播
  183 + *
  184 + * @param deviceId 视频设备
  185 + * @param channelId 预览通道
  186 + */
  187 + @Override
  188 + public String audioBroadcastCmd(String deviceId, String channelId) {
  189 + // TODO Auto-generated method stub
  190 + return null;
  191 + }
  192 +
  193 + /**
  194 + * 音视频录像控制
  195 + *
  196 + * @param deviceId 视频设备
  197 + * @param channelId 预览通道
  198 + */
  199 + @Override
  200 + public String recordCmd(String deviceId, String channelId) {
  201 + // TODO Auto-generated method stub
  202 + return null;
  203 + }
  204 +
  205 + /**
  206 + * 报警布防/撤防命令
  207 + *
  208 + * @param deviceId 视频设备
  209 + */
  210 + @Override
  211 + public String guardCmd(String deviceId) {
  212 + // TODO Auto-generated method stub
  213 + return null;
  214 + }
  215 +
  216 + /**
  217 + * 报警复位命令
  218 + *
  219 + * @param deviceId 视频设备
  220 + */
  221 + @Override
  222 + public String alarmCmd(String deviceId) {
  223 + // TODO Auto-generated method stub
  224 + return null;
  225 + }
  226 +
  227 + /**
  228 + * 强制关键帧命令,设备收到此命令应立刻发送一个IDR帧
  229 + *
  230 + * @param deviceId 视频设备
  231 + * @param channelId 预览通道
  232 + */
  233 + @Override
  234 + public String iFameCmd(String deviceId, String channelId) {
  235 + // TODO Auto-generated method stub
  236 + return null;
  237 + }
  238 +
  239 + /**
  240 + * 看守位控制命令
  241 + *
  242 + * @param deviceId 视频设备
  243 + */
  244 + @Override
  245 + public String homePositionCmd(String deviceId) {
  246 + // TODO Auto-generated method stub
  247 + return null;
  248 + }
  249 +
  250 + /**
  251 + * 设备配置命令
  252 + *
  253 + * @param deviceId 视频设备
  254 + */
  255 + @Override
  256 + public String deviceConfigCmd(String deviceId) {
  257 + // TODO Auto-generated method stub
  258 + return null;
  259 + }
  260 +
  261 + /**
  262 + * 查询设备状态
  263 + *
  264 + * @param device 视频设备
  265 + */
  266 + @Override
  267 + public boolean deviceStatusQuery(Device device) {
  268 + // TODO Auto-generated method stub
  269 + return false;
  270 + }
  271 +
  272 + /**
  273 + * 查询设备信息
  274 + *
  275 + * @param device 视频设备
  276 + */
  277 + @Override
  278 + public boolean deviceInfoQuery(Device device) {
  279 + try {
  280 + StringBuffer catalogXml = new StringBuffer(200);
  281 + catalogXml.append("<?xml version=\"1.0\" encoding=\"GB2312\"?>");
  282 + catalogXml.append("<Query>");
  283 + catalogXml.append("<CmdType>DeviceInfo</CmdType>");
  284 + catalogXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>");
  285 + catalogXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>");
  286 + catalogXml.append("</Query>");
  287 +
  288 + Request request = headerProvider.createMessageRequest(device, catalogXml.toString(), "ViaDeviceInfoBranch", "FromDeviceInfoTag", "ToDeviceInfoTag");
  289 +
  290 + transmitRequest(device.getTransport(), request);
  291 + } catch (SipException | ParseException | InvalidArgumentException e) {
  292 + e.printStackTrace();
  293 + return false;
  294 + }
  295 + return true;
  296 + }
  297 +
  298 + /**
  299 + * 查询目录列表
  300 + *
  301 + * @param device 视频设备
  302 + */
  303 + @Override
  304 + public boolean catalogQuery(Device device) {
  305 + try {
  306 + StringBuffer catalogXml = new StringBuffer(200);
  307 + catalogXml.append("<?xml version=\"1.0\" encoding=\"GB2312\"?>");
  308 + catalogXml.append("<Query>");
  309 + catalogXml.append("<CmdType>Catalog</CmdType>");
  310 + catalogXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>");
  311 + catalogXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>");
  312 + catalogXml.append("</Query>");
  313 +
  314 + Request request = headerProvider.createMessageRequest(device, catalogXml.toString(), "ViaCatalogBranch", "FromCatalogTag", "ToCatalogTag");
  315 +
  316 + transmitRequest(device.getTransport(), request);
  317 +
  318 + } catch (SipException | ParseException | InvalidArgumentException e) {
  319 + e.printStackTrace();
  320 + return false;
  321 + }
  322 + return true;
  323 + }
  324 +
  325 + /**
  326 + * 查询录像信息
  327 + *
  328 + * @param device 视频设备
  329 + */
  330 + @Override
  331 + public boolean recordInfoQuery(Device device) {
  332 + // TODO Auto-generated method stub
  333 + return false;
  334 + }
  335 +
  336 + /**
  337 + * 查询报警信息
  338 + *
  339 + * @param device 视频设备
  340 + */
  341 + @Override
  342 + public boolean alarmInfoQuery(Device device) {
  343 + // TODO Auto-generated method stub
  344 + return false;
  345 + }
  346 +
  347 + /**
  348 + * 查询设备配置
  349 + *
  350 + * @param device 视频设备
  351 + */
  352 + @Override
  353 + public boolean configQuery(Device device) {
  354 + // TODO Auto-generated method stub
  355 + return false;
  356 + }
  357 +
  358 + /**
  359 + * 查询设备预置位置
  360 + *
  361 + * @param device 视频设备
  362 + */
  363 + @Override
  364 + public boolean presetQuery(Device device) {
  365 + // TODO Auto-generated method stub
  366 + return false;
  367 + }
  368 +
  369 + /**
  370 + * 查询移动设备位置数据
  371 + *
  372 + * @param device 视频设备
  373 + */
  374 + @Override
  375 + public boolean mobilePostitionQuery(Device device) {
  376 + // TODO Auto-generated method stub
  377 + return false;
  378 + }
  379 +
  380 + private void transmitRequest(String transport, Request request) throws SipException {
  381 + if(transport.equals("TCP")) {
  382 + sipLayer.getTcpSipProvider().sendRequest(request);
  383 + } else if(transport.equals("UDP")) {
  384 + sipLayer.getUdpSipProvider().sendRequest(request);
  385 + }
  386 + }
  387 +}
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/ISIPRequestProcessor.java 0 → 100644
  1 +++ a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/ISIPRequestProcessor.java
  1 +package com.genersoft.iot.vmp.gb28181.transmit.request;
  2 +
  3 +import javax.sip.RequestEvent;
  4 +import javax.sip.ServerTransaction;
  5 +
  6 +import com.genersoft.iot.vmp.gb28181.SipLayer;
  7 +
  8 +/**
  9 + * @Description:处理接收IPCamera发来的SIP协议请求消息
  10 + * @author: songww
  11 + * @date: 2020年5月3日 下午4:42:22
  12 + */
  13 +public interface ISIPRequestProcessor {
  14 +
  15 + public void process(RequestEvent evt, SipLayer layer, ServerTransaction transaction);
  16 +
  17 +}
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/AckRequestProcessor.java 0 → 100644
  1 +++ a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/AckRequestProcessor.java
  1 +package com.genersoft.iot.vmp.gb28181.transmit.request.impl;
  2 +
  3 +import javax.sip.Dialog;
  4 +import javax.sip.InvalidArgumentException;
  5 +import javax.sip.RequestEvent;
  6 +import javax.sip.ServerTransaction;
  7 +import javax.sip.SipException;
  8 +import javax.sip.message.Request;
  9 +
  10 +import org.springframework.stereotype.Component;
  11 +
  12 +import com.genersoft.iot.vmp.gb28181.SipLayer;
  13 +import com.genersoft.iot.vmp.gb28181.transmit.request.ISIPRequestProcessor;
  14 +
  15 +import gov.nist.javax.sip.header.CSeq;
  16 +
  17 +/**
  18 + * @Description:ACK请求处理器
  19 + * @author: songww
  20 + * @date: 2020年5月3日 下午5:31:45
  21 + */
  22 +@Component
  23 +public class AckRequestProcessor implements ISIPRequestProcessor {
  24 +
  25 + /**
  26 + * 处理 ACK请求
  27 + *
  28 + * @param evt
  29 + * @param layer
  30 + * @param transaction
  31 + * @param config
  32 + */
  33 + @Override
  34 + public void process(RequestEvent evt, SipLayer layer, ServerTransaction transaction) {
  35 + Request request = evt.getRequest();
  36 + Dialog dialog = evt.getDialog();
  37 + try {
  38 + Request ackRequest = null;
  39 + CSeq csReq = (CSeq) request.getHeader(CSeq.NAME);
  40 + ackRequest = dialog.createAck(csReq.getSeqNumber());
  41 + dialog.sendAck(ackRequest);
  42 + System.out.println("send ack to callee:" + ackRequest.toString());
  43 + } catch (SipException e) {
  44 + e.printStackTrace();
  45 + } catch (InvalidArgumentException e) {
  46 + e.printStackTrace();
  47 + }
  48 +
  49 + }
  50 +
  51 +}
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/ByeRequestProcessor.java 0 → 100644
  1 +++ a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/ByeRequestProcessor.java
  1 +package com.genersoft.iot.vmp.gb28181.transmit.request.impl;
  2 +
  3 +import javax.sip.RequestEvent;
  4 +import javax.sip.ServerTransaction;
  5 +
  6 +import org.springframework.stereotype.Component;
  7 +
  8 +import com.genersoft.iot.vmp.gb28181.SipLayer;
  9 +import com.genersoft.iot.vmp.gb28181.transmit.request.ISIPRequestProcessor;
  10 +
  11 +/**
  12 + * @Description: BYE请求处理器
  13 + * @author: songww
  14 + * @date: 2020年5月3日 下午5:32:05
  15 + */
  16 +@Component
  17 +public class ByeRequestProcessor implements ISIPRequestProcessor {
  18 +
  19 + /**
  20 + * 处理BYE请求
  21 + *
  22 + * @param evt
  23 + * @param layer
  24 + * @param transaction
  25 + * @param config
  26 + */
  27 + @Override
  28 + public void process(RequestEvent evt, SipLayer layer, ServerTransaction transaction) {
  29 + // TODO Auto-generated method stub
  30 +
  31 + }
  32 +
  33 +}
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/CancelRequestProcessor.java 0 → 100644
  1 +++ a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/CancelRequestProcessor.java
  1 +package com.genersoft.iot.vmp.gb28181.transmit.request.impl;
  2 +
  3 +import javax.sip.RequestEvent;
  4 +import javax.sip.ServerTransaction;
  5 +
  6 +import org.springframework.stereotype.Component;
  7 +
  8 +import com.genersoft.iot.vmp.gb28181.SipLayer;
  9 +import com.genersoft.iot.vmp.gb28181.transmit.request.ISIPRequestProcessor;
  10 +
  11 +/**
  12 + * @Description:CANCEL请求处理器
  13 + * @author: songww
  14 + * @date: 2020年5月3日 下午5:32:23
  15 + */
  16 +@Component
  17 +public class CancelRequestProcessor implements ISIPRequestProcessor {
  18 +
  19 + /**
  20 + * 处理CANCEL请求
  21 + *
  22 + * @param evt
  23 + * @param layer
  24 + * @param transaction
  25 + * @param config
  26 + */
  27 + @Override
  28 + public void process(RequestEvent evt, SipLayer layer, ServerTransaction transaction) {
  29 + // TODO Auto-generated method stub
  30 +
  31 + }
  32 +
  33 +}
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/InviteRequestProcessor.java 0 → 100644
  1 +++ a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/InviteRequestProcessor.java
  1 +package com.genersoft.iot.vmp.gb28181.transmit.request.impl;
  2 +
  3 +import javax.sip.RequestEvent;
  4 +import javax.sip.ServerTransaction;
  5 +
  6 +import org.springframework.stereotype.Component;
  7 +
  8 +import com.genersoft.iot.vmp.gb28181.SipLayer;
  9 +import com.genersoft.iot.vmp.gb28181.transmit.request.ISIPRequestProcessor;
  10 +
  11 +/**
  12 + * @Description:处理INVITE请求
  13 + * @author: songww
  14 + * @date: 2020年5月3日 下午4:43:52
  15 + */
  16 +@Component
  17 +public class InviteRequestProcessor implements ISIPRequestProcessor {
  18 +
  19 + /**
  20 + * 处理invite请求
  21 + *
  22 + * @param request
  23 + * 请求消息
  24 + */
  25 + @Override
  26 + public void process(RequestEvent evt, SipLayer layer, ServerTransaction transaction) {
  27 + // TODO Auto-generated method stub
  28 +// Request request = requestEvent.getRequest();
  29 +//
  30 +// try {
  31 +// // 发送100 Trying
  32 +// ServerTransaction serverTransaction = getServerTransaction(requestEvent);
  33 +// // 查询目标地址
  34 +// URI reqUri = request.getRequestURI();
  35 +// URI contactURI = currUser.get(reqUri);
  36 +//
  37 +// System.out.println("processInvite rqStr=" + reqUri + " contact=" + contactURI);
  38 +//
  39 +// // 根据Request uri来路由,后续的响应消息通过VIA来路由
  40 +// Request cliReq = messageFactory.createRequest(request.toString());
  41 +// cliReq.setRequestURI(contactURI);
  42 +//
  43 +// HeaderFactory headerFactory = SipFactory.getInstance().createHeaderFactory();
  44 +// Via callerVia = (Via) request.getHeader(Via.NAME);
  45 +// Via via = (Via) headerFactory.createViaHeader(SIPMain.ip, SIPMain.port, "UDP",
  46 +// callerVia.getBranch() + "sipphone");
  47 +//
  48 +// // FIXME 需要测试是否能够通过设置VIA头域来修改VIA头域值
  49 +// cliReq.removeHeader(Via.NAME);
  50 +// cliReq.addHeader(via);
  51 +//
  52 +// // 更新contact的地址
  53 +// ContactHeader contactHeader = headerFactory.createContactHeader();
  54 +// Address address = SipFactory.getInstance().createAddressFactory()
  55 +// .createAddress("sip:sipsoft@" + SIPMain.ip + ":" + SIPMain.port);
  56 +// contactHeader.setAddress(address);
  57 +// contactHeader.setExpires(3600);
  58 +// cliReq.setHeader(contactHeader);
  59 +//
  60 +// clientTransactionId = sipProvider.getNewClientTransaction(cliReq);
  61 +// clientTransactionId.sendRequest();
  62 +//
  63 +// System.out.println("processInvite clientTransactionId=" + clientTransactionId.toString());
  64 +//
  65 +// System.out.println("send invite to callee: " + cliReq);
  66 +// } catch (TransactionUnavailableException e1) {
  67 +// e1.printStackTrace();
  68 +// } catch (SipException e) {
  69 +// e.printStackTrace();
  70 +// } catch (ParseException e) {
  71 +// e.printStackTrace();
  72 +// } catch (Exception e) {
  73 +// e.printStackTrace();
  74 +// }
  75 + }
  76 +
  77 +}
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/MessageRequestProcessor.java 0 → 100644
  1 +++ a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/MessageRequestProcessor.java
  1 +package com.genersoft.iot.vmp.gb28181.transmit.request.impl;
  2 +
  3 +import java.io.ByteArrayInputStream;
  4 +import java.text.ParseException;
  5 +import java.util.HashMap;
  6 +import java.util.Iterator;
  7 +import java.util.Map;
  8 +
  9 +import javax.sip.InvalidArgumentException;
  10 +import javax.sip.RequestEvent;
  11 +import javax.sip.ServerTransaction;
  12 +import javax.sip.SipException;
  13 +import javax.sip.message.Request;
  14 +import javax.sip.message.Response;
  15 +
  16 +import org.dom4j.Document;
  17 +import org.dom4j.DocumentException;
  18 +import org.dom4j.Element;
  19 +import org.dom4j.io.SAXReader;
  20 +import org.springframework.beans.factory.annotation.Autowired;
  21 +import org.springframework.stereotype.Component;
  22 +
  23 +import com.genersoft.iot.vmp.common.VideoManagerConstants;
  24 +import com.genersoft.iot.vmp.gb28181.SipLayer;
  25 +import com.genersoft.iot.vmp.gb28181.bean.Device;
  26 +import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
  27 +import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
  28 +import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
  29 +import com.genersoft.iot.vmp.gb28181.transmit.request.ISIPRequestProcessor;
  30 +import com.genersoft.iot.vmp.gb28181.utils.XmlUtil;
  31 +import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
  32 +
  33 +/**
  34 + * @Description:MESSAGE请求处理器
  35 + * @author: songww
  36 + * @date: 2020年5月3日 下午5:32:41
  37 + */
  38 +@Component
  39 +public class MessageRequestProcessor implements ISIPRequestProcessor {
  40 +
  41 + private ServerTransaction transaction;
  42 +
  43 + private SipLayer layer;
  44 +
  45 + @Autowired
  46 + private SIPCommander cmder;
  47 +
  48 + @Autowired
  49 + private IVideoManagerStorager storager;
  50 +
  51 + @Autowired
  52 + private EventPublisher publisher;
  53 +
  54 + /**
  55 + * 处理MESSAGE请求
  56 + *
  57 + * @param evt
  58 + * @param layer
  59 + * @param transaction
  60 + */
  61 + @Override
  62 + public void process(RequestEvent evt, SipLayer layer, ServerTransaction transaction) {
  63 +
  64 + this.layer = layer;
  65 + this.transaction = transaction;
  66 +
  67 + Request request = evt.getRequest();
  68 +
  69 + if (new String(request.getRawContent()).contains("<CmdType>Keepalive</CmdType>")) {
  70 + processMessageKeepAlive(evt);
  71 + } else if (new String(request.getRawContent()).contains("<CmdType>Catalog</CmdType>")) {
  72 + processMessageCatalogList(evt);
  73 + } else if (new String(request.getRawContent()).contains("<CmdType>DeviceInfo</CmdType>")) {
  74 + processMessageDeviceInfo(evt);
  75 + } else if (new String(request.getRawContent()).contains("<CmdType>Alarm</CmdType>")) {
  76 + processMessageAlarm(evt);
  77 + }
  78 +
  79 + }
  80 +
  81 + /***
  82 + * 收到catalog设备目录列表请求 处理
  83 + * @param evt
  84 + */
  85 + private void processMessageCatalogList(RequestEvent evt) {
  86 + try {
  87 + Request request = evt.getRequest();
  88 + SAXReader reader = new SAXReader();
  89 + reader.setEncoding("GB2312");
  90 + Document xml = reader.read(new ByteArrayInputStream(request.getRawContent()));
  91 + Element rootElement = xml.getRootElement();
  92 + Element deviceIdElement = rootElement.element("DeviceID");
  93 + String deviceId = deviceIdElement.getText().toString();
  94 + Element deviceListElement = rootElement.element("DeviceList");
  95 + if (deviceListElement == null) {
  96 + return;
  97 + }
  98 + Iterator<Element> deviceListIterator = deviceListElement.elementIterator();
  99 + if (deviceListIterator != null) {
  100 + Device device = storager.queryVideoDevice(deviceId);
  101 + if (device == null) {
  102 + return;
  103 + }
  104 + Map<String, DeviceChannel> channelMap = device.getChannelMap();
  105 + if (channelMap == null) {
  106 + channelMap = new HashMap<String, DeviceChannel>(5);
  107 + device.setChannelMap(channelMap);
  108 + }
  109 + // 遍历DeviceList
  110 + while (deviceListIterator.hasNext()) {
  111 + Element itemDevice = deviceListIterator.next();
  112 + Element channelDeviceElement = itemDevice.element("DeviceID");
  113 + if (channelDeviceElement == null) {
  114 + continue;
  115 + }
  116 + String channelDeviceId = channelDeviceElement.getText().toString();
  117 + Element channdelNameElement = itemDevice.element("Name");
  118 + String channelName = channdelNameElement != null ? channdelNameElement.getText().toString() : "";
  119 + Element statusElement = itemDevice.element("Status");
  120 + String status = statusElement != null ? statusElement.getText().toString() : "ON";
  121 + DeviceChannel deviceChannel = channelMap.containsKey(channelDeviceId) ? channelMap.get(channelDeviceId) : new DeviceChannel();
  122 + deviceChannel.setName(channelName);
  123 + deviceChannel.setChannelId(channelDeviceId);
  124 + if(status.equals("ON")) {
  125 + deviceChannel.setStatus(1);
  126 + }
  127 + if(status.equals("OFF")) {
  128 + deviceChannel.setStatus(0);
  129 + }
  130 +
  131 + deviceChannel.setManufacture(XmlUtil.getText(itemDevice,"Manufacturer"));
  132 + deviceChannel.setModel(XmlUtil.getText(itemDevice,"Model"));
  133 + deviceChannel.setOwner(XmlUtil.getText(itemDevice,"Owner"));
  134 + deviceChannel.setCivilCode(XmlUtil.getText(itemDevice,"CivilCode"));
  135 + deviceChannel.setBlock(XmlUtil.getText(itemDevice,"Block"));
  136 + deviceChannel.setAddress(XmlUtil.getText(itemDevice,"Address"));
  137 + deviceChannel.setParental(itemDevice.element("Parental") == null? 0:Integer.parseInt(XmlUtil.getText(itemDevice,"Parental")));
  138 + deviceChannel.setParentId(XmlUtil.getText(itemDevice,"ParentId"));
  139 + deviceChannel.setSafetyWay(itemDevice.element("SafetyWay") == null? 0:Integer.parseInt(XmlUtil.getText(itemDevice,"SafetyWay")));
  140 + deviceChannel.setRegisterWay(itemDevice.element("RegisterWay") == null? 1:Integer.parseInt(XmlUtil.getText(itemDevice,"RegisterWay")));
  141 + deviceChannel.setCertNum(XmlUtil.getText(itemDevice,"CertNum"));
  142 + deviceChannel.setCertifiable(itemDevice.element("Certifiable") == null? 0:Integer.parseInt(XmlUtil.getText(itemDevice,"Certifiable")));
  143 + deviceChannel.setErrCode(itemDevice.element("ErrCode") == null? 0:Integer.parseInt(XmlUtil.getText(itemDevice,"ErrCode")));
  144 + deviceChannel.setEndTime(XmlUtil.getText(itemDevice,"EndTime"));
  145 + deviceChannel.setSecrecy(XmlUtil.getText(itemDevice,"Secrecy"));
  146 + deviceChannel.setIpAddress(XmlUtil.getText(itemDevice,"IPAddress"));
  147 + deviceChannel.setPort(itemDevice.element("Port") == null? 0:Integer.parseInt(XmlUtil.getText(itemDevice,"Port")));
  148 + deviceChannel.setPassword(XmlUtil.getText(itemDevice,"Password"));
  149 + deviceChannel.setLongitude(itemDevice.element("Longitude") == null? 0.00:Double.parseDouble(XmlUtil.getText(itemDevice,"Longitude")));
  150 + deviceChannel.setLatitude(itemDevice.element("Latitude") == null? 0.00:Double.parseDouble(XmlUtil.getText(itemDevice,"Latitude")));
  151 + channelMap.put(channelDeviceId, deviceChannel);
  152 + }
  153 + // 更新
  154 + storager.update(device);
  155 + }
  156 + } catch (DocumentException e) {
  157 + e.printStackTrace();
  158 + }
  159 + }
  160 +
  161 + /***
  162 + * 收到deviceInfo设备信息请求 处理
  163 + * @param evt
  164 + */
  165 + private void processMessageDeviceInfo(RequestEvent evt) {
  166 + try {
  167 + Request request = evt.getRequest();
  168 + SAXReader reader = new SAXReader();
  169 + // reader.setEncoding("GB2312");
  170 + Document xml = reader.read(new ByteArrayInputStream(request.getRawContent()));
  171 + Element rootElement = xml.getRootElement();
  172 + Element deviceIdElement = rootElement.element("DeviceID");
  173 + String deviceId = deviceIdElement.getText().toString();
  174 +
  175 + Device device = storager.queryVideoDevice(deviceId);
  176 + if (device == null) {
  177 + return;
  178 + }
  179 + device.setName(XmlUtil.getText(rootElement,"DeviceName"));
  180 + device.setManufacturer(XmlUtil.getText(rootElement,"Manufacturer"));
  181 + device.setModel(XmlUtil.getText(rootElement,"Model"));
  182 + device.setFirmware(XmlUtil.getText(rootElement,"Firmware"));
  183 + storager.update(device);
  184 + cmder.catalogQuery(device);
  185 + } catch (DocumentException e) {
  186 + e.printStackTrace();
  187 + }
  188 + }
  189 +
  190 + /***
  191 + * 收到alarm设备报警信息 处理
  192 + * @param evt
  193 + */
  194 + private void processMessageAlarm(RequestEvent evt) {
  195 + try {
  196 + Request request = evt.getRequest();
  197 + SAXReader reader = new SAXReader();
  198 + // reader.setEncoding("GB2312");
  199 + Document xml = reader.read(new ByteArrayInputStream(request.getRawContent()));
  200 + Element rootElement = xml.getRootElement();
  201 + Element deviceIdElement = rootElement.element("DeviceID");
  202 + String deviceId = deviceIdElement.getText().toString();
  203 +
  204 + Device device = storager.queryVideoDevice(deviceId);
  205 + if (device == null) {
  206 + return;
  207 + }
  208 + device.setName(XmlUtil.getText(rootElement,"DeviceName"));
  209 + device.setManufacturer(XmlUtil.getText(rootElement,"Manufacturer"));
  210 + device.setModel(XmlUtil.getText(rootElement,"Model"));
  211 + device.setFirmware(XmlUtil.getText(rootElement,"Firmware"));
  212 + storager.update(device);
  213 + cmder.catalogQuery(device);
  214 + } catch (DocumentException e) {
  215 + e.printStackTrace();
  216 + }
  217 + }
  218 +
  219 + /***
  220 + * 收到keepalive请求 处理
  221 + * @param evt
  222 + */
  223 + private void processMessageKeepAlive(RequestEvent evt){
  224 + try {
  225 + Request request = evt.getRequest();
  226 + Response response = layer.getMessageFactory().createResponse(Response.OK,request);
  227 + SAXReader reader = new SAXReader();
  228 + Document xml = reader.read(new ByteArrayInputStream(request.getRawContent()));
  229 + // reader.setEncoding("GB2312");
  230 + Element rootElement = xml.getRootElement();
  231 + Element deviceIdElement = rootElement.element("DeviceID");
  232 + transaction.sendResponse(response);
  233 + publisher.onlineEventPublish(deviceIdElement.getText(), VideoManagerConstants.EVENT_ONLINE_KEEPLIVE);
  234 + } catch (ParseException | SipException | InvalidArgumentException | DocumentException e) {
  235 + e.printStackTrace();
  236 + }
  237 + }
  238 +
  239 +}
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/OtherRequestProcessor.java 0 → 100644
  1 +++ a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/OtherRequestProcessor.java
  1 +package com.genersoft.iot.vmp.gb28181.transmit.request.impl;
  2 +
  3 +import javax.sip.RequestEvent;
  4 +import javax.sip.ServerTransaction;
  5 +
  6 +import org.springframework.stereotype.Component;
  7 +
  8 +import com.genersoft.iot.vmp.gb28181.SipLayer;
  9 +import com.genersoft.iot.vmp.gb28181.transmit.request.ISIPRequestProcessor;
  10 +
  11 +/**
  12 + * @Description:暂不支持的消息请求处理器
  13 + * @author: songww
  14 + * @date: 2020年5月3日 下午5:32:59
  15 + */
  16 +@Component
  17 +public class OtherRequestProcessor implements ISIPRequestProcessor {
  18 +
  19 + /**
  20 + * <p>Title: process</p>
  21 + * <p>Description: </p>
  22 + * @param evt
  23 + * @param layer
  24 + * @param transaction
  25 + * @param config
  26 + */
  27 + @Override
  28 + public void process(RequestEvent evt, SipLayer layer, ServerTransaction transaction) {
  29 + System.out.println("no support the method! Method:" + evt.getRequest().getMethod());
  30 + }
  31 +
  32 +}
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/RegisterRequestProcessor.java 0 → 100644
  1 +++ a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/RegisterRequestProcessor.java
  1 +package com.genersoft.iot.vmp.gb28181.transmit.request.impl;
  2 +
  3 +import java.security.NoSuchAlgorithmException;
  4 +import java.text.ParseException;
  5 +import java.util.Calendar;
  6 +import java.util.Locale;
  7 +
  8 +import javax.sip.InvalidArgumentException;
  9 +import javax.sip.RequestEvent;
  10 +import javax.sip.ServerTransaction;
  11 +import javax.sip.SipException;
  12 +import javax.sip.header.AuthorizationHeader;
  13 +import javax.sip.header.ContactHeader;
  14 +import javax.sip.header.ExpiresHeader;
  15 +import javax.sip.header.FromHeader;
  16 +import javax.sip.header.ViaHeader;
  17 +import javax.sip.message.Request;
  18 +import javax.sip.message.Response;
  19 +
  20 +import org.springframework.beans.factory.annotation.Autowired;
  21 +import org.springframework.stereotype.Component;
  22 +import org.springframework.util.StringUtils;
  23 +
  24 +import com.genersoft.iot.vmp.common.VideoManagerConstants;
  25 +import com.genersoft.iot.vmp.conf.SipConfig;
  26 +import com.genersoft.iot.vmp.gb28181.SipLayer;
  27 +import com.genersoft.iot.vmp.gb28181.auth.DigestServerAuthenticationHelper;
  28 +import com.genersoft.iot.vmp.gb28181.bean.Device;
  29 +import com.genersoft.iot.vmp.gb28181.bean.Host;
  30 +import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
  31 +import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
  32 +import com.genersoft.iot.vmp.gb28181.transmit.request.ISIPRequestProcessor;
  33 +import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
  34 +
  35 +import gov.nist.javax.sip.address.AddressImpl;
  36 +import gov.nist.javax.sip.address.SipUri;
  37 +import gov.nist.javax.sip.header.Expires;
  38 +
  39 +/**
  40 + * @Description:收到注册请求 处理
  41 + * @author: songww
  42 + * @date: 2020年5月3日 下午4:47:25
  43 + */
  44 +@Component
  45 +public class RegisterRequestProcessor implements ISIPRequestProcessor {
  46 +
  47 + @Autowired
  48 + private SipConfig config;
  49 +
  50 + @Autowired
  51 + private SIPCommander cmder;
  52 +
  53 + @Autowired
  54 + private IVideoManagerStorager storager;
  55 +
  56 + @Autowired
  57 + private EventPublisher publisher;
  58 +
  59 + /***
  60 + * 收到注册请求 处理
  61 + *
  62 + * @param request
  63 + * 请求消息
  64 + */
  65 + @Override
  66 + public void process(RequestEvent evt, SipLayer layer, ServerTransaction transaction) {
  67 + try {
  68 + System.out.println("收到注册请求,开始处理");
  69 + Request request = evt.getRequest();
  70 +
  71 + Response response = null;
  72 + boolean passwordCorrect = false;
  73 + // 注册标志 0:未携带授权头或者密码错误 1:注册成功 2:注销成功
  74 + int registerFlag = 0;
  75 + Device device = null;
  76 + AuthorizationHeader authorhead = (AuthorizationHeader) request.getHeader(AuthorizationHeader.NAME);
  77 + // 校验密码是否正确
  78 + if (authorhead != null) {
  79 + passwordCorrect = new DigestServerAuthenticationHelper().doAuthenticatePlainTextPassword(request,
  80 + config.getSipPassword());
  81 + }
  82 +
  83 + // 未携带授权头或者密码错误 回复401
  84 + if (authorhead == null || !passwordCorrect) {
  85 +
  86 + if (authorhead == null) {
  87 + System.out.println("未携带授权头 回复401");
  88 + } else if (!passwordCorrect) {
  89 + System.out.println("密码错误 回复401");
  90 + }
  91 + response = layer.getMessageFactory().createResponse(Response.UNAUTHORIZED, request);
  92 + new DigestServerAuthenticationHelper().generateChallenge(layer.getHeaderFactory(), response, config.getSipDomain());
  93 + }
  94 + // 携带授权头并且密码正确
  95 + else if (passwordCorrect) {
  96 + response = layer.getMessageFactory().createResponse(Response.OK, request);
  97 + // 添加date头
  98 + response.addHeader(layer.getHeaderFactory().createDateHeader(Calendar.getInstance(Locale.ENGLISH)));
  99 + ExpiresHeader expiresHeader = (ExpiresHeader) request.getHeader(Expires.NAME);
  100 + // 添加Contact头
  101 + response.addHeader(request.getHeader(ContactHeader.NAME));
  102 + // 添加Expires头
  103 + response.addHeader(request.getExpires());
  104 +
  105 + // 1.获取到通信地址等信息,保存到Redis
  106 + FromHeader fromHeader = (FromHeader) request.getHeader(FromHeader.NAME);
  107 + ViaHeader viaHeader = (ViaHeader) request.getHeader(ViaHeader.NAME);
  108 + String received = viaHeader.getReceived();
  109 + int rPort = viaHeader.getRPort();
  110 + // 本地模拟设备 received 为空 rPort 为 -1
  111 + // 解析本地地址替代
  112 + if (StringUtils.isEmpty(received) || rPort == -1) {
  113 + received = viaHeader.getHost();
  114 + rPort = viaHeader.getPort();
  115 + }
  116 + //
  117 + Host host = new Host();
  118 + host.setIp(received);
  119 + host.setPort(rPort);
  120 + host.setAddress(received.concat(":").concat(String.valueOf(rPort)));
  121 + AddressImpl address = (AddressImpl) fromHeader.getAddress();
  122 + SipUri uri = (SipUri) address.getURI();
  123 + String deviceId = uri.getUser();
  124 + device = new Device();
  125 + device.setDeviceId(deviceId);
  126 + device.setHost(host);
  127 + // 注销成功
  128 + if (expiresHeader != null && expiresHeader.getExpires() == 0) {
  129 + registerFlag = 2;
  130 + }
  131 + // 注册成功
  132 + else {
  133 + registerFlag = 1;
  134 + // 判断TCP还是UDP
  135 + boolean isTcp = false;
  136 + ViaHeader reqViaHeader = (ViaHeader) request.getHeader(ViaHeader.NAME);
  137 + String transport = reqViaHeader.getTransport();
  138 + if (transport.equals("TCP")) {
  139 + isTcp = true;
  140 + }
  141 + device.setTransport(isTcp ? "TCP" : "UDP");
  142 + }
  143 + }
  144 + transaction.sendResponse(response);
  145 + // 注册成功
  146 + // 保存到redis
  147 + // 下发catelog查询目录
  148 + if (registerFlag == 1 && device != null) {
  149 + System.out.println("注册成功! deviceId:" + device.getDeviceId());
  150 + storager.update(device);
  151 + publisher.onlineEventPublish(device.getDeviceId(), VideoManagerConstants.EVENT_ONLINE_REGISTER);
  152 + cmder.deviceInfoQuery(device);
  153 + } else if (registerFlag == 2) {
  154 + System.out.println("注销成功! deviceId:" + device.getDeviceId());
  155 + publisher.outlineEventPublish(device.getDeviceId(), VideoManagerConstants.EVENT_OUTLINE_UNREGISTER);
  156 + }
  157 + } catch (SipException | InvalidArgumentException | NoSuchAlgorithmException | ParseException e) {
  158 + e.printStackTrace();
  159 + }
  160 +
  161 + }
  162 +
  163 +}
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/SubscribeRequestProcessor.java 0 → 100644
  1 +++ a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/SubscribeRequestProcessor.java
  1 +package com.genersoft.iot.vmp.gb28181.transmit.request.impl;
  2 +
  3 +import java.text.ParseException;
  4 +
  5 +import javax.sip.InvalidArgumentException;
  6 +import javax.sip.RequestEvent;
  7 +import javax.sip.ServerTransaction;
  8 +import javax.sip.SipException;
  9 +import javax.sip.header.ExpiresHeader;
  10 +import javax.sip.message.Request;
  11 +import javax.sip.message.Response;
  12 +
  13 +import org.springframework.stereotype.Component;
  14 +
  15 +import com.genersoft.iot.vmp.gb28181.SipLayer;
  16 +import com.genersoft.iot.vmp.gb28181.transmit.request.ISIPRequestProcessor;
  17 +
  18 +/**
  19 + * @Description:SUBSCRIBE请求处理器
  20 + * @author: songww
  21 + * @date: 2020年5月3日 下午5:31:20
  22 + */
  23 +@Component
  24 +public class SubscribeRequestProcessor implements ISIPRequestProcessor {
  25 +
  26 + /**
  27 + * 处理SUBSCRIBE请求
  28 + *
  29 + * @param evt
  30 + * @param layer
  31 + * @param transaction
  32 + * @param config
  33 + */
  34 + @Override
  35 + public void process(RequestEvent evt, SipLayer layer, ServerTransaction transaction) {
  36 + Request request = evt.getRequest();
  37 +
  38 + try {
  39 + Response response = null;
  40 + response = layer.getMessageFactory().createResponse(200, request);
  41 + if (response != null) {
  42 + ExpiresHeader expireHeader = layer.getHeaderFactory().createExpiresHeader(30);
  43 + response.setExpires(expireHeader);
  44 + }
  45 + System.out.println("response : " + response.toString());
  46 +
  47 + if (transaction != null) {
  48 + transaction.sendResponse(response);
  49 + transaction.terminate();
  50 + } else {
  51 + System.out.println("processRequest serverTransactionId is null.");
  52 + }
  53 +
  54 + } catch (ParseException e) {
  55 + e.printStackTrace();
  56 + } catch (SipException e) {
  57 + e.printStackTrace();
  58 + } catch (InvalidArgumentException e) {
  59 + e.printStackTrace();
  60 + }
  61 +
  62 + }
  63 +
  64 +}
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/response/ISIPResponseProcessor.java 0 → 100644
  1 +++ a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/response/ISIPResponseProcessor.java
  1 +package com.genersoft.iot.vmp.gb28181.transmit.response;
  2 +
  3 +import javax.sip.ResponseEvent;
  4 +
  5 +import com.genersoft.iot.vmp.conf.SipConfig;
  6 +import com.genersoft.iot.vmp.gb28181.SipLayer;
  7 +
  8 +/**
  9 + * @Description:处理接收IPCamera发来的SIP协议响应消息
  10 + * @author: songww
  11 + * @date: 2020年5月3日 下午4:42:22
  12 + */
  13 +public interface ISIPResponseProcessor {
  14 +
  15 + public void process(ResponseEvent evt, SipLayer layer, SipConfig config);
  16 +
  17 +}
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/response/impl/ByeResponseProcessor.java 0 → 100644
  1 +++ a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/response/impl/ByeResponseProcessor.java
  1 +package com.genersoft.iot.vmp.gb28181.transmit.response.impl;
  2 +
  3 +import javax.sip.ResponseEvent;
  4 +
  5 +import org.springframework.stereotype.Component;
  6 +
  7 +import com.genersoft.iot.vmp.conf.SipConfig;
  8 +import com.genersoft.iot.vmp.gb28181.SipLayer;
  9 +import com.genersoft.iot.vmp.gb28181.transmit.response.ISIPResponseProcessor;
  10 +
  11 +/**
  12 + * @Description: BYE请求响应器
  13 + * @author: songww
  14 + * @date: 2020年5月3日 下午5:32:05
  15 + */
  16 +@Component
  17 +public class ByeResponseProcessor implements ISIPResponseProcessor {
  18 +
  19 + /**
  20 + * 处理BYE响应
  21 + *
  22 + * @param evt
  23 + * @param layer
  24 + * @param transaction
  25 + * @param config
  26 + */
  27 + @Override
  28 + public void process(ResponseEvent evt, SipLayer layer, SipConfig config) {
  29 + // TODO Auto-generated method stub
  30 +
  31 + }
  32 +
  33 +}
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/response/impl/CancelResponseProcessor.java 0 → 100644
  1 +++ a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/response/impl/CancelResponseProcessor.java
  1 +package com.genersoft.iot.vmp.gb28181.transmit.response.impl;
  2 +
  3 +import javax.sip.ResponseEvent;
  4 +
  5 +import org.springframework.stereotype.Component;
  6 +
  7 +import com.genersoft.iot.vmp.conf.SipConfig;
  8 +import com.genersoft.iot.vmp.gb28181.SipLayer;
  9 +import com.genersoft.iot.vmp.gb28181.transmit.response.ISIPResponseProcessor;
  10 +
  11 +/**
  12 + * @Description:CANCEL响应处理器
  13 + * @author: songww
  14 + * @date: 2020年5月3日 下午5:32:23
  15 + */
  16 +@Component
  17 +public class CancelResponseProcessor implements ISIPResponseProcessor {
  18 +
  19 + /**
  20 + * 处理CANCEL响应
  21 + *
  22 + * @param evt
  23 + * @param layer
  24 + * @param transaction
  25 + * @param config
  26 + */
  27 + @Override
  28 + public void process(ResponseEvent evt, SipLayer layer, SipConfig config) {
  29 + // TODO Auto-generated method stub
  30 +
  31 + }
  32 +
  33 +}
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/response/impl/InviteResponseProcessor.java 0 → 100644
  1 +++ a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/response/impl/InviteResponseProcessor.java
  1 +package com.genersoft.iot.vmp.gb28181.transmit.response.impl;
  2 +
  3 +import javax.sip.Dialog;
  4 +import javax.sip.InvalidArgumentException;
  5 +import javax.sip.ResponseEvent;
  6 +import javax.sip.SipException;
  7 +import javax.sip.message.Request;
  8 +
  9 +import org.springframework.stereotype.Component;
  10 +
  11 +import com.genersoft.iot.vmp.conf.SipConfig;
  12 +import com.genersoft.iot.vmp.gb28181.SipLayer;
  13 +import com.genersoft.iot.vmp.gb28181.transmit.response.ISIPResponseProcessor;
  14 +
  15 +/**
  16 + * @Description:处理INVITE响应
  17 + * @author: songww
  18 + * @date: 2020年5月3日 下午4:43:52
  19 + */
  20 +@Component
  21 +public class InviteResponseProcessor implements ISIPResponseProcessor {
  22 +
  23 + /**
  24 + * 处理invite响应
  25 + *
  26 + * @param request
  27 + * 响应消息
  28 + */
  29 + @Override
  30 + public void process(ResponseEvent evt, SipLayer layer, SipConfig config) {
  31 + try {
  32 + Dialog dialog = evt.getDialog();
  33 + Request reqAck =dialog.createAck(1L);
  34 + dialog.sendAck(reqAck);
  35 + } catch (InvalidArgumentException | SipException e) {
  36 + e.printStackTrace();
  37 + }
  38 + }
  39 +
  40 +}
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/response/impl/OtherResponseProcessor.java 0 → 100644
  1 +++ a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/response/impl/OtherResponseProcessor.java
  1 +package com.genersoft.iot.vmp.gb28181.transmit.response.impl;
  2 +
  3 +import javax.sip.ResponseEvent;
  4 +
  5 +import org.springframework.stereotype.Component;
  6 +
  7 +import com.genersoft.iot.vmp.conf.SipConfig;
  8 +import com.genersoft.iot.vmp.gb28181.SipLayer;
  9 +import com.genersoft.iot.vmp.gb28181.transmit.response.ISIPResponseProcessor;
  10 +
  11 +/**
  12 + * @Description:暂不支持的消息响应处理器
  13 + * @author: songww
  14 + * @date: 2020年5月3日 下午5:32:59
  15 + */
  16 +@Component
  17 +public class OtherResponseProcessor implements ISIPResponseProcessor {
  18 +
  19 + /**
  20 + * <p>Title: process</p>
  21 + * <p>Description: </p>
  22 + * @param evt
  23 + * @param layer
  24 + * @param config
  25 + */
  26 + @Override
  27 + public void process(ResponseEvent evt, SipLayer layer, SipConfig config) {
  28 + // TODO Auto-generated method stub
  29 +
  30 + }
  31 +
  32 +}
src/main/java/com/genersoft/iot/vmp/gb28181/utils/XmlUtil.java 0 → 100644
  1 +++ a/src/main/java/com/genersoft/iot/vmp/gb28181/utils/XmlUtil.java
  1 +package com.genersoft.iot.vmp.gb28181.utils;
  2 +
  3 +import java.io.StringReader;
  4 +import java.util.ArrayList;
  5 +import java.util.HashMap;
  6 +import java.util.Iterator;
  7 +import java.util.List;
  8 +import java.util.Map;
  9 +
  10 +import org.dom4j.Attribute;
  11 +import org.dom4j.Document;
  12 +import org.dom4j.DocumentException;
  13 +import org.dom4j.Element;
  14 +import org.dom4j.io.SAXReader;
  15 +import org.slf4j.Logger;
  16 +import org.slf4j.LoggerFactory;
  17 +
  18 +/**
  19 + * 基于dom4j的工具包
  20 + *
  21 + *
  22 + */
  23 +public class XmlUtil
  24 +{
  25 + /**
  26 + * 日志服务
  27 + */
  28 + private static Logger LOG = LoggerFactory.getLogger(XmlUtil.class);
  29 +
  30 + /**
  31 + * 解析XML为Document对象
  32 + *
  33 + * @param xml
  34 + * 被解析的XMl
  35 + * @return Document
  36 + */
  37 + public static Element parseXml(String xml)
  38 + {
  39 + Document document = null;
  40 + //
  41 + StringReader sr = new StringReader(xml);
  42 + SAXReader saxReader = new SAXReader();
  43 + try
  44 + {
  45 + document = saxReader.read(sr);
  46 + }
  47 + catch (DocumentException e)
  48 + {
  49 + LOG.error("解析失败", e);
  50 + }
  51 + return null == document ? null : document.getRootElement();
  52 + }
  53 +
  54 + /**
  55 + * 获取element对象的text的值
  56 + *
  57 + * @param em
  58 + * 节点的对象
  59 + * @param tag
  60 + * 节点的tag
  61 + * @return 节点
  62 + */
  63 + public static String getText(Element em, String tag)
  64 + {
  65 + if (null == em)
  66 + {
  67 + return null;
  68 + }
  69 + Element e = em.element(tag);
  70 + //
  71 + return null == e ? null : e.getText();
  72 + }
  73 +
  74 + /**
  75 + * 递归解析xml节点,适用于 多节点数据
  76 + *
  77 + * @param node
  78 + * node
  79 + * @param nodeName
  80 + * nodeName
  81 + * @return List<Map<String, Object>>
  82 + */
  83 + public static List<Map<String, Object>> listNodes(Element node, String nodeName)
  84 + {
  85 + if (null == node)
  86 + {
  87 + return null;
  88 + }
  89 + // 初始化返回
  90 + List<Map<String, Object>> listMap = new ArrayList<Map<String, Object>>();
  91 + // 首先获取当前节点的所有属性节点
  92 + List<Attribute> list = node.attributes();
  93 +
  94 + Map<String, Object> map = null;
  95 + // 遍历属性节点
  96 + for (Attribute attribute : list)
  97 + {
  98 + if (nodeName.equals(node.getName()))
  99 + {
  100 + if (null == map)
  101 + {
  102 + map = new HashMap<String, Object>();
  103 + listMap.add(map);
  104 + }
  105 + // 取到的节点属性放到map中
  106 + map.put(attribute.getName(), attribute.getValue());
  107 + }
  108 +
  109 + }
  110 + // 遍历当前节点下的所有节点 ,nodeName 要解析的节点名称
  111 + // 使用递归
  112 + Iterator<Element> iterator = node.elementIterator();
  113 + while (iterator.hasNext())
  114 + {
  115 + Element e = iterator.next();
  116 + listMap.addAll(listNodes(e, nodeName));
  117 + }
  118 + return listMap;
  119 + }
  120 +
  121 +}
src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorager.java 0 → 100644
  1 +++ a/src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorager.java
  1 +package com.genersoft.iot.vmp.storager;
  2 +
  3 +import java.util.List;
  4 +
  5 +import com.genersoft.iot.vmp.gb28181.bean.Device;
  6 +
  7 +/**
  8 + * @Description:视频设备数据存储接口
  9 + * @author: songww
  10 + * @date: 2020年5月6日 下午2:14:31
  11 + */
  12 +public interface IVideoManagerStorager {
  13 +
  14 + /**
  15 + * 根据设备ID判断设备是否存在
  16 + *
  17 + * @param deviceId 设备ID
  18 + * @return true:存在 false:不存在
  19 + */
  20 + public boolean exists(String deviceId);
  21 +
  22 + /**
  23 + * 视频设备创建
  24 + *
  25 + * @param device 设备对象
  26 + * @return true:创建成功 false:创建失败
  27 + */
  28 + public boolean create(Device device);
  29 +
  30 + /**
  31 + * 视频设备更新
  32 + *
  33 + * @param device 设备对象
  34 + * @return true:创建成功 false:创建失败
  35 + */
  36 + public boolean update(Device device);
  37 +
  38 + /**
  39 + * 获取设备
  40 + *
  41 + * @param deviceId 设备ID
  42 + * @return DShadow 设备对象
  43 + */
  44 + public Device queryVideoDevice(String deviceId);
  45 +
  46 + /**
  47 + * 获取多个设备
  48 + *
  49 + * @param deviceIds 设备ID数组
  50 + * @return List<Device> 设备对象数组
  51 + */
  52 + public List<Device> queryVideoDeviceList(String[] deviceIds);
  53 +
  54 + /**
  55 + * 删除设备
  56 + *
  57 + * @param deviceId 设备ID
  58 + * @return true:删除成功 false:删除失败
  59 + */
  60 + public boolean delete(String deviceId);
  61 +
  62 + /**
  63 + * 更新设备在线
  64 + *
  65 + * @param deviceId 设备ID
  66 + * @return true:更新成功 false:更新失败
  67 + */
  68 + public boolean online(String deviceId);
  69 +
  70 + /**
  71 + * 更新设备离线
  72 + *
  73 + * @param deviceId 设备ID
  74 + * @return true:更新成功 false:更新失败
  75 + */
  76 + public boolean outline(String deviceId);
  77 +}
src/main/java/com/genersoft/iot/vmp/storager/VideoManagerStoragerFactory.java 0 → 100644
  1 +++ a/src/main/java/com/genersoft/iot/vmp/storager/VideoManagerStoragerFactory.java
  1 +package com.genersoft.iot.vmp.storager;
  2 +
  3 +import org.springframework.beans.factory.annotation.Autowired;
  4 +import org.springframework.context.annotation.Bean;
  5 +import org.springframework.stereotype.Component;
  6 +
  7 +import com.genersoft.iot.vmp.conf.VManagerConfig;
  8 +
  9 +/**
  10 + * @Description:视频设备数据存储工厂,根据存储策略,返回对应的存储器
  11 + * @author: songww
  12 + * @date: 2020年5月6日 下午2:15:16
  13 + */
  14 +@Component
  15 +public class VideoManagerStoragerFactory {
  16 +
  17 + @Autowired
  18 + private VManagerConfig vmConfig;
  19 +
  20 + @Autowired
  21 + private IVideoManagerStorager jdbcStorager;
  22 +
  23 + @Autowired
  24 + private IVideoManagerStorager redisStorager;
  25 +
  26 + @Bean("storager")
  27 + public IVideoManagerStorager getStorager() {
  28 + if ("redis".equals(vmConfig.getDatabase().toLowerCase())) {
  29 + return redisStorager;
  30 + } else if ("jdbc".equals(vmConfig.getDatabase().toLowerCase())) {
  31 + return jdbcStorager;
  32 + }
  33 + return redisStorager;
  34 + }
  35 +
  36 +}
src/main/java/com/genersoft/iot/vmp/storager/jdbc/VideoManagerJdbcStoragerImpl.java 0 → 100644
  1 +++ a/src/main/java/com/genersoft/iot/vmp/storager/jdbc/VideoManagerJdbcStoragerImpl.java
  1 +package com.genersoft.iot.vmp.storager.jdbc;
  2 +
  3 +import java.util.List;
  4 +
  5 +import org.springframework.stereotype.Component;
  6 +import org.springframework.stereotype.Service;
  7 +
  8 +import com.genersoft.iot.vmp.common.VideoManagerConstants;
  9 +import com.genersoft.iot.vmp.gb28181.bean.Device;
  10 +import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
  11 +
  12 +/**
  13 + * @Description:视频设备数据存储-jdbc实现
  14 + * @author: songww
  15 + * @date: 2020年5月6日 下午2:28:12
  16 + */
  17 +@Component("jdbcStorager")
  18 +public class VideoManagerJdbcStoragerImpl implements IVideoManagerStorager {
  19 +
  20 + /**
  21 + * 根据设备ID判断设备是否存在
  22 + *
  23 + * @param deviceId 设备ID
  24 + * @return true:存在 false:不存在
  25 + */
  26 + @Override
  27 + public boolean exists(String deviceId) {
  28 + // TODO Auto-generated method stub
  29 + return false;
  30 + }
  31 +
  32 + /**
  33 + * 视频设备创建
  34 + *
  35 + * @param device 设备对象
  36 + * @return true:创建成功 false:创建失败
  37 + */
  38 + @Override
  39 + public boolean create(Device device) {
  40 + // TODO Auto-generated method stub
  41 + return false;
  42 + }
  43 +
  44 + /**
  45 + * 视频设备更新
  46 + *
  47 + * @param device 设备对象
  48 + * @return true:更新成功 false:更新失败
  49 + */
  50 + @Override
  51 + public boolean update(Device device) {
  52 + // TODO Auto-generated method stub
  53 + return false;
  54 + }
  55 +
  56 + /**
  57 + * 获取设备
  58 + *
  59 + * @param deviceId 设备ID
  60 + * @return Device 设备对象
  61 + */
  62 + @Override
  63 + public Device queryVideoDevice(String deviceId) {
  64 + // TODO Auto-generated method stub
  65 + return null;
  66 + }
  67 +
  68 + /**
  69 + * 获取多个设备
  70 + *
  71 + * @param deviceIds 设备ID数组
  72 + * @return List<Device> 设备对象数组
  73 + */
  74 + @Override
  75 + public List<Device> queryVideoDeviceList(String[] deviceIds) {
  76 + // TODO Auto-generated method stub
  77 + return null;
  78 + }
  79 +
  80 + /**
  81 + * 删除设备
  82 + *
  83 + * @param deviceId 设备ID
  84 + * @return true:删除成功 false:删除失败
  85 + */
  86 + @Override
  87 + public boolean delete(String deviceId) {
  88 + // TODO Auto-generated method stub
  89 + return false;
  90 + }
  91 +
  92 + /**
  93 + * 更新设备在线
  94 + *
  95 + * @param deviceId 设备ID
  96 + * @return true:更新成功 false:更新失败
  97 + */
  98 + @Override
  99 + public boolean online(String deviceId) {
  100 + // TODO Auto-generated method stub
  101 + return false;
  102 + }
  103 +
  104 + /**
  105 + * 更新设备离线
  106 + *
  107 + * @param deviceId 设备ID
  108 + * @return true:更新成功 false:更新失败
  109 + */
  110 + @Override
  111 + public boolean outline(String deviceId) {
  112 + // TODO Auto-generated method stub
  113 + return false;
  114 + }
  115 +
  116 +}
src/main/java/com/genersoft/iot/vmp/storager/redis/VideoManagerRedisStoragerImpl.java 0 → 100644
  1 +++ a/src/main/java/com/genersoft/iot/vmp/storager/redis/VideoManagerRedisStoragerImpl.java
  1 +package com.genersoft.iot.vmp.storager.redis;
  2 +
  3 +import java.util.ArrayList;
  4 +import java.util.List;
  5 +
  6 +import org.springframework.beans.factory.annotation.Autowired;
  7 +import org.springframework.stereotype.Component;
  8 +
  9 +import com.genersoft.iot.vmp.common.VideoManagerConstants;
  10 +import com.genersoft.iot.vmp.gb28181.bean.Device;
  11 +import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
  12 +import com.genersoft.iot.vmp.utils.redis.RedisUtil;
  13 +
  14 +/**
  15 + * @Description:视频设备数据存储-redis实现
  16 + * @author: songww
  17 + * @date: 2020年5月6日 下午2:31:42
  18 + */
  19 +@Component("redisStorager")
  20 +public class VideoManagerRedisStoragerImpl implements IVideoManagerStorager {
  21 +
  22 + @Autowired
  23 + private RedisUtil redis;
  24 +
  25 + /**
  26 + * 根据设备ID判断设备是否存在
  27 + *
  28 + * @param deviceId 设备ID
  29 + * @return true:存在 false:不存在
  30 + */
  31 + @Override
  32 + public boolean exists(String deviceId) {
  33 + return redis.hasKey(VideoManagerConstants.CACHEKEY_PREFIX+deviceId);
  34 + }
  35 +
  36 + /**
  37 + * 视频设备创建
  38 + *
  39 + * @param device 设备对象
  40 + * @return true:创建成功 false:创建失败
  41 + */
  42 + @Override
  43 + public boolean create(Device device) {
  44 + return redis.set(VideoManagerConstants.CACHEKEY_PREFIX+device.getDeviceId(), device);
  45 + }
  46 +
  47 + /**
  48 + * 视频设备更新
  49 + *
  50 + * @param device 设备对象
  51 + * @return true:更新成功 false:更新失败
  52 + */
  53 + @Override
  54 + public boolean update(Device device) {
  55 + return redis.set(VideoManagerConstants.CACHEKEY_PREFIX+device.getDeviceId(), device);
  56 + }
  57 +
  58 + /**
  59 + * 获取设备
  60 + *
  61 + * @param deviceId 设备ID
  62 + * @return Device 设备对象
  63 + */
  64 + @Override
  65 + public Device queryVideoDevice(String deviceId) {
  66 + return (Device)redis.get(VideoManagerConstants.CACHEKEY_PREFIX+deviceId);
  67 + }
  68 +
  69 + /**
  70 + * 获取多个设备
  71 + *
  72 + * @param deviceIds 设备ID数组
  73 + * @return List<Device> 设备对象数组
  74 + */
  75 + @Override
  76 + public List<Device> queryVideoDeviceList(String[] deviceIds) {
  77 + List<Device> devices = new ArrayList<>();
  78 + if (deviceIds == null || deviceIds.length == 0) {
  79 + List<Object> deviceIdList = redis.keys(VideoManagerConstants.CACHEKEY_PREFIX+"*");
  80 + for (int i = 0; i < deviceIdList.size(); i++) {
  81 + devices.add((Device)redis.get((String)deviceIdList.get(i)));
  82 + }
  83 + } else {
  84 + for (int i = 0; i < deviceIds.length; i++) {
  85 + devices.add((Device)redis.get(VideoManagerConstants.CACHEKEY_PREFIX+deviceIds[i]));
  86 + }
  87 + }
  88 + return devices;
  89 + }
  90 +
  91 + /**
  92 + * 删除设备
  93 + *
  94 + * @param deviceId 设备ID
  95 + * @return true:删除成功 false:删除失败
  96 + */
  97 + @Override
  98 + public boolean delete(String deviceId) {
  99 + redis.del(VideoManagerConstants.CACHEKEY_PREFIX+deviceId);
  100 + return true;
  101 + }
  102 +
  103 + /**
  104 + * 更新设备在线
  105 + *
  106 + * @param deviceId 设备ID
  107 + * @return true:更新成功 false:更新失败
  108 + */
  109 + @Override
  110 + public boolean online(String deviceId) {
  111 + Device device = (Device)redis.get(VideoManagerConstants.CACHEKEY_PREFIX+deviceId);
  112 + device.setOnline(1);
  113 + return redis.set(VideoManagerConstants.CACHEKEY_PREFIX+device.getDeviceId(), device);
  114 + }
  115 +
  116 + /**
  117 + * 更新设备离线
  118 + *
  119 + * @param deviceId 设备ID
  120 + * @return true:更新成功 false:更新失败
  121 + */
  122 + @Override
  123 + public boolean outline(String deviceId) {
  124 + Device device = (Device)redis.get(VideoManagerConstants.CACHEKEY_PREFIX+deviceId);
  125 + device.setOnline(0);
  126 + return redis.set(VideoManagerConstants.CACHEKEY_PREFIX+device.getDeviceId(), device);
  127 + }
  128 +
  129 +}
src/main/java/com/genersoft/iot/vmp/utils/redis/FastJsonRedisSerializer.java 0 → 100644
  1 +++ a/src/main/java/com/genersoft/iot/vmp/utils/redis/FastJsonRedisSerializer.java
  1 +package com.genersoft.iot.vmp.utils.redis;
  2 +
  3 +import java.nio.charset.Charset;
  4 +
  5 +import org.springframework.data.redis.serializer.RedisSerializer;
  6 +import org.springframework.data.redis.serializer.SerializationException;
  7 +
  8 +import com.alibaba.fastjson.JSON;
  9 +import com.alibaba.fastjson.serializer.SerializerFeature;
  10 +
  11 +/**
  12 + * @Description:使用fastjson实现redis的序列化
  13 + * @author: songww
  14 + * @date: 2020年5月6日 下午8:40:11
  15 + */
  16 +public class FastJsonRedisSerializer<T> implements RedisSerializer<T> {
  17 +
  18 + public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
  19 +
  20 + private Class<T> clazz;
  21 +
  22 + public FastJsonRedisSerializer(Class<T> clazz) {
  23 + super();
  24 + this.clazz = clazz;
  25 + }
  26 +
  27 + @Override
  28 + public byte[] serialize(T t) throws SerializationException {
  29 + if (t == null) {
  30 + return new byte[0];
  31 + }
  32 + return JSON.toJSONString(t, SerializerFeature.WriteClassName).getBytes(DEFAULT_CHARSET);
  33 + }
  34 +
  35 + @Override
  36 + public T deserialize(byte[] bytes) throws SerializationException {
  37 + if (bytes == null || bytes.length <= 0) {
  38 + return null;
  39 + }
  40 + String str = new String(bytes, DEFAULT_CHARSET);
  41 + return (T) JSON.parseObject(str, clazz);
  42 + }
  43 +}
src/main/java/com/genersoft/iot/vmp/utils/redis/RedisUtil.java 0 → 100644
  1 +++ a/src/main/java/com/genersoft/iot/vmp/utils/redis/RedisUtil.java
  1 +package com.genersoft.iot.vmp.utils.redis;
  2 +
  3 +import java.util.ArrayList;
  4 +import java.util.List;
  5 +import java.util.Map;
  6 +import java.util.Set;
  7 +import java.util.concurrent.TimeUnit;
  8 +
  9 +import org.springframework.beans.factory.annotation.Autowired;
  10 +import org.springframework.data.redis.core.RedisTemplate;
  11 +import org.springframework.stereotype.Component;
  12 +import org.springframework.util.CollectionUtils;
  13 +
  14 +/**
  15 + * @Description:Redis工具类
  16 + * @author: songww
  17 + * @date: 2020年5月6日 下午8:27:29
  18 + */
  19 +@Component
  20 +public class RedisUtil {
  21 +
  22 + @Autowired
  23 + private RedisTemplate redisTemplate;
  24 +
  25 + /**
  26 + * 指定缓存失效时间
  27 + * @param key 键
  28 + * @param time 时间(秒)
  29 + * @return true / false
  30 + */
  31 + public boolean expire(String key, long time) {
  32 + try {
  33 + if (time > 0) {
  34 + redisTemplate.expire(key, time, TimeUnit.SECONDS);
  35 + }
  36 + return true;
  37 + } catch (Exception e) {
  38 + e.printStackTrace();
  39 + return false;
  40 + }
  41 + }
  42 +
  43 + /**
  44 + * 根据 key 获取过期时间
  45 + * @param key 键
  46 + * @return
  47 + */
  48 + public long getExpire(String key) {
  49 + return redisTemplate.getExpire(key, TimeUnit.SECONDS);
  50 + }
  51 +
  52 + /**
  53 + * 判断 key 是否存在
  54 + * @param key 键
  55 + * @return true / false
  56 + */
  57 + public boolean hasKey(String key) {
  58 + try {
  59 + return redisTemplate.hasKey(key);
  60 + } catch (Exception e) {
  61 + e.printStackTrace();
  62 + return false;
  63 + }
  64 + }
  65 +
  66 + /**
  67 + * 删除缓存
  68 + * @SuppressWarnings("unchecked") 忽略类型转换警告
  69 + * @param key 键(一个或者多个)
  70 + */
  71 + public void del(String... key) {
  72 + if (key != null && key.length > 0) {
  73 + if (key.length == 1) {
  74 + redisTemplate.delete(key[0]);
  75 + } else {
  76 +// 传入一个 Collection<String> 集合
  77 + redisTemplate.delete(CollectionUtils.arrayToList(key));
  78 + }
  79 + }
  80 + }
  81 +
  82 +// ============================== String ==============================
  83 +
  84 + /**
  85 + * 普通缓存获取
  86 + * @param key 键
  87 + * @return 值
  88 + */
  89 + public Object get(String key) {
  90 + return key == null ? null : redisTemplate.opsForValue().get(key);
  91 + }
  92 +
  93 + /**
  94 + * 普通缓存放入
  95 + * @param key 键
  96 + * @param value 值
  97 + * @return true / false
  98 + */
  99 + public boolean set(String key, Object value) {
  100 + try {
  101 + redisTemplate.opsForValue().set(key, value);
  102 + return true;
  103 + } catch (Exception e) {
  104 + e.printStackTrace();
  105 + return false;
  106 + }
  107 + }
  108 +
  109 + /**
  110 + * 普通缓存放入并设置时间
  111 + * @param key 键
  112 + * @param value 值
  113 + * @param time 时间(秒),如果 time < 0 则设置无限时间
  114 + * @return true / false
  115 + */
  116 + public boolean set(String key, Object value, long time) {
  117 + try {
  118 + if (time > 0) {
  119 + redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
  120 + } else {
  121 + set(key, value);
  122 + }
  123 + return true;
  124 + } catch (Exception e) {
  125 + e.printStackTrace();
  126 + return false;
  127 + }
  128 + }
  129 +
  130 + /**
  131 + * 递增
  132 + * @param key 键
  133 + * @param delta 递增大小
  134 + * @return
  135 + */
  136 + public long incr(String key, long delta) {
  137 + if (delta < 0) {
  138 + throw new RuntimeException("递增因子必须大于 0");
  139 + }
  140 + return redisTemplate.opsForValue().increment(key, delta);
  141 + }
  142 +
  143 + /**
  144 + * 递减
  145 + * @param key 键
  146 + * @param delta 递减大小
  147 + * @return
  148 + */
  149 + public long decr(String key, long delta) {
  150 + if (delta < 0) {
  151 + throw new RuntimeException("递减因子必须大于 0");
  152 + }
  153 + return redisTemplate.opsForValue().increment(key, delta);
  154 + }
  155 +
  156 +// ============================== Map ==============================
  157 +
  158 + /**
  159 + * HashGet
  160 + * @param key 键(no null)
  161 + * @param item 项(no null)
  162 + * @return 值
  163 + */
  164 + public Object hget(String key, String item) {
  165 + return redisTemplate.opsForHash().get(key, item);
  166 + }
  167 +
  168 + /**
  169 + * 获取 key 对应的 map
  170 + * @param key 键(no null)
  171 + * @return 对应的多个键值
  172 + */
  173 + public Map<Object, Object> hmget(String key) {
  174 + return redisTemplate.opsForHash().entries(key);
  175 + }
  176 +
  177 + /**
  178 + * HashSet
  179 + * @param key 键
  180 + * @param map 值
  181 + * @return true / false
  182 + */
  183 + public boolean hmset(String key, Map<Object, Object> map) {
  184 + try {
  185 + redisTemplate.opsForHash().putAll(key, map);
  186 + return true;
  187 + } catch (Exception e) {
  188 + e.printStackTrace();
  189 + return false;
  190 + }
  191 + }
  192 +
  193 + /**
  194 + * HashSet 并设置时间
  195 + * @param key 键
  196 + * @param map 值
  197 + * @param time 时间
  198 + * @return true / false
  199 + */
  200 + public boolean hmset(String key, Map<Object, Object> map, long time) {
  201 + try {
  202 + redisTemplate.opsForHash().putAll(key, map);
  203 + if (time > 0) {
  204 + expire(key, time);
  205 + }
  206 + return true;
  207 + } catch (Exception e) {
  208 + e.printStackTrace();
  209 + return false;
  210 + }
  211 + }
  212 +
  213 + /**
  214 + * 向一张 Hash表 中放入数据,如不存在则创建
  215 + * @param key 键
  216 + * @param item 项
  217 + * @param value 值
  218 + * @return true / false
  219 + */
  220 + public boolean hset(String key, String item, Object value) {
  221 + try {
  222 + redisTemplate.opsForHash().put(key, item, value);
  223 + return true;
  224 + } catch (Exception e) {
  225 + e.printStackTrace();
  226 + return false;
  227 + }
  228 + }
  229 +
  230 + /**
  231 + * 向一张 Hash表 中放入数据,并设置时间,如不存在则创建
  232 + * @param key 键
  233 + * @param item 项
  234 + * @param value 值
  235 + * @param time 时间(如果原来的 Hash表 设置了时间,这里会覆盖)
  236 + * @return true / false
  237 + */
  238 + public boolean hset(String key, String item, Object value, long time) {
  239 + try {
  240 + redisTemplate.opsForHash().put(key, item, value);
  241 + if (time > 0) {
  242 + expire(key, time);
  243 + }
  244 + return true;
  245 + } catch (Exception e) {
  246 + e.printStackTrace();
  247 + return false;
  248 + }
  249 + }
  250 +
  251 + /**
  252 + * 删除 Hash表 中的值
  253 + * @param key 键
  254 + * @param item 项(可以多个,no null)
  255 + */
  256 + public void hdel(String key, Object... item) {
  257 + redisTemplate.opsForHash().delete(key, item);
  258 + }
  259 +
  260 + /**
  261 + * 判断 Hash表 中是否有该键的值
  262 + * @param key 键(no null)
  263 + * @param item 值(no null)
  264 + * @return true / false
  265 + */
  266 + public boolean hHasKey(String key, String item) {
  267 + return redisTemplate.opsForHash().hasKey(key, item);
  268 + }
  269 +
  270 + /**
  271 + * Hash递增,如果不存在则创建一个,并把新增的值返回
  272 + * @param key 键
  273 + * @param item 项
  274 + * @param by 递增大小 > 0
  275 + * @return
  276 + */
  277 + public Double hincr(String key, String item, Double by) {
  278 + return redisTemplate.opsForHash().increment(key, item, by);
  279 + }
  280 +
  281 + /**
  282 + * Hash递减
  283 + * @param key 键
  284 + * @param item 项
  285 + * @param by 递减大小
  286 + * @return
  287 + */
  288 + public Double hdecr(String key, String item, Double by) {
  289 + return redisTemplate.opsForHash().increment(key, item, -by);
  290 + }
  291 +
  292 +// ============================== Set ==============================
  293 +
  294 + /**
  295 + * 根据 key 获取 set 中的所有值
  296 + * @param key 键
  297 + * @return 值
  298 + */
  299 + public Set<Object> sGet(String key) {
  300 + try {
  301 + return redisTemplate.opsForSet().members(key);
  302 + } catch (Exception e) {
  303 + e.printStackTrace();
  304 + return null;
  305 + }
  306 + }
  307 +
  308 + /**
  309 + * 从键为 key 的 set 中,根据 value 查询是否存在
  310 + * @param key 键
  311 + * @param value 值
  312 + * @return true / false
  313 + */
  314 + public boolean sHasKey(String key, Object value) {
  315 + try {
  316 + return redisTemplate.opsForSet().isMember(key, value);
  317 + } catch (Exception e) {
  318 + e.printStackTrace();
  319 + return false;
  320 + }
  321 + }
  322 +
  323 + /**
  324 + * 将数据放入 set缓存
  325 + * @param key 键值
  326 + * @param values 值(可以多个)
  327 + * @return 成功个数
  328 + */
  329 + public long sSet(String key, Object... values) {
  330 + try {
  331 + return redisTemplate.opsForSet().add(key, values);
  332 + } catch (Exception e) {
  333 + e.printStackTrace();
  334 + return 0;
  335 + }
  336 + }
  337 +
  338 + /**
  339 + * 将数据放入 set缓存,并设置时间
  340 + * @param key 键
  341 + * @param time 时间
  342 + * @param values 值(可以多个)
  343 + * @return 成功放入个数
  344 + */
  345 + public long sSet(String key, long time, Object... values) {
  346 + try {
  347 + long count = redisTemplate.opsForSet().add(key, values);
  348 + if (time > 0) {
  349 + expire(key, time);
  350 + }
  351 + return count;
  352 + } catch (Exception e) {
  353 + e.printStackTrace();
  354 + return 0;
  355 + }
  356 + }
  357 +
  358 + /**
  359 + * 获取 set缓存的长度
  360 + * @param key 键
  361 + * @return 长度
  362 + */
  363 + public long sGetSetSize(String key) {
  364 + try {
  365 + return redisTemplate.opsForSet().size(key);
  366 + } catch (Exception e) {
  367 + e.printStackTrace();
  368 + return 0;
  369 + }
  370 + }
  371 +
  372 + /**
  373 + * 移除 set缓存中,值为 value 的
  374 + * @param key 键
  375 + * @param values 值
  376 + * @return 成功移除个数
  377 + */
  378 + public long setRemove(String key, Object... values) {
  379 + try {
  380 + return redisTemplate.opsForSet().remove(key, values);
  381 + } catch (Exception e) {
  382 + e.printStackTrace();
  383 + return 0;
  384 + }
  385 + }
  386 +
  387 +// ============================== List ==============================
  388 +
  389 + /**
  390 + * 获取 list缓存的内容
  391 + * @param key 键
  392 + * @param start 开始
  393 + * @param end 结束(0 到 -1 代表所有值)
  394 + * @return
  395 + */
  396 + public List<Object> lGet(String key, long start, long end) {
  397 + try {
  398 + return redisTemplate.opsForList().range(key, start, end);
  399 + } catch (Exception e) {
  400 + e.printStackTrace();
  401 + return null;
  402 + }
  403 + }
  404 +
  405 + /**
  406 + * 获取 list缓存的长度
  407 + * @param key 键
  408 + * @return 长度
  409 + */
  410 + public long lGetListSize(String key) {
  411 + try {
  412 + return redisTemplate.opsForList().size(key);
  413 + } catch (Exception e) {
  414 + e.printStackTrace();
  415 + return 0;
  416 + }
  417 + }
  418 +
  419 + /**
  420 + * 根据索引 index 获取键为 key 的 list 中的元素
  421 + * @param key 键
  422 + * @param index 索引
  423 + * 当 index >= 0 时 {0:表头, 1:第二个元素}
  424 + * 当 index < 0 时 {-1:表尾, -2:倒数第二个元素}
  425 + * @return 值
  426 + */
  427 + public Object lGetIndex(String key, long index) {
  428 + try {
  429 + return redisTemplate.opsForList().index(key, index);
  430 + } catch (Exception e) {
  431 + e.printStackTrace();
  432 + return null;
  433 + }
  434 + }
  435 +
  436 + /**
  437 + * 将值 value 插入键为 key 的 list 中,如果 list 不存在则创建空 list
  438 + * @param key 键
  439 + * @param value 值
  440 + * @return true / false
  441 + */
  442 + public boolean lSet(String key, Object value) {
  443 + try {
  444 + redisTemplate.opsForList().rightPush(key, value);
  445 + return true;
  446 + } catch (Exception e) {
  447 + e.printStackTrace();
  448 + return false;
  449 + }
  450 + }
  451 +
  452 + /**
  453 + * 将值 value 插入键为 key 的 list 中,并设置时间
  454 + * @param key 键
  455 + * @param value 值
  456 + * @param time 时间
  457 + * @return true / false
  458 + */
  459 + public boolean lSet(String key, Object value, long time) {
  460 + try {
  461 + redisTemplate.opsForList().rightPush(key, value);
  462 + if (time > 0) {
  463 + expire(key, time);
  464 + }
  465 + return true;
  466 + } catch (Exception e) {
  467 + e.printStackTrace();
  468 + return false;
  469 + }
  470 + }
  471 +
  472 + /**
  473 + * 将 values 插入键为 key 的 list 中
  474 + * @param key 键
  475 + * @param values 值
  476 + * @return true / false
  477 + */
  478 + public boolean lSetList(String key, List<Object> values) {
  479 + try {
  480 + redisTemplate.opsForList().rightPushAll(key, values);
  481 + return true;
  482 + } catch (Exception e) {
  483 + e.printStackTrace();
  484 + return false;
  485 + }
  486 + }
  487 +
  488 + /**
  489 + * 将 values 插入键为 key 的 list 中,并设置时间
  490 + * @param key 键
  491 + * @param values 值
  492 + * @param time 时间
  493 + * @return true / false
  494 + */
  495 + public boolean lSetList(String key, List<Object> values, long time) {
  496 + try {
  497 + redisTemplate.opsForList().rightPushAll(key, values);
  498 + if (time > 0) {
  499 + expire(key, time);
  500 + }
  501 + return true;
  502 + } catch (Exception e) {
  503 + e.printStackTrace();
  504 + return false;
  505 + }
  506 + }
  507 +
  508 + /**
  509 + * 根据索引 index 修改键为 key 的值
  510 + * @param key 键
  511 + * @param index 索引
  512 + * @param value 值
  513 + * @return true / false
  514 + */
  515 + public boolean lUpdateIndex(String key, long index, Object value) {
  516 + try {
  517 + redisTemplate.opsForList().set(key, index, value);
  518 + return true;
  519 + } catch (Exception e) {
  520 + e.printStackTrace();
  521 + return false;
  522 + }
  523 + }
  524 +
  525 + /**
  526 + * 在键为 key 的 list 中删除值为 value 的元素
  527 + * @param key 键
  528 + * @param count 如果 count == 0 则删除 list 中所有值为 value 的元素
  529 + * 如果 count > 0 则删除 list 中最左边那个值为 value 的元素
  530 + * 如果 count < 0 则删除 list 中最右边那个值为 value 的元素
  531 + * @param value
  532 + * @return
  533 + */
  534 + public long lRemove(String key, long count, Object value) {
  535 + try {
  536 + return redisTemplate.opsForList().remove(key, count, value);
  537 + } catch (Exception e) {
  538 + e.printStackTrace();
  539 + return 0;
  540 + }
  541 + }
  542 +
  543 + /**
  544 + * 模糊查询
  545 + * @param key 键
  546 + * @return true / false
  547 + */
  548 + public List<Object> keys(String key) {
  549 + try {
  550 + Set<String> set = redisTemplate.keys(key);
  551 + return new ArrayList<>(set);
  552 + } catch (Exception e) {
  553 + e.printStackTrace();
  554 + return null;
  555 + }
  556 + }
  557 +}
src/main/java/com/genersoft/iot/vmp/vmanager/device/DeviceController.java 0 → 100644
  1 +++ a/src/main/java/com/genersoft/iot/vmp/vmanager/device/DeviceController.java
  1 +package com.genersoft.iot.vmp.vmanager.device;
  2 +
  3 +import java.util.ArrayList;
  4 +import java.util.List;
  5 +
  6 +import org.slf4j.Logger;
  7 +import org.slf4j.LoggerFactory;
  8 +import org.springframework.beans.factory.annotation.Autowired;
  9 +import org.springframework.http.HttpStatus;
  10 +import org.springframework.http.ResponseEntity;
  11 +import org.springframework.web.bind.annotation.GetMapping;
  12 +import org.springframework.web.bind.annotation.PathVariable;
  13 +import org.springframework.web.bind.annotation.RequestMapping;
  14 +import org.springframework.web.bind.annotation.RestController;
  15 +
  16 +import com.genersoft.iot.vmp.gb28181.bean.Device;
  17 +import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
  18 +
  19 +@RestController
  20 +@RequestMapping("/api")
  21 +public class DeviceController {
  22 +
  23 + private final static Logger logger = LoggerFactory.getLogger(DeviceController.class);
  24 +
  25 + @Autowired
  26 + private IVideoManagerStorager storager;
  27 +
  28 + @GetMapping("/devices/{deviceId}")
  29 + public ResponseEntity<List<Device>> devices(@PathVariable String deviceId){
  30 +
  31 + if (logger.isDebugEnabled()) {
  32 + logger.debug("查询视频设备API调用,deviceId:" + deviceId);
  33 + }
  34 +
  35 + List<Device> deviceList = new ArrayList<>();
  36 + deviceList.add(storager.queryVideoDevice(deviceId));
  37 + return new ResponseEntity<>(deviceList,HttpStatus.OK);
  38 + }
  39 +
  40 + @GetMapping("/devices")
  41 + public ResponseEntity<List<Device>> devices(){
  42 +
  43 + if (logger.isDebugEnabled()) {
  44 + logger.debug("查询所有视频设备API调用");
  45 + }
  46 +
  47 + List<Device> deviceList = storager.queryVideoDeviceList(null);
  48 + return new ResponseEntity<>(deviceList,HttpStatus.OK);
  49 + }
  50 +}
src/main/java/com/genersoft/iot/vmp/vmanager/play/PlayController.java 0 → 100644
  1 +++ a/src/main/java/com/genersoft/iot/vmp/vmanager/play/PlayController.java
  1 +package com.genersoft.iot.vmp.vmanager.play;
  2 +
  3 +import org.slf4j.Logger;
  4 +import org.slf4j.LoggerFactory;
  5 +import org.springframework.beans.factory.annotation.Autowired;
  6 +import org.springframework.http.HttpStatus;
  7 +import org.springframework.http.ResponseEntity;
  8 +import org.springframework.web.bind.annotation.GetMapping;
  9 +import org.springframework.web.bind.annotation.PathVariable;
  10 +import org.springframework.web.bind.annotation.RequestMapping;
  11 +import org.springframework.web.bind.annotation.RestController;
  12 +
  13 +import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
  14 +
  15 +@RestController
  16 +@RequestMapping("/api")
  17 +public class PlayController {
  18 +
  19 + private final static Logger logger = LoggerFactory.getLogger(PlayController.class);
  20 +
  21 + @Autowired
  22 + private SIPCommander cmder;
  23 +
  24 + @GetMapping("/play/{deviceId}_{channelId}")
  25 + public ResponseEntity<String> play(@PathVariable String deviceId,@PathVariable String channelId){
  26 +
  27 + String ssrc = cmder.playStreamCmd(deviceId, channelId);
  28 +
  29 + if (logger.isDebugEnabled()) {
  30 + logger.debug(String.format("设备预览 API调用,deviceId:%s ,channelId:%s",deviceId, channelId));
  31 + logger.debug("设备预览 API调用,ssrc:"+ssrc+",ZLMedia streamId:"+Integer.toHexString(Integer.parseInt(ssrc)));
  32 + }
  33 +
  34 + if(ssrc!=null) {
  35 + return new ResponseEntity<String>(ssrc,HttpStatus.OK);
  36 + } else {
  37 + logger.warn("设备预览API调用失败!");
  38 + return new ResponseEntity<String>(HttpStatus.INTERNAL_SERVER_ERROR);
  39 + }
  40 + }
  41 +}
src/main/java/com/genersoft/iot/vmp/vmanager/ptz/PtzController.java 0 → 100644
  1 +++ a/src/main/java/com/genersoft/iot/vmp/vmanager/ptz/PtzController.java
  1 +package com.genersoft.iot.vmp.vmanager.ptz;
  2 +
  3 +import org.slf4j.Logger;
  4 +import org.slf4j.LoggerFactory;
  5 +import org.springframework.beans.factory.annotation.Autowired;
  6 +import org.springframework.http.HttpStatus;
  7 +import org.springframework.http.ResponseEntity;
  8 +import org.springframework.web.bind.annotation.GetMapping;
  9 +import org.springframework.web.bind.annotation.PathVariable;
  10 +import org.springframework.web.bind.annotation.RequestMapping;
  11 +import org.springframework.web.bind.annotation.RestController;
  12 +
  13 +import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
  14 +
  15 +@RestController
  16 +@RequestMapping("/api")
  17 +public class PtzController {
  18 +
  19 + private final static Logger logger = LoggerFactory.getLogger(PtzController.class);
  20 +
  21 + @Autowired
  22 + private SIPCommander cmder;
  23 +
  24 + /***
  25 + * http://localhost:8080/api/ptz/34020000001320000002_34020000001320000008?leftRight=1&upDown=0&inOut=0&moveSpeed=50&zoomSpeed=0
  26 + * @param deviceId
  27 + * @param channelId
  28 + * @param leftRight
  29 + * @param upDown
  30 + * @param inOut
  31 + * @param moveSpeed
  32 + * @param zoomSpeed
  33 + * @return
  34 + */
  35 + @GetMapping("/ptz/{deviceId}_{channelId}")
  36 + public ResponseEntity<String> ptz(@PathVariable String deviceId,@PathVariable String channelId,int leftRight, int upDown, int inOut, int moveSpeed, int zoomSpeed){
  37 +
  38 + if (logger.isDebugEnabled()) {
  39 + 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));
  40 + }
  41 +
  42 + cmder.ptzCmd(deviceId, channelId, leftRight, upDown, inOut, moveSpeed, zoomSpeed);
  43 + return new ResponseEntity<String>("success",HttpStatus.OK);
  44 + }
  45 +}
src/main/resources/application.yml 0 → 100644
  1 +++ a/src/main/resources/application.yml
  1 +spring:
  2 + application:
  3 + name: wvp
  4 + # 数据存储方式,支持redis、jdbc
  5 + database: redis
  6 + redis:
  7 + # Redis服务器IP
  8 + host: 127.0.0.1
  9 + #端口号
  10 + port: 6379
  11 + datebase: 0
  12 + #访问密码,若你的redis服务器没有设置密码,就不需要用密码去连接
  13 + password:
  14 + #超时时间
  15 + timeout: 10000
  16 + datasource:
  17 + name: wcp
  18 + url: jdbc:mysql://127.0.0.1:3306/wcp?useUnicode=true&characterEncoding=UTF8&rewriteBatchedStatements=true
  19 + username: root
  20 + password: 123456
  21 + type: com.alibaba.druid.pool.DruidDataSource
  22 + driver-class-name: com.mysql.jdbc.Driver
  23 +server:
  24 + port: 8080
  25 +sip:
  26 + # 本地服务地址
  27 + ip: 192.168.0.3
  28 + server_id: 34020000002000000001
  29 + port: 5060
  30 + domain: 34020000
  31 + # 暂时使用统一密码,后续改为一机一密
  32 + password: admin
  33 +media:
  34 + # ZLMediaServer IP
  35 + ip: 192.168.0.4
  36 + port: 10000
0 \ No newline at end of file 37 \ No newline at end of file