Commit 70091f29f2c3c3f974ffc2cc8f140db9f992ca0e
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 |