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