Browse Source

fix #61 1、支持配置接入多台ZLM。2、播流会话数据存储到redis,防止wvp宕机后会话数据丢失。3、master合并到2.0分支。4、移除lombok。5、代码格式化。

pull/76/head
wangshaopeng@sunnybs.com 4 years ago
parent
commit
1fe9569af2
  1. 1
      .gitignore
  2. 439
      pom.xml
  3. 25
      src/main/java/com/genersoft/iot/vmp/VManageBootstrap.java
  4. 133
      src/main/java/com/genersoft/iot/vmp/common/StreamInfo.java
  5. 97
      src/main/java/com/genersoft/iot/vmp/conf/MediaConfig.java
  6. 535
      src/main/java/com/genersoft/iot/vmp/conf/MediaServerConfig.java
  7. 16
      src/main/java/com/genersoft/iot/vmp/conf/SsrcConfig.java
  8. 72
      src/main/java/com/genersoft/iot/vmp/gb28181/SipLayer.java
  9. 14
      src/main/java/com/genersoft/iot/vmp/gb28181/session/VideoStreamSessionManager.java
  10. 372
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPProcessorFactory.java
  11. 72
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/callback/DeferredResultHolder.java
  12. 579
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java
  13. 330
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderProvider.java
  14. 1500
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java
  15. 233
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/AckRequestProcessor.java
  16. 225
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/ByeRequestProcessor.java
  17. 761
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/InviteRequestProcessor.java
  18. 799
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/MessageRequestProcessor.java
  19. 322
      src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java
  20. 13
      src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMMediaListManager.java
  21. 29
      src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRESTfulUtils.java
  22. 47
      src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRTPServerFactory.java
  23. 17
      src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRunner.java
  24. 9
      src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java
  25. 203
      src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorager.java
  26. 39
      src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java
  27. 719
      src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStoragerImpl.java
  28. 20
      src/main/java/com/genersoft/iot/vmp/utils/redis/RedisUtil.java
  29. 146
      src/main/java/com/genersoft/iot/vmp/vmanager/play/PlayController.java
  30. 37
      src/main/java/com/genersoft/iot/vmp/vmanager/play/bean/PlayResult.java
  31. 7
      src/main/java/com/genersoft/iot/vmp/vmanager/service/IPlayService.java
  32. 126
      src/main/java/com/genersoft/iot/vmp/vmanager/service/impl/PlayServiceImpl.java
  33. 168
      src/main/resources/application-dev.yml
  34. 2
      src/main/resources/application.yml

1
.gitignore

@ -26,5 +26,6 @@ hs_err_pid*
/.idea/*
/target/*
/.idea/
/logs/
/target/

439
pom.xml

@ -1,225 +1,220 @@
<?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>2.3.5.RELEASE</version>
</parent>
<groupId>com.genersoft</groupId>
<artifactId>wvp</artifactId>
<name>web video platform</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<!-- 依赖版本 -->
<mybatis-spring-boot-starter-version>2.1.4</mybatis-spring-boot-starter-version>
<druid-version>1.2.3</druid-version>
<mysql-connector-java-version>8.0.22</mysql-connector-java-version>
<sqlite-jdbc-version>3.32.3.2</sqlite-jdbc-version>
<jedis-version>3.1.0</jedis-version>
<pagehelper-spring-boot-starter-version>1.2.10</pagehelper-spring-boot-starter-version>
<springfox-swagger2-version>2.9.2</springfox-swagger2-version>
<springfox-swagger-ui-version>2.6.1</springfox-swagger-ui-version>
<jain-sip-ri-version>1.3.0-91</jain-sip-ri-version>
<log4j-version>1.2.17</log4j-version>
<dom4j-version>2.1.3</dom4j-version>
<fastjson-version>1.2.73</fastjson-version>
<guava-version>30.0-jre</guava-version>
<lombok-version>1.18.12</lombok-version>
<commons-lang3-version>3.7</commons-lang3-version>
<commons-io-version>2.6</commons-io-version>
<okhttp-version>4.9.0</okhttp-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>
</properties>
<repositories>
<repository>
<id>nexus-aliyun</id>
<name>Nexus aliyun</name>
<url>https://maven.aliyun.com/repository/public</url>
<layout>default</layout>
<snapshots>
<enabled>false</enabled>
</snapshots>
<releases>
<enabled>true</enabled>
</releases>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>nexus-aliyun</id>
<name>Nexus aliyun</name>
<url>https://maven.aliyun.com/repository/public</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
<releases>
<enabled>true</enabled>
</releases>
</pluginRepository>
</pluginRepositories>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>${mybatis-spring-boot-starter-version}</version>
</dependency>
<!-- druid数据库连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>${druid-version}</version>
</dependency>
<!-- mysql数据库 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql-connector-java-version}</version>
</dependency>
<!-- 添加sqlite-jdbc数据库驱动 -->
<dependency>
<groupId>org.xerial</groupId>
<artifactId>sqlite-jdbc</artifactId>
<version>${sqlite-jdbc-version}</version>
</dependency>
<!--Mybatis分页插件 -->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>${pagehelper-spring-boot-starter-version}</version>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>${jedis-version}</version>
</dependency>
<!--Swagger2 -->
<!--在线文档 -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>${springfox-swagger2-version}</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>${springfox-swagger-ui-version}</version>
</dependency>
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
</dependency>
<!-- 日志相关 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<!-- sip协议栈 -->
<dependency>
<groupId>javax.sip</groupId>
<artifactId>jain-sip-ri</artifactId>
<version>${jain-sip-ri-version}</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j-version}</version>
</dependency>
<!-- xml解析库 -->
<dependency>
<groupId>org.dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>${dom4j-version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${fastjson-version}</version>
</dependency>
<!--Guava是一种基于开源的Java库-->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>${guava-version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok-version}</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>${commons-lang3-version}</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>${commons-io-version}</version>
</dependency>
<!-- okhttp -->
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>${okhttp-version}</version>
</dependency>
<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>2.3.5.RELEASE</version>
</parent>
<groupId>com.genersoft</groupId>
<artifactId>wvp</artifactId>
<name>web video platform</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<!-- 依赖版本 -->
<mybatis-spring-boot-starter-version>2.1.4</mybatis-spring-boot-starter-version>
<druid-version>1.2.3</druid-version>
<mysql-connector-java-version>8.0.22</mysql-connector-java-version>
<sqlite-jdbc-version>3.32.3.2</sqlite-jdbc-version>
<jedis-version>3.1.0</jedis-version>
<pagehelper-spring-boot-starter-version>1.2.10</pagehelper-spring-boot-starter-version>
<springfox-swagger2-version>2.9.2</springfox-swagger2-version>
<springfox-swagger-ui-version>2.6.1</springfox-swagger-ui-version>
<jain-sip-ri-version>1.3.0-91</jain-sip-ri-version>
<log4j-version>1.2.17</log4j-version>
<dom4j-version>2.1.3</dom4j-version>
<fastjson-version>1.2.73</fastjson-version>
<guava-version>30.0-jre</guava-version>
<lombok-version>1.18.12</lombok-version>
<commons-lang3-version>3.7</commons-lang3-version>
<commons-io-version>2.6</commons-io-version>
<okhttp-version>4.9.0</okhttp-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>
</properties>
<repositories>
<repository>
<id>nexus-aliyun</id>
<name>Nexus aliyun</name>
<url>https://maven.aliyun.com/repository/public</url>
<layout>default</layout>
<snapshots>
<enabled>false</enabled>
</snapshots>
<releases>
<enabled>true</enabled>
</releases>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>nexus-aliyun</id>
<name>Nexus aliyun</name>
<url>https://maven.aliyun.com/repository/public</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
<releases>
<enabled>true</enabled>
</releases>
</pluginRepository>
</pluginRepositories>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>${mybatis-spring-boot-starter-version}</version>
</dependency>
<!-- druid数据库连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>${druid-version}</version>
</dependency>
<!-- mysql数据库 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql-connector-java-version}</version>
</dependency>
<!-- 添加sqlite-jdbc数据库驱动 -->
<dependency>
<groupId>org.xerial</groupId>
<artifactId>sqlite-jdbc</artifactId>
<version>${sqlite-jdbc-version}</version>
</dependency>
<!--Mybatis分页插件 -->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>${pagehelper-spring-boot-starter-version}</version>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>${jedis-version}</version>
</dependency>
<!--Swagger2 -->
<!--在线文档 -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>${springfox-swagger2-version}</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>${springfox-swagger-ui-version}</version>
</dependency>
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
</dependency>
<!-- 日志相关 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<!-- sip协议栈 -->
<dependency>
<groupId>javax.sip</groupId>
<artifactId>jain-sip-ri</artifactId>
<version>${jain-sip-ri-version}</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j-version}</version>
</dependency>
<!-- xml解析库 -->
<dependency>
<groupId>org.dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>${dom4j-version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${fastjson-version}</version>
</dependency>
<!--Guava是一种基于开源的Java库-->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>${guava-version}</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>${commons-lang3-version}</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>${commons-io-version}</version>
</dependency>
<!-- okhttp -->
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>${okhttp-version}</version>
</dependency>
</dependencies>
<build>
<finalName>wvp-2.5.8</finalName>
<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>
<build>
<finalName>wvp-2.5.8</finalName>
<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>

25
src/main/java/com/genersoft/iot/vmp/VManageBootstrap.java

@ -5,17 +5,18 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
@SpringBootApplication
public class VManageBootstrap extends LogManager {
private static String[] args;
private static ConfigurableApplicationContext context;
public static void main(String[] args) {
VManageBootstrap.args = args;
VManageBootstrap.context = SpringApplication.run(VManageBootstrap.class, args);
}
// 项目重启
public static void restart() {
context.close();
VManageBootstrap.context = SpringApplication.run(VManageBootstrap.class, args);
public class VManageBootstrap {
private static String[] args;
private static ConfigurableApplicationContext context;
}
public static void main(String[] args) {
VManageBootstrap.args = args;
VManageBootstrap.context = SpringApplication.run(VManageBootstrap.class, args);
}
// 项目重启
public static void restart() {
context.close();
VManageBootstrap.context = SpringApplication.run(VManageBootstrap.class, args);
}
}

133
src/main/java/com/genersoft/iot/vmp/common/StreamInfo.java

@ -1,9 +1,10 @@
package com.genersoft.iot.vmp.common;
import com.alibaba.fastjson.JSONArray;
import lombok.Data;
@Data
/**
* @author skywsp
*/
public class StreamInfo {
/**
@ -25,4 +26,132 @@ public class StreamInfo {
private String rtmp;
private String rtsp;
private JSONArray tracks;
public String getMediaServerIp() {
return mediaServerIp;
}
public void setMediaServerIp(String mediaServerIp) {
this.mediaServerIp = mediaServerIp;
}
public String getSsrc() {
return ssrc;
}
public void setSsrc(String ssrc) {
this.ssrc = ssrc;
}
public String getDeviceID() {
return deviceID;
}
public void setDeviceID(String deviceID) {
this.deviceID = deviceID;
}
public String getChannelId() {
return channelId;
}
public void setChannelId(String channelId) {
this.channelId = channelId;
}
public String getFlv() {
return flv;
}
public void setFlv(String flv) {
this.flv = flv;
}
public String getWs_flv() {
return ws_flv;
}
public void setWs_flv(String ws_flv) {
this.ws_flv = ws_flv;
}
public String getRtmp() {
return rtmp;
}
public void setRtmp(String rtmp) {
this.rtmp = rtmp;
}
public String getHls() {
return hls;
}
public void setHls(String hls) {
this.hls = hls;
}
public String getRtsp() {
return rtsp;
}
public void setRtsp(String rtsp) {
this.rtsp = rtsp;
}
public JSONArray getTracks() {
return tracks;
}
public void setTracks(JSONArray tracks) {
this.tracks = tracks;
}
public String getFmp4() {
return fmp4;
}
public void setFmp4(String fmp4) {
this.fmp4 = fmp4;
}
public String getWs_fmp4() {
return ws_fmp4;
}
public void setWs_fmp4(String ws_fmp4) {
this.ws_fmp4 = ws_fmp4;
}
public String getWs_hls() {
return ws_hls;
}
public void setWs_hls(String ws_hls) {
this.ws_hls = ws_hls;
}
public String getTs() {
return ts;
}
public void setTs(String ts) {
this.ts = ts;
}
public String getWs_ts() {
return ws_ts;
}
public void setWs_ts(String ws_ts) {
this.ws_ts = ws_ts;
}
public String getStreamId() {
return streamId;
}
public void setStreamId(String streamId) {
this.streamId = streamId;
}
}

97
src/main/java/com/genersoft/iot/vmp/conf/MediaConfig.java

@ -1,6 +1,5 @@
package com.genersoft.iot.vmp.conf;
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
@ -11,7 +10,6 @@ import java.util.HashMap;
* 对配置文件进行校验
*/
@Configuration("mediaConfig")
@Data
public class MediaConfig {
@Value("${media.ip}")
private String mediaIp;
@ -50,4 +48,99 @@ public class MediaConfig {
*/
private HashMap<String, SsrcConfig> mediaServerSsrcMap;
public String getMediaIp() {
return mediaIp;
}
public void setMediaIp(String mediaIp) {
this.mediaIp = mediaIp;
}
public String[] getMediaIpArr() {
return mediaIpArr;
}
public void setMediaIpArr(String[] mediaIpArr) {
this.mediaIpArr = mediaIpArr;
}
public String getMediaHookIp() {
return mediaHookIp;
}
public void setMediaHookIp(String mediaHookIp) {
this.mediaHookIp = mediaHookIp;
}
public Integer getMediaPort() {
return mediaPort;
}
public void setMediaPort(Integer mediaPort) {
this.mediaPort = mediaPort;
}
public Boolean getAutoConfig() {
return autoConfig;
}
public void setAutoConfig(Boolean autoConfig) {
this.autoConfig = autoConfig;
}
public String getMediaSecret() {
return mediaSecret;
}
public void setMediaSecret(String mediaSecret) {
this.mediaSecret = mediaSecret;
}
public String getStreamNoneReaderDelayMS() {
return streamNoneReaderDelayMS;
}
public void setStreamNoneReaderDelayMS(String streamNoneReaderDelayMS) {
this.streamNoneReaderDelayMS = streamNoneReaderDelayMS;
}
public Boolean getAutoApplyPlay() {
return autoApplyPlay;
}
public void setAutoApplyPlay(Boolean autoApplyPlay) {
this.autoApplyPlay = autoApplyPlay;
}
public Boolean getSeniorSdp() {
return seniorSdp;
}
public void setSeniorSdp(Boolean seniorSdp) {
this.seniorSdp = seniorSdp;
}
public Boolean getRtpEnable() {
return rtpEnable;
}
public void setRtpEnable(Boolean rtpEnable) {
this.rtpEnable = rtpEnable;
}
public String getUdpPortRange() {
return udpPortRange;
}
public void setUdpPortRange(String udpPortRange) {
this.udpPortRange = udpPortRange;
}
public HashMap<String, SsrcConfig> getMediaServerSsrcMap() {
return mediaServerSsrcMap;
}
public void setMediaServerSsrcMap(HashMap<String, SsrcConfig> mediaServerSsrcMap) {
this.mediaServerSsrcMap = mediaServerSsrcMap;
}
}

535
src/main/java/com/genersoft/iot/vmp/conf/MediaServerConfig.java

@ -1,9 +1,7 @@
package com.genersoft.iot.vmp.conf;
import com.alibaba.fastjson.annotation.JSONField;
import lombok.Data;
@Data
public class MediaServerConfig {
@JSONField(name = "api.apiDebug")
@ -33,6 +31,10 @@ public class MediaServerConfig {
@JSONField(name = "general.streamNoneReaderDelayMS")
private String generalStreamNoneReaderDelayMS;
private String localIP;
private String wanIp;
@JSONField(name = "hls.fileBufSize")
private String hlsFileBufSize;
@ -197,4 +199,533 @@ public class MediaServerConfig {
@JSONField(name = "shell.shell")
private String shellPhell;
public String getApiDebug() {
return apiDebug;
}
public void setApiDebug(String apiDebug) {
this.apiDebug = apiDebug;
}
public String getApiSecret() {
return apiSecret;
}
public void setApiSecret(String apiSecret) {
this.apiSecret = apiSecret;
}
public String getFfmpegBin() {
return ffmpegBin;
}
public void setFfmpegBin(String ffmpegBin) {
this.ffmpegBin = ffmpegBin;
}
public String getFfmpegCmd() {
return ffmpegCmd;
}
public void setFfmpegCmd(String ffmpegCmd) {
this.ffmpegCmd = ffmpegCmd;
}
public String getFfmpegLog() {
return ffmpegLog;
}
public void setFfmpegLog(String ffmpegLog) {
this.ffmpegLog = ffmpegLog;
}
public String getGeneralEnableVhost() {
return generalEnableVhost;
}
public void setGeneralEnableVhost(String generalEnableVhost) {
this.generalEnableVhost = generalEnableVhost;
}
public String getGeneralFlowThreshold() {
return generalFlowThreshold;
}
public void setGeneralFlowThreshold(String generalFlowThreshold) {
this.generalFlowThreshold = generalFlowThreshold;
}
public String getGeneralMaxStreamWaitMS() {
return generalMaxStreamWaitMS;
}
public void setGeneralMaxStreamWaitMS(String generalMaxStreamWaitMS) {
this.generalMaxStreamWaitMS = generalMaxStreamWaitMS;
}
public String getGeneralStreamNoneReaderDelayMS() {
return generalStreamNoneReaderDelayMS;
}
public void setGeneralStreamNoneReaderDelayMS(String generalStreamNoneReaderDelayMS) {
this.generalStreamNoneReaderDelayMS = generalStreamNoneReaderDelayMS;
}
public String getLocalIP() {
return localIP;
}
public void setLocalIP(String localIP) {
this.localIP = localIP;
}
public String getHlsFileBufSize() {
return hlsFileBufSize;
}
public void setHlsFileBufSize(String hlsFileBufSize) {
this.hlsFileBufSize = hlsFileBufSize;
}
public String getHlsFilePath() {
return hlsFilePath;
}
public void setHlsFilePath(String hlsFilePath) {
this.hlsFilePath = hlsFilePath;
}
public String getHlsSegDur() {
return hlsSegDur;
}
public void setHlsSegDur(String hlsSegDur) {
this.hlsSegDur = hlsSegDur;
}
public String getHlsSegNum() {
return hlsSegNum;
}
public void setHlsSegNum(String hlsSegNum) {
this.hlsSegNum = hlsSegNum;
}
public String getHookAccessFileExceptHLS() {
return hookAccessFileExceptHLS;
}
public void setHookAccessFileExceptHLS(String hookAccessFileExceptHLS) {
this.hookAccessFileExceptHLS = hookAccessFileExceptHLS;
}
public String getHookAdminParams() {
return hookAdminParams;
}
public void setHookAdminParams(String hookAdminParams) {
this.hookAdminParams = hookAdminParams;
}
public String getHookEnable() {
return hookEnable;
}
public void setHookEnable(String hookEnable) {
this.hookEnable = hookEnable;
}
public String getHookOnFlowReport() {
return hookOnFlowReport;
}
public void setHookOnFlowReport(String hookOnFlowReport) {
this.hookOnFlowReport = hookOnFlowReport;
}
public String getHookOnHttpAccess() {
return hookOnHttpAccess;
}
public void setHookOnHttpAccess(String hookOnHttpAccess) {
this.hookOnHttpAccess = hookOnHttpAccess;
}
public String getHookOnPlay() {
return hookOnPlay;
}
public void setHookOnPlay(String hookOnPlay) {
this.hookOnPlay = hookOnPlay;
}
public String getHookOnPublish() {
return hookOnPublish;
}
public void setHookOnPublish(String hookOnPublish) {
this.hookOnPublish = hookOnPublish;
}
public String getHookOnRecordMp4() {
return hookOnRecordMp4;
}
public void setHookOnRecordMp4(String hookOnRecordMp4) {
this.hookOnRecordMp4 = hookOnRecordMp4;
}
public String getHookOnRtspAuth() {
return hookOnRtspAuth;
}
public void setHookOnRtspAuth(String hookOnRtspAuth) {
this.hookOnRtspAuth = hookOnRtspAuth;
}
public String getHookOnRtspRealm() {
return hookOnRtspRealm;
}
public void setHookOnRtspRealm(String hookOnRtspRealm) {
this.hookOnRtspRealm = hookOnRtspRealm;
}
public String getHookOnShellLogin() {
return hookOnShellLogin;
}
public void setHookOnShellLogin(String hookOnShellLogin) {
this.hookOnShellLogin = hookOnShellLogin;
}
public String getHookOnStreamChanged() {
return hookOnStreamChanged;
}
public void setHookOnStreamChanged(String hookOnStreamChanged) {
this.hookOnStreamChanged = hookOnStreamChanged;
}
public String getHookOnStreamNoneReader() {
return hookOnStreamNoneReader;
}
public void setHookOnStreamNoneReader(String hookOnStreamNoneReader) {
this.hookOnStreamNoneReader = hookOnStreamNoneReader;
}
public String getHookOnStreamNotFound() {
return hookOnStreamNotFound;
}
public void setHookOnStreamNotFound(String hookOnStreamNotFound) {
this.hookOnStreamNotFound = hookOnStreamNotFound;
}
public String getHookTimeoutSec() {
return hookTimeoutSec;
}
public void setHookTimeoutSec(String hookTimeoutSec) {
this.hookTimeoutSec = hookTimeoutSec;
}
public String getHttpCharSet() {
return httpCharSet;
}
public void setHttpCharSet(String httpCharSet) {
this.httpCharSet = httpCharSet;
}
public String getHttpKeepAliveSecond() {
return httpKeepAliveSecond;
}
public void setHttpKeepAliveSecond(String httpKeepAliveSecond) {
this.httpKeepAliveSecond = httpKeepAliveSecond;
}
public String getHttpMaxReqCount() {
return httpMaxReqCount;
}
public void setHttpMaxReqCount(String httpMaxReqCount) {
this.httpMaxReqCount = httpMaxReqCount;
}
public String getHttpMaxReqSize() {
return httpMaxReqSize;
}
public void setHttpMaxReqSize(String httpMaxReqSize) {
this.httpMaxReqSize = httpMaxReqSize;
}
public String getHttpNotFound() {
return httpNotFound;
}
public void setHttpNotFound(String httpNotFound) {
this.httpNotFound = httpNotFound;
}
public String getHttpPort() {
return httpPort;
}
public void setHttpPort(String httpPort) {
this.httpPort = httpPort;
}
public String getHttpRootPath() {
return httpRootPath;
}
public void setHttpRootPath(String httpRootPath) {
this.httpRootPath = httpRootPath;
}
public String getHttpSendBufSize() {
return httpSendBufSize;
}
public void setHttpSendBufSize(String httpSendBufSize) {
this.httpSendBufSize = httpSendBufSize;
}
public String getHttpSSLport() {
return httpSSLport;
}
public void setHttpSSLport(String httpSSLport) {
this.httpSSLport = httpSSLport;
}
public String getMulticastAddrMax() {
return multicastAddrMax;
}
public void setMulticastAddrMax(String multicastAddrMax) {
this.multicastAddrMax = multicastAddrMax;
}
public String getMulticastAddrMin() {
return multicastAddrMin;
}
public void setMulticastAddrMin(String multicastAddrMin) {
this.multicastAddrMin = multicastAddrMin;
}
public String getMulticastUdpTTL() {
return multicastUdpTTL;
}
public void setMulticastUdpTTL(String multicastUdpTTL) {
this.multicastUdpTTL = multicastUdpTTL;
}
public String getRecordAppName() {
return recordAppName;
}
public void setRecordAppName(String recordAppName) {
this.recordAppName = recordAppName;
}
public String getRecordFilePath() {
return recordFilePath;
}
public void setRecordFilePath(String recordFilePath) {
this.recordFilePath = recordFilePath;
}
public String getRecordFileSecond() {
return recordFileSecond;
}
public void setRecordFileSecond(String recordFileSecond) {
this.recordFileSecond = recordFileSecond;
}
public String getRecordFileSampleMS() {
return recordFileSampleMS;
}
public void setRecordFileSampleMS(String recordFileSampleMS) {
this.recordFileSampleMS = recordFileSampleMS;
}
public String getRtmpHandshakeSecond() {
return rtmpHandshakeSecond;
}
public void setRtmpHandshakeSecond(String rtmpHandshakeSecond) {
this.rtmpHandshakeSecond = rtmpHandshakeSecond;
}
public String getRtmpKeepAliveSecond() {
return rtmpKeepAliveSecond;
}
public void setRtmpKeepAliveSecond(String rtmpKeepAliveSecond) {
this.rtmpKeepAliveSecond = rtmpKeepAliveSecond;
}
public String getRtmpModifyStamp() {
return rtmpModifyStamp;
}
public void setRtmpModifyStamp(String rtmpModifyStamp) {
this.rtmpModifyStamp = rtmpModifyStamp;
}
public String getRtmpPort() {
return rtmpPort;
}
public void setRtmpPort(String rtmpPort) {
this.rtmpPort = rtmpPort;
}
public String getRtpAudioMtuSize() {
return rtpAudioMtuSize;
}
public void setRtpAudioMtuSize(String rtpAudioMtuSize) {
this.rtpAudioMtuSize = rtpAudioMtuSize;
}
public String getRtpClearCount() {
return rtpClearCount;
}
public void setRtpClearCount(String rtpClearCount) {
this.rtpClearCount = rtpClearCount;
}
public String getRtpCycleMS() {
return rtpCycleMS;
}
public void setRtpCycleMS(String rtpCycleMS) {
this.rtpCycleMS = rtpCycleMS;
}
public String getRtpMaxRtpCount() {
return rtpMaxRtpCount;
}
public void setRtpMaxRtpCount(String rtpMaxRtpCount) {
this.rtpMaxRtpCount = rtpMaxRtpCount;
}
public String getRtpVideoMtuSize() {
return rtpVideoMtuSize;
}
public void setRtpVideoMtuSize(String rtpVideoMtuSize) {
this.rtpVideoMtuSize = rtpVideoMtuSize;
}
public String getRtpProxyCheckSource() {
return rtpProxyCheckSource;
}
public void setRtpProxyCheckSource(String rtpProxyCheckSource) {
this.rtpProxyCheckSource = rtpProxyCheckSource;
}
public String getRtpProxyDumpDir() {
return rtpProxyDumpDir;
}
public void setRtpProxyDumpDir(String rtpProxyDumpDir) {
this.rtpProxyDumpDir = rtpProxyDumpDir;
}
public String getRtpProxyPort() {
return rtpProxyPort;
}
public void setRtpProxyPort(String rtpProxyPort) {
this.rtpProxyPort = rtpProxyPort;
}
public String getRtpProxyTimeoutSec() {
return rtpProxyTimeoutSec;
}
public void setRtpProxyTimeoutSec(String rtpProxyTimeoutSec) {
this.rtpProxyTimeoutSec = rtpProxyTimeoutSec;
}
public String getRtspAuthBasic() {
return rtspAuthBasic;
}
public void setRtspAuthBasic(String rtspAuthBasic) {
this.rtspAuthBasic = rtspAuthBasic;
}
public String getRtspHandshakeSecond() {
return rtspHandshakeSecond;
}
public void setRtspHandshakeSecond(String rtspHandshakeSecond) {
this.rtspHandshakeSecond = rtspHandshakeSecond;
}
public String getRtspKeepAliveSecond() {
return rtspKeepAliveSecond;
}
public void setRtspKeepAliveSecond(String rtspKeepAliveSecond) {
this.rtspKeepAliveSecond = rtspKeepAliveSecond;
}
public String getRtspPort() {
return rtspPort;
}
public void setRtspPort(String rtspPort) {
this.rtspPort = rtspPort;
}
public String getRtspSSlport() {
return rtspSSlport;
}
public void setRtspSSlport(String rtspSSlport) {
this.rtspSSlport = rtspSSlport;
}
public String getShellMaxReqSize() {
return shellMaxReqSize;
}
public void setShellMaxReqSize(String shellMaxReqSize) {
this.shellMaxReqSize = shellMaxReqSize;
}
public String getShellPhell() {
return shellPhell;
}
public void setShellPhell(String shellPhell) {
this.shellPhell = shellPhell;
}
public String getWanIp() {
return wanIp;
}
public void setWanIp(String wanIp) {
this.wanIp = wanIp;
}
}

16
src/main/java/com/genersoft/iot/vmp/conf/SsrcConfig.java

@ -1,7 +1,6 @@
package com.genersoft.iot.vmp.conf;
import com.genersoft.iot.vmp.utils.ConfigConst;
import lombok.Data;
import java.util.ArrayList;
import java.util.List;
@ -10,12 +9,11 @@ import java.util.Set;
/**
* 每一个zlm流媒体服务器都设置MAX_STRTEAM_COUNT个可用同步信源(SSRC)
*/
@Data
public class SsrcConfig {
/**
* zlm流媒体服务器IP
*/
String mediaServerIp;
private String mediaServerIp;
/**
* zlm流媒体服务器已用会话句柄
*/
@ -25,6 +23,18 @@ public class SsrcConfig {
*/
private List<String> notUsed;
public String getMediaServerIp() {
return mediaServerIp;
}
public List<String> getIsUsed() {
return isUsed;
}
public List<String> getNotUsed() {
return notUsed;
}
public void init(String mediaServerIp, Set<String> usedSet) {
this.mediaServerIp = mediaServerIp;
this.isUsed = new ArrayList<>();

72
src/main/java/com/genersoft/iot/vmp/gb28181/SipLayer.java

@ -153,42 +153,42 @@ public class SipLayer implements SipListener {
});
}
@Override
public void processResponse(ResponseEvent evt) {
Response response = evt.getResponse();
logger.debug(evt.getResponse().toString());
int status = response.getStatusCode();
if (((status >= 200) && (status < 300)) || status == 401) { // Success!
ISIPResponseProcessor processor = processorFactory.createResponseProcessor(evt);
try {
processor.process(evt, this, sipConfig);
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (evt.getResponse() != null && sipSubscribe.getOkSubscribesSize() > 0 ) {
CallIdHeader callIdHeader = (CallIdHeader)evt.getResponse().getHeader(CallIdHeader.NAME);
if (callIdHeader != null) {
SipSubscribe.Event subscribe = sipSubscribe.getOkSubscribe(callIdHeader.getCallId());
if (subscribe != null) {
subscribe.response(evt);
}
}
}
} else if ((status >= 100) && (status < 200)) {
// 增加其它无需回复的响应,如101、180等
} else {
logger.warn("接收到失败的response响应!status:" + status + ",message:" + response.getReasonPhrase()/* .getContent().toString()*/);
if (evt.getResponse() != null && sipSubscribe.getErrorSubscribesSize() > 0 ) {
CallIdHeader callIdHeader = (CallIdHeader)evt.getResponse().getHeader(CallIdHeader.NAME);
if (callIdHeader != null) {
SipSubscribe.Event subscribe = sipSubscribe.getErrorSubscribe(callIdHeader.getCallId());
if (subscribe != null) {
subscribe.response(evt);
}
}
}
}
@Override
public void processResponse(ResponseEvent evt) {
Response response = evt.getResponse();
logger.debug(evt.getResponse().toString());
int status = response.getStatusCode();
if (((status >= 200) && (status < 300)) || status == 401) { // Success!
ISIPResponseProcessor processor = processorFactory.createResponseProcessor(evt);
try {
processor.process(evt, this, sipConfig);
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (evt.getResponse() != null && sipSubscribe.getOkSubscribesSize() > 0) {
CallIdHeader callIdHeader = (CallIdHeader) evt.getResponse().getHeader(CallIdHeader.NAME);
if (callIdHeader != null) {
SipSubscribe.Event subscribe = sipSubscribe.getOkSubscribe(callIdHeader.getCallId());
if (subscribe != null) {
subscribe.response(evt);
}
}
}
} else if ((status >= 100) && (status < 200)) {
// 增加其它无需回复的响应,如101、180等
} else {
logger.warn("接收到失败的response响应!status:" + status + ",message:" + response.getReasonPhrase()/* .getContent().toString()*/);
if (evt.getResponse() != null && sipSubscribe.getErrorSubscribesSize() > 0) {
CallIdHeader callIdHeader = (CallIdHeader) evt.getResponse().getHeader(CallIdHeader.NAME);
if (callIdHeader != null) {
SipSubscribe.Event subscribe = sipSubscribe.getErrorSubscribe(callIdHeader.getCallId());
if (subscribe != null) {
subscribe.response(evt);
}
}
}
}
}

14
src/main/java/com/genersoft/iot/vmp/gb28181/session/VideoStreamSessionManager.java

@ -9,8 +9,9 @@ import com.genersoft.iot.vmp.conf.SsrcConfig;
import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import com.genersoft.iot.vmp.utils.redis.JedisUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@ -27,7 +28,6 @@ import java.util.concurrent.ConcurrentHashMap;
* @author: swwheihei
* @date: 2020年5月13日 下午4:03:02
*/
@Slf4j
@Component
public class VideoStreamSessionManager {
/**
@ -37,6 +37,8 @@ public class VideoStreamSessionManager {
private ConcurrentHashMap<String, ClientTransaction> sessionMap = new ConcurrentHashMap<>();
private String ssrcPrefix;
private final Logger logger = LoggerFactory.getLogger(VideoStreamSessionManager.class);
@Autowired
private SipConfig sipConfig;
@Autowired
@ -190,7 +192,7 @@ public class VideoStreamSessionManager {
public StreamInfo getPlayStreamInfo(String channelId) {
if (StringUtils.isBlank(channelId)) {
log.error("getPlayStreamInfo channelId can not be null!!!");
logger.error("getPlayStreamInfo channelId can not be null!!!");
return null;
}
return redisCatchStorage.queryPlayByChannel(channelId);
@ -198,7 +200,7 @@ public class VideoStreamSessionManager {
public StreamInfo getPlayBackStreamInfo(String channelId) {
if (StringUtils.isBlank(channelId)) {
log.error("getPlayBackStreamInfo channelId can not be null!!!");
logger.error("getPlayBackStreamInfo channelId can not be null!!!");
return null;
}
return redisCatchStorage.queryPlaybackByChannel(channelId);
@ -206,7 +208,7 @@ public class VideoStreamSessionManager {
public StreamInfo getStreamInfo(String channelId, String streamId) {
if (StringUtils.isBlank(channelId) || StringUtils.isBlank(streamId)) {
log.error("getStreamInfo channelId and streamId can not be null!!!");
logger.error("getStreamInfo channelId and streamId can not be null!!!");
return null;
}
StreamInfo streamInfo = getStreamInfo(channelId, streamId, PlayTypeEnum.PLAY);
@ -218,7 +220,7 @@ public class VideoStreamSessionManager {
private StreamInfo getStreamInfo(String channelId, String streamId, PlayTypeEnum playType) {
if (StringUtils.isBlank(channelId) || StringUtils.isBlank(streamId)) {
log.error("getStreamInfo channelId and streamId can not be null!!!");
logger.error("getStreamInfo channelId and streamId can not be null!!!");
return null;
}
// TODO channelId

372
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPProcessorFactory.java

@ -1,231 +1,219 @@
package com.genersoft.iot.vmp.gb28181.transmit;
import javax.sip.RequestEvent;
import javax.sip.ResponseEvent;
import javax.sip.SipProvider;
import javax.sip.header.CSeqHeader;
import javax.sip.message.Request;
import javax.sip.message.Response;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform;
import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import com.genersoft.iot.vmp.gb28181.transmit.response.impl.*;
import com.genersoft.iot.vmp.vmanager.service.IPlayService;
// import org.slf4j.Logger;
// import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import com.genersoft.iot.vmp.conf.SipConfig;
import com.genersoft.iot.vmp.gb28181.auth.RegisterLogicHandler;
import com.genersoft.iot.vmp.gb28181.event.DeviceOffLineDetector;
import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform;
import com.genersoft.iot.vmp.gb28181.transmit.request.ISIPRequestProcessor;
import com.genersoft.iot.vmp.gb28181.transmit.request.impl.AckRequestProcessor;
import com.genersoft.iot.vmp.gb28181.transmit.request.impl.ByeRequestProcessor;
import com.genersoft.iot.vmp.gb28181.transmit.request.impl.CancelRequestProcessor;
import com.genersoft.iot.vmp.gb28181.transmit.request.impl.InviteRequestProcessor;
import com.genersoft.iot.vmp.gb28181.transmit.request.impl.MessageRequestProcessor;
import com.genersoft.iot.vmp.gb28181.transmit.request.impl.NotifyRequestProcessor;
import com.genersoft.iot.vmp.gb28181.transmit.request.impl.OtherRequestProcessor;
import com.genersoft.iot.vmp.gb28181.transmit.request.impl.RegisterRequestProcessor;
import com.genersoft.iot.vmp.gb28181.transmit.request.impl.SubscribeRequestProcessor;
import com.genersoft.iot.vmp.gb28181.transmit.request.impl.*;
import com.genersoft.iot.vmp.gb28181.transmit.response.ISIPResponseProcessor;
import com.genersoft.iot.vmp.gb28181.transmit.response.impl.ByeResponseProcessor;
import com.genersoft.iot.vmp.gb28181.transmit.response.impl.CancelResponseProcessor;
import com.genersoft.iot.vmp.gb28181.transmit.response.impl.InviteResponseProcessor;
import com.genersoft.iot.vmp.gb28181.transmit.response.impl.OtherResponseProcessor;
import com.genersoft.iot.vmp.gb28181.transmit.response.impl.*;
import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
import com.genersoft.iot.vmp.utils.SpringBeanFactory;
import com.genersoft.iot.vmp.utils.redis.RedisUtil;
import com.genersoft.iot.vmp.vmanager.service.IPlayService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import javax.sip.RequestEvent;
import javax.sip.ResponseEvent;
import javax.sip.SipProvider;
import javax.sip.header.CSeqHeader;
import javax.sip.message.Request;
import javax.sip.message.Response;
/**
// import org.slf4j.Logger;
// import org.slf4j.LoggerFactory;
/**
* @Description: SIP信令处理分配
* @author: swwheihei
* @date: 2020年5月3日 下午4:24:37
* @date: 2020年5月3日 下午4:24:37
*/
@Component
public class SIPProcessorFactory {
// private final static Logger logger = LoggerFactory.getLogger(SIPProcessorFactory.class);
@Autowired
private SipConfig sipConfig;
@Autowired
private RegisterLogicHandler handler;
@Autowired
private IVideoManagerStorager storager;
@Autowired
private IRedisCatchStorage redisCatchStorage;
// private final static Logger logger = LoggerFactory.getLogger(SIPProcessorFactory.class);
@Autowired
private SipConfig sipConfig;
@Autowired
private RegisterLogicHandler handler;
@Autowired
private EventPublisher publisher;
@Autowired
private IVideoManagerStorager storager;
@Autowired
private SIPCommander cmder;
@Autowired
private IRedisCatchStorage redisCatchStorage;
@Autowired
private SIPCommanderFroPlatform cmderFroPlatform;
@Autowired
private EventPublisher publisher;
@Autowired
private RedisUtil redis;
@Autowired
private SIPCommander cmder;
@Autowired
private DeferredResultHolder deferredResultHolder;
@Autowired
private SIPCommanderFroPlatform cmderFroPlatform;
@Autowired
private DeviceOffLineDetector offLineDetector;
@Autowired
private RedisUtil redis;
@Autowired
private InviteResponseProcessor inviteResponseProcessor;
@Autowired
private DeferredResultHolder deferredResultHolder;
@Autowired
private ByeResponseProcessor byeResponseProcessor;
@Autowired
private DeviceOffLineDetector offLineDetector;
@Autowired
private CancelResponseProcessor cancelResponseProcessor;
@Autowired
private InviteResponseProcessor inviteResponseProcessor;
@Autowired
@Lazy
private RegisterResponseProcessor registerResponseProcessor;
@Autowired
private ByeResponseProcessor byeResponseProcessor;
@Autowired
private CancelResponseProcessor cancelResponseProcessor;
@Autowired
private OtherResponseProcessor otherResponseProcessor;
@Autowired
@Lazy
private RegisterResponseProcessor registerResponseProcessor;
@Autowired
private IPlayService playService;
@Autowired
private ZLMRTPServerFactory zlmrtpServerFactory;
@Autowired
private OtherResponseProcessor otherResponseProcessor;
@Autowired
private IPlayService playService;
// 注:这里使用注解会导致循环依赖注入,暂用springBean
private SipProvider tcpSipProvider;
// 注:这里使用注解会导致循环依赖注入,暂用springBean
private SipProvider udpSipProvider;
public ISIPRequestProcessor createRequestProcessor(RequestEvent evt) {
Request request = evt.getRequest();
String method = request.getMethod();
@Autowired
private ZLMRTPServerFactory zlmrtpServerFactory;
// 注:这里使用注解会导致循环依赖注入,暂用springBean
private SipProvider tcpSipProvider;
// 注:这里使用注解会导致循环依赖注入,暂用springBean
private SipProvider udpSipProvider;
public ISIPRequestProcessor createRequestProcessor(RequestEvent evt) {
Request request = evt.getRequest();
String method = request.getMethod();
// logger.info("接收到消息:"+request.getMethod());
// sipSubscribe.getSubscribe(evt.getServerTransaction().getBranchId()).response(evt);
if (Request.INVITE.equals(method)) {
InviteRequestProcessor processor = new InviteRequestProcessor();
processor.setRequestEvent(evt);
processor.setTcpSipProvider(getTcpSipProvider());
processor.setUdpSipProvider(getUdpSipProvider());
processor.setCmder(cmder);
processor.setCmderFroPlatform(cmderFroPlatform);
processor.setPlayService(playService);
processor.setStorager(storager);
processor.setRedisCatchStorage(redisCatchStorage);
processor.setZlmrtpServerFactory(zlmrtpServerFactory);
return processor;
} else if (Request.REGISTER.equals(method)) {
RegisterRequestProcessor processor = new RegisterRequestProcessor();
processor.setRequestEvent(evt);
processor.setTcpSipProvider(getTcpSipProvider());
processor.setUdpSipProvider(getUdpSipProvider());
processor.setHandler(handler);
processor.setPublisher(publisher);
processor.setSipConfig(sipConfig);
processor.setVideoManagerStorager(storager);
return processor;
} else if (Request.SUBSCRIBE.equals(method)) {
SubscribeRequestProcessor processor = new SubscribeRequestProcessor();
processor.setRequestEvent(evt);
return processor;
} else if (Request.ACK.equals(method)) {
AckRequestProcessor processor = new AckRequestProcessor();
processor.setRequestEvent(evt);
processor.setRedisCatchStorage(redisCatchStorage);
processor.setZlmrtpServerFactory(zlmrtpServerFactory);
return processor;
} else if (Request.BYE.equals(method)) {
ByeRequestProcessor processor = new ByeRequestProcessor();
processor.setRequestEvent(evt);
processor.setRedisCatchStorage(redisCatchStorage);
processor.setZlmrtpServerFactory(zlmrtpServerFactory);
processor.setSIPCommander(cmder);
return processor;
} else if (Request.CANCEL.equals(method)) {
CancelRequestProcessor processor = new CancelRequestProcessor();
processor.setRequestEvent(evt);
return processor;
} else if (Request.MESSAGE.equals(method)) {
MessageRequestProcessor processor = new MessageRequestProcessor();
processor.setRequestEvent(evt);
processor.setTcpSipProvider(getTcpSipProvider());
processor.setUdpSipProvider(getUdpSipProvider());
processor.setPublisher(publisher);
processor.setRedis(redis);
processor.setDeferredResultHolder(deferredResultHolder);
processor.setOffLineDetector(offLineDetector);
processor.setCmder(cmder);
processor.setCmderFroPlatform(cmderFroPlatform);
processor.setStorager(storager);
processor.setRedisCatchStorage(redisCatchStorage);
return processor;
} else if (Request.NOTIFY.equalsIgnoreCase(method)) {
NotifyRequestProcessor processor = new NotifyRequestProcessor();
processor.setRequestEvent(evt);
processor.setTcpSipProvider(getTcpSipProvider());
processor.setUdpSipProvider(getUdpSipProvider());
processor.setPublisher(publisher);
processor.setRedis(redis);
processor.setDeferredResultHolder(deferredResultHolder);
processor.setOffLineDetector(offLineDetector);
processor.setCmder(cmder);
processor.setStorager(storager);
processor.setRedisCatchStorage(redisCatchStorage);
return processor;
} else {
OtherRequestProcessor processor = new OtherRequestProcessor();
processor.setRequestEvent(evt);
return processor;
}
}
public ISIPResponseProcessor createResponseProcessor(ResponseEvent evt) {
Response response = evt.getResponse();
CSeqHeader cseqHeader = (CSeqHeader) response.getHeader(CSeqHeader.NAME);
String method = cseqHeader.getMethod();
if(Request.INVITE.equals(method)){
return inviteResponseProcessor;
} else if (Request.BYE.equals(method)) {
return byeResponseProcessor;
} else if (Request.CANCEL.equals(method)) {
return cancelResponseProcessor;
}else if (Request.REGISTER.equals(method)) {
return registerResponseProcessor;
} else {
return otherResponseProcessor;
}
}
private SipProvider getTcpSipProvider() {
if (tcpSipProvider == null) {
tcpSipProvider = (SipProvider) SpringBeanFactory.getBean("tcpSipProvider");
}
return tcpSipProvider;
}
private SipProvider getUdpSipProvider() {
if (udpSipProvider == null) {
udpSipProvider = (SipProvider) SpringBeanFactory.getBean("udpSipProvider");
}
return udpSipProvider;
}
if (Request.INVITE.equals(method)) {
InviteRequestProcessor processor = new InviteRequestProcessor();
processor.setRequestEvent(evt);
processor.setTcpSipProvider(getTcpSipProvider());
processor.setUdpSipProvider(getUdpSipProvider());
processor.setCmder(cmder);
processor.setCmderFroPlatform(cmderFroPlatform);
processor.setPlayService(playService);
processor.setStorager(storager);
processor.setRedisCatchStorage(redisCatchStorage);
processor.setZlmrtpServerFactory(zlmrtpServerFactory);
return processor;
} else if (Request.REGISTER.equals(method)) {
RegisterRequestProcessor processor = new RegisterRequestProcessor();
processor.setRequestEvent(evt);
processor.setTcpSipProvider(getTcpSipProvider());
processor.setUdpSipProvider(getUdpSipProvider());
processor.setHandler(handler);
processor.setPublisher(publisher);
processor.setSipConfig(sipConfig);
processor.setVideoManagerStorager(storager);
return processor;
} else if (Request.SUBSCRIBE.equals(method)) {
SubscribeRequestProcessor processor = new SubscribeRequestProcessor();
processor.setRequestEvent(evt);
return processor;
} else if (Request.ACK.equals(method)) {
AckRequestProcessor processor = new AckRequestProcessor();
processor.setRequestEvent(evt);
processor.setRedisCatchStorage(redisCatchStorage);
processor.setZlmrtpServerFactory(zlmrtpServerFactory);
return processor;
} else if (Request.BYE.equals(method)) {
ByeRequestProcessor processor = new ByeRequestProcessor();
processor.setRequestEvent(evt);
processor.setRedisCatchStorage(redisCatchStorage);
processor.setZlmrtpServerFactory(zlmrtpServerFactory);
processor.setSIPCommander(cmder);
return processor;
} else if (Request.CANCEL.equals(method)) {
CancelRequestProcessor processor = new CancelRequestProcessor();
processor.setRequestEvent(evt);
return processor;
} else if (Request.MESSAGE.equals(method)) {
MessageRequestProcessor processor = new MessageRequestProcessor();
processor.setRequestEvent(evt);
processor.setTcpSipProvider(getTcpSipProvider());
processor.setUdpSipProvider(getUdpSipProvider());
processor.setPublisher(publisher);
processor.setRedis(redis);
processor.setDeferredResultHolder(deferredResultHolder);
processor.setOffLineDetector(offLineDetector);
processor.setCmder(cmder);
processor.setCmderFroPlatform(cmderFroPlatform);
processor.setStorager(storager);
processor.setRedisCatchStorage(redisCatchStorage);
return processor;
} else if (Request.NOTIFY.equalsIgnoreCase(method)) {
NotifyRequestProcessor processor = new NotifyRequestProcessor();
processor.setRequestEvent(evt);
processor.setTcpSipProvider(getTcpSipProvider());
processor.setUdpSipProvider(getUdpSipProvider());
processor.setPublisher(publisher);
processor.setRedis(redis);
processor.setDeferredResultHolder(deferredResultHolder);
processor.setOffLineDetector(offLineDetector);
processor.setCmder(cmder);
processor.setStorager(storager);
processor.setRedisCatchStorage(redisCatchStorage);
return processor;
} else {
OtherRequestProcessor processor = new OtherRequestProcessor();
processor.setRequestEvent(evt);
return processor;
}
}
public ISIPResponseProcessor createResponseProcessor(ResponseEvent evt) {
Response response = evt.getResponse();
CSeqHeader cseqHeader = (CSeqHeader) response.getHeader(CSeqHeader.NAME);
String method = cseqHeader.getMethod();
if (Request.INVITE.equals(method)) {
return inviteResponseProcessor;
} else if (Request.BYE.equals(method)) {
return byeResponseProcessor;
} else if (Request.CANCEL.equals(method)) {
return cancelResponseProcessor;
} else if (Request.REGISTER.equals(method)) {
return registerResponseProcessor;
} else {
return otherResponseProcessor;
}
}
private SipProvider getTcpSipProvider() {
if (tcpSipProvider == null) {
tcpSipProvider = (SipProvider) SpringBeanFactory.getBean("tcpSipProvider");
}
return tcpSipProvider;
}
private SipProvider getUdpSipProvider() {
if (udpSipProvider == null) {
udpSipProvider = (SipProvider) SpringBeanFactory.getBean("udpSipProvider");
}
return udpSipProvider;
}
}

72
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/callback/DeferredResultHolder.java

@ -1,60 +1,60 @@
package com.genersoft.iot.vmp.gb28181.transmit.callback;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.async.DeferredResult;
/**
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* @Description: 异步请求处理
* @author: swwheihei
* @date: 2020年5月8日 下午7:59:05
* @date: 2020年5月8日 下午7:59:05
*/
@Component
public class DeferredResultHolder {
public static final String CALLBACK_CMD_DEVICESTATUS = "CALLBACK_DEVICESTATUS";
public static final String CALLBACK_CMD_DEVICEINFO = "CALLBACK_DEVICEINFO";
public static final String CALLBACK_CMD_DEVICECONTROL = "CALLBACK_DEVICECONTROL";
public static final String CALLBACK_CMD_DEVICECONFIG = "CALLBACK_DEVICECONFIG";
public static final String CALLBACK_CMD_CONFIGDOWNLOAD = "CALLBACK_CONFIGDOWNLOAD";
public static final String CALLBACK_CMD_CATALOG = "CALLBACK_CATALOG";
public static final String CALLBACK_CMD_RECORDINFO = "CALLBACK_RECORDINFO";
public static final String CALLBACK_CMD_DEVICESTATUS = "CALLBACK_DEVICESTATUS";
public static final String CALLBACK_CMD_DEVICEINFO = "CALLBACK_DEVICEINFO";
public static final String CALLBACK_CMD_DEVICECONTROL = "CALLBACK_DEVICECONTROL";
public static final String CALLBACK_CMD_DEVICECONFIG = "CALLBACK_DEVICECONFIG";
public static final String CALLBACK_CMD_CONFIGDOWNLOAD = "CALLBACK_CONFIGDOWNLOAD";
public static final String CALLBACK_CMD_CATALOG = "CALLBACK_CATALOG";
public static final String CALLBACK_CMD_RECORDINFO = "CALLBACK_RECORDINFO";
public static final String CALLBACK_CMD_PlAY = "CALLBACK_PLAY";
public static final String CALLBACK_CMD_PlAY = "CALLBACK_PLAY";
public static final String CALLBACK_CMD_STOP = "CALLBACK_STOP";
public static final String CALLBACK_CMD_STOP = "CALLBACK_STOP";
public static final String CALLBACK_CMD_MOBILEPOSITION = "CALLBACK_MOBILEPOSITION";
public static final String CALLBACK_CMD_MOBILEPOSITION = "CALLBACK_MOBILEPOSITION";
public static final String CALLBACK_CMD_PRESETQUERY = "CALLBACK_PRESETQUERY";
public static final String CALLBACK_CMD_PRESETQUERY = "CALLBACK_PRESETQUERY";
public static final String CALLBACK_CMD_ALARM = "CALLBACK_ALARM";
public static final String CALLBACK_CMD_ALARM = "CALLBACK_ALARM";
public static final String CALLBACK_CMD_BROADCAST = "CALLBACK_BROADCAST";
public static final String CALLBACK_CMD_BROADCAST = "CALLBACK_BROADCAST";
private Map<String, DeferredResult> map = new ConcurrentHashMap<String, DeferredResult>();
private Map<String, DeferredResult> map = new ConcurrentHashMap<String, DeferredResult>();
public void put(String key, DeferredResult result) {
map.put(key, result);
}
public void put(String key, DeferredResult result) {
map.put(key, result);
}
public void invokeResult(RequestMessage msg) {
public void invokeResult(RequestMessage msg) {
// DeferredResult result = map.get(msg.getId());
// 获取并移除
DeferredResult result = map.remove(msg.getId());
if (result == null) {
return;
}
result.setResult(new ResponseEntity<>(msg.getData(),HttpStatus.OK));
}
// 获取并移除
DeferredResult result = map.remove(msg.getId());
if (result == null) {
return;
}
result.setResult(new ResponseEntity<>(msg.getData(), HttpStatus.OK));
}
}

579
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java

@ -5,297 +5,300 @@ import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe;
/**
* @Description:设备能力接口用于定义设备的控制查询能力
/**
* @Description:设备能力接口用于定义设备的控制查询能力
* @author: swwheihei
* @date: 2020年5月3日 下午9:16:34
* @date: 2020年5月3日 下午9:16:34
*/
public interface ISIPCommander {
/**
* 云台方向放控制使用配置文件中的默认镜头移动速度
*
* @param device 控制设备
* @param channelId 预览通道
* @param leftRight 镜头左移右移 0:停止 1:左移 2:右移
* @param upDown 镜头上移下移 0:停止 1:上移 2:下移
* @param moveSpeed 镜头移动速度
*/
boolean ptzdirectCmd(Device device,String channelId,int leftRight, int upDown);
/**
* 云台方向放控制
*
* @param device 控制设备
* @param channelId 预览通道
* @param leftRight 镜头左移右移 0:停止 1:左移 2:右移
* @param upDown 镜头上移下移 0:停止 1:上移 2:下移
* @param moveSpeed 镜头移动速度
*/
boolean ptzdirectCmd(Device device,String channelId,int leftRight, int upDown, int moveSpeed);
/**
* 云台缩放控制使用配置文件中的默认镜头缩放速度
*
* @param device 控制设备
* @param channelId 预览通道
* @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大
*/
boolean ptzZoomCmd(Device device,String channelId,int inOut);
/**
* 云台缩放控制
*
* @param device 控制设备
* @param channelId 预览通道
* @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大
* @param zoomSpeed 镜头缩放速度
*/
boolean ptzZoomCmd(Device device,String channelId,int inOut, int moveSpeed);
/**
* 云台控制支持方向与缩放控制
*
* @param device 控制设备
* @param channelId 预览通道
* @param leftRight 镜头左移右移 0:停止 1:左移 2:右移
* @param upDown 镜头上移下移 0:停止 1:上移 2:下移
* @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大
* @param moveSpeed 镜头移动速度
* @param zoomSpeed 镜头缩放速度
*/
boolean ptzCmd(Device device,String channelId,int leftRight, int upDown, int inOut, int moveSpeed, int zoomSpeed);
/**
* 前端控制包括PTZ指令FI指令预置位指令巡航指令扫描指令和辅助开关指令
*
* @param device 控制设备
* @param channelId 预览通道
* @param cmdCode 指令码
* @param parameter1 数据1
* @param parameter2 数据2
* @param combineCode2 组合码2
*/
boolean frontEndCmd(Device device, String channelId, int cmdCode, int parameter1, int parameter2, int combineCode2);
/**
* 前端控制指令用于转发上级指令
* @param device 控制设备
* @param channelId 预览通道
* @param cmdString 前端控制指令串
*/
boolean fronEndCmd(Device device, String channelId, String cmdString);
/**
* 请求预览视频流
*
* @param device 视频设备
* @param channelId 预览通道
*/
void playStreamCmd(Device device, String channelId, ZLMHttpHookSubscribe.Event event, SipSubscribe.Event errorEvent);
/**
* 请求回放视频流
*
* @param device 视频设备
* @param channelId 预览通道
* @param startTime 开始时间,格式要求yyyy-MM-dd HH:mm:ss
* @param endTime 结束时间,格式要求yyyy-MM-dd HH:mm:ss
*/
void playbackStreamCmd(Device device, String channelId, String startTime, String endTime, ZLMHttpHookSubscribe.Event event, SipSubscribe.Event errorEvent);
/**
* 视频流停止
*
* @param streamInfo streamInfo
* @param okEvent okEvent
*/
void stopStreamByeCmd(StreamInfo streamInfo, SipSubscribe.Event okEvent);
/**
* 语音广播
*
* @param device 视频设备
* @param channelId 预览通道
*/
boolean audioBroadcastCmd(Device device,String channelId);
/**
* 语音广播
*
* @param device 视频设备
*/
void audioBroadcastCmd(Device device, SipSubscribe.Event okEvent);
boolean audioBroadcastCmd(Device device);
/**
* 音视频录像控制
*
* @param device 视频设备
* @param channelId 预览通道
* @param recordCmdStr 录像命令Record / StopRecord
*/
boolean recordCmd(Device device, String channelId, String recordCmdStr, SipSubscribe.Event errorEvent);
/**
* 远程启动控制命令
*
* @param device 视频设备
*/
boolean teleBootCmd(Device device);
/**
* 报警布防/撤防命令
*
* @param device 视频设备
* @param setGuard true: SetGuard, false: ResetGuard
*/
boolean guardCmd(Device device, String guardCmdStr, SipSubscribe.Event errorEvent);
/**
* 报警复位命令
*
* @param device 视频设备
* @param alarmMethod 报警方式可选
* @param alarmType 报警类型可选
*/
boolean alarmCmd(Device device, String alarmMethod, String alarmType, SipSubscribe.Event errorEvent);
/**
* 强制关键帧命令,设备收到此命令应立刻发送一个IDR帧
*
* @param device 视频设备
* @param channelId 预览通道
*/
boolean iFrameCmd(Device device, String channelId);
/**
* 看守位控制命令
*
* @param device 视频设备
* @param enabled 看守位使能1 = 开启0 = 关闭
* @param resetTime 自动归位时间间隔开启看守位时使用单位:(s)
* @param presetIndex 调用预置位编号开启看守位时使用取值范围0~255
*/
boolean homePositionCmd(Device device, String channelId, String enabled, String resetTime, String presetIndex, SipSubscribe.Event errorEvent);
/**
* 设备配置命令
*
* @param device 视频设备
*/
boolean deviceConfigCmd(Device device);
/**
* 设备配置命令basicParam
*
* @param device 视频设备
* @param channelId 通道编码可选
* @param name 设备/通道名称可选
* @param expiration 注册过期时间可选
* @param heartBeatInterval 心跳间隔时间可选
* @param heartBeatCount 心跳超时次数可选
*/
boolean deviceBasicConfigCmd(Device device, String channelId, String name, String expiration, String heartBeatInterval, String heartBeatCount, SipSubscribe.Event errorEvent);
/**
* 查询设备状态
*
* @param device 视频设备
*/
boolean deviceStatusQuery(Device device, SipSubscribe.Event errorEvent);
/**
* 查询设备信息
*
* @param device 视频设备
* @return
*/
boolean deviceInfoQuery(Device device);
/**
* 查询目录列表
*
* @param device 视频设备
*/
boolean catalogQuery(Device device, SipSubscribe.Event errorEvent);
/**
* 查询录像信息
*
* @param device 视频设备
* @param startTime 开始时间,格式要求yyyy-MM-dd HH:mm:ss
* @param endTime 结束时间,格式要求yyyy-MM-dd HH:mm:ss
*/
boolean recordInfoQuery(Device device, String channelId, String startTime, String endTime);
/**
* 查询报警信息
*
* @param device 视频设备
* @param startPriority 报警起始级别可选
* @param endPriority 报警终止级别可选
* @param alarmMethod 报警方式条件可选
* @param alarmType 报警类型
* @param startTime 报警发生起始时间可选
* @param endTime 报警发生终止时间可选
* @return true = 命令发送成功
*/
boolean alarmInfoQuery(Device device, String startPriority, String endPriority, String alarmMethod,
String alarmType, String startTime, String endTime, SipSubscribe.Event errorEvent);
/**
* 查询设备配置
*
* @param device 视频设备
* @param channelId 通道编码可选
* @param configType 配置类型
*/
boolean deviceConfigQuery(Device device, String channelId, String configType, SipSubscribe.Event errorEvent);
/**
* 查询设备预置位置
*
* @param device 视频设备
*/
boolean presetQuery(Device device, String channelId, SipSubscribe.Event errorEvent);
/**
* 查询移动设备位置数据
*
* @param device 视频设备
*/
boolean mobilePostitionQuery(Device device, SipSubscribe.Event errorEvent);
/**
* 订阅取消订阅移动位置
*
* @param device 视频设备
* @param expires 订阅超时时间=0时为取消订阅
* @param interval 上报时间间隔
* @return true = 命令发送成功
*/
boolean mobilePositionSubscribe(Device device, int expires, int interval);
/**
* 订阅取消订阅报警信息
* @param device 视频设备
* @param expires 订阅过期时间0 = 取消订阅
* @param startPriority 报警起始级别可选
* @param endPriority 报警终止级别可选
* @param alarmMethods 报警方式条件可选
* @param alarmType 报警类型
* @param startTime 报警发生起始时间可选
* @param endTime 报警发生终止时间可选
* @return true = 命令发送成功
*/
boolean alarmSubscribe(Device device, int expires, String startPriority, String endPriority, String alarmMethod, String alarmType, String startTime, String endTime);
/**
* 释放rtpserver
* @param device
* @param channelId
*/
/**
* 云台方向放控制使用配置文件中的默认镜头移动速度
*
* @param device 控制设备
* @param channelId 预览通道
* @param leftRight 镜头左移右移 0:停止 1:左移 2:右移
* @param upDown 镜头上移下移 0:停止 1:上移 2:下移
*/
boolean ptzdirectCmd(Device device, String channelId, int leftRight, int upDown);
/**
* 云台方向放控制
*
* @param device 控制设备
* @param channelId 预览通道
* @param leftRight 镜头左移右移 0:停止 1:左移 2:右移
* @param upDown 镜头上移下移 0:停止 1:上移 2:下移
* @param moveSpeed 镜头移动速度
*/
boolean ptzdirectCmd(Device device, String channelId, int leftRight, int upDown, int moveSpeed);
/**
* 云台缩放控制使用配置文件中的默认镜头缩放速度
*
* @param device 控制设备
* @param channelId 预览通道
* @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大
*/
boolean ptzZoomCmd(Device device, String channelId, int inOut);
/**
* 云台缩放控制
*
* @param device 控制设备
* @param channelId 预览通道
* @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大
* @param moveSpeed 镜头缩放速度
*/
boolean ptzZoomCmd(Device device, String channelId, int inOut, int moveSpeed);
/**
* 云台控制支持方向与缩放控制
*
* @param device 控制设备
* @param channelId 预览通道
* @param leftRight 镜头左移右移 0:停止 1:左移 2:右移
* @param upDown 镜头上移下移 0:停止 1:上移 2:下移
* @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大
* @param moveSpeed 镜头移动速度
* @param zoomSpeed 镜头缩放速度
*/
boolean ptzCmd(Device device, String channelId, int leftRight, int upDown, int inOut, int moveSpeed, int zoomSpeed);
/**
* 前端控制包括PTZ指令FI指令预置位指令巡航指令扫描指令和辅助开关指令
*
* @param device 控制设备
* @param channelId 预览通道
* @param cmdCode 指令码
* @param parameter1 数据1
* @param parameter2 数据2
* @param combineCode2 组合码2
*/
boolean frontEndCmd(Device device, String channelId, int cmdCode, int parameter1, int parameter2, int combineCode2);
/**
* 前端控制指令用于转发上级指令
*
* @param device 控制设备
* @param channelId 预览通道
* @param cmdString 前端控制指令串
*/
boolean fronEndCmd(Device device, String channelId, String cmdString);
/**
* 请求预览视频流
*
* @param device 视频设备
* @param channelId 预览通道
*/
void playStreamCmd(Device device, String channelId, ZLMHttpHookSubscribe.Event event, SipSubscribe.Event errorEvent);
/**
* 请求回放视频流
*
* @param device 视频设备
* @param channelId 预览通道
* @param startTime 开始时间,格式要求yyyy-MM-dd HH:mm:ss
* @param endTime 结束时间,格式要求yyyy-MM-dd HH:mm:ss
*/
void playbackStreamCmd(Device device, String channelId, String startTime, String endTime, ZLMHttpHookSubscribe.Event event, SipSubscribe.Event errorEvent);
/**
* 视频流停止
*
* @param streamInfo streamInfo
* @param okEvent okEvent
*/
void stopStreamByeCmd(StreamInfo streamInfo, SipSubscribe.Event okEvent);
/**
* 语音广播
*
* @param device 视频设备
* @param channelId 预览通道
*/
boolean audioBroadcastCmd(Device device, String channelId);
/**
* 语音广播
*
* @param device 视频设备
*/
void audioBroadcastCmd(Device device, SipSubscribe.Event okEvent);
boolean audioBroadcastCmd(Device device);
/**
* 音视频录像控制
*
* @param device 视频设备
* @param channelId 预览通道
* @param recordCmdStr 录像命令Record / StopRecord
*/
boolean recordCmd(Device device, String channelId, String recordCmdStr, SipSubscribe.Event errorEvent);
/**
* 远程启动控制命令
*
* @param device 视频设备
*/
boolean teleBootCmd(Device device);
/**
* 报警布防/撤防命令
*
* @param device 视频设备
* @param guardCmdStr true: SetGuard, false: ResetGuard
*/
boolean guardCmd(Device device, String guardCmdStr, SipSubscribe.Event errorEvent);
/**
* 报警复位命令
*
* @param device 视频设备
* @param alarmMethod 报警方式可选
* @param alarmType 报警类型可选
*/
boolean alarmCmd(Device device, String alarmMethod, String alarmType, SipSubscribe.Event errorEvent);
/**
* 强制关键帧命令,设备收到此命令应立刻发送一个IDR帧
*
* @param device 视频设备
* @param channelId 预览通道
*/
boolean iFrameCmd(Device device, String channelId);
/**
* 看守位控制命令
*
* @param device 视频设备
* @param enabled 看守位使能1 = 开启0 = 关闭
* @param resetTime 自动归位时间间隔开启看守位时使用单位:(s)
* @param presetIndex 调用预置位编号开启看守位时使用取值范围0~255
*/
boolean homePositionCmd(Device device, String channelId, String enabled, String resetTime, String presetIndex, SipSubscribe.Event errorEvent);
/**
* 设备配置命令
*
* @param device 视频设备
*/
boolean deviceConfigCmd(Device device);
/**
* 设备配置命令basicParam
*
* @param device 视频设备
* @param channelId 通道编码可选
* @param name 设备/通道名称可选
* @param expiration 注册过期时间可选
* @param heartBeatInterval 心跳间隔时间可选
* @param heartBeatCount 心跳超时次数可选
*/
boolean deviceBasicConfigCmd(Device device, String channelId, String name, String expiration, String heartBeatInterval, String heartBeatCount, SipSubscribe.Event errorEvent);
/**
* 查询设备状态
*
* @param device 视频设备
*/
boolean deviceStatusQuery(Device device, SipSubscribe.Event errorEvent);
/**
* 查询设备信息
*
* @param device 视频设备
* @return
*/
boolean deviceInfoQuery(Device device);
/**
* 查询目录列表
*
* @param device 视频设备
*/
boolean catalogQuery(Device device, SipSubscribe.Event errorEvent);
/**
* 查询录像信息
*
* @param device 视频设备
* @param startTime 开始时间,格式要求yyyy-MM-dd HH:mm:ss
* @param endTime 结束时间,格式要求yyyy-MM-dd HH:mm:ss
*/
boolean recordInfoQuery(Device device, String channelId, String startTime, String endTime);
/**
* 查询报警信息
*
* @param device 视频设备
* @param startPriority 报警起始级别可选
* @param endPriority 报警终止级别可选
* @param alarmMethod 报警方式条件可选
* @param alarmType 报警类型
* @param startTime 报警发生起始时间可选
* @param endTime 报警发生终止时间可选
* @return true = 命令发送成功
*/
boolean alarmInfoQuery(Device device, String startPriority, String endPriority, String alarmMethod,
String alarmType, String startTime, String endTime, SipSubscribe.Event errorEvent);
/**
* 查询设备配置
*
* @param device 视频设备
* @param channelId 通道编码可选
* @param configType 配置类型
*/
boolean deviceConfigQuery(Device device, String channelId, String configType, SipSubscribe.Event errorEvent);
/**
* 查询设备预置位置
*
* @param device 视频设备
*/
boolean presetQuery(Device device, String channelId, SipSubscribe.Event errorEvent);
/**
* 查询移动设备位置数据
*
* @param device 视频设备
*/
boolean mobilePostitionQuery(Device device, SipSubscribe.Event errorEvent);
/**
* 订阅取消订阅移动位置
*
* @param device 视频设备
* @param expires 订阅超时时间=0时为取消订阅
* @param interval 上报时间间隔
* @return true = 命令发送成功
*/
boolean mobilePositionSubscribe(Device device, int expires, int interval);
/**
* 订阅取消订阅报警信息
*
* @param device 视频设备
* @param expires 订阅过期时间0 = 取消订阅
* @param startPriority 报警起始级别可选
* @param endPriority 报警终止级别可选
* @param alarmMethod 报警方式条件可选
* @param alarmType 报警类型
* @param startTime 报警发生起始时间可选
* @param endTime 报警发生终止时间可选
* @return true = 命令发送成功
*/
boolean alarmSubscribe(Device device, int expires, String startPriority, String endPriority, String alarmMethod, String alarmType, String startTime, String endTime);
/**
* 释放rtpserver
*
* @param device
* @param channelId
*/
void closeRTPServer(Device device, String channelId);
}

330
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderProvider.java

@ -1,23 +1,19 @@
package com.genersoft.iot.vmp.gb28181.transmit.cmd;
import java.text.ParseException;
import java.util.ArrayList;
import com.genersoft.iot.vmp.conf.SipConfig;
import com.genersoft.iot.vmp.gb28181.bean.Device;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.sip.InvalidArgumentException;
import javax.sip.PeerUnavailableException;
import javax.sip.SipFactory;
// import javax.sip.SipProvider;
import javax.sip.address.Address;
import javax.sip.address.SipURI;
import javax.sip.header.*;
import javax.sip.message.Request;
import org.springframework.beans.factory.annotation.Autowired;
// import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
import com.genersoft.iot.vmp.conf.SipConfig;
import com.genersoft.iot.vmp.gb28181.bean.Device;
import java.text.ParseException;
import java.util.ArrayList;
/**
* @Description:摄像头命令request创造器 TODO 冗余代码太多待优化
@ -27,157 +23,165 @@ import com.genersoft.iot.vmp.gb28181.bean.Device;
@Component
public class SIPRequestHeaderProvider {
@Autowired
private SipConfig sipConfig;
@Autowired
private SipFactory sipFactory;
public Request createMessageRequest(Device device, String content, String viaTag, String fromTag, String toTag, CallIdHeader callIdHeader) throws ParseException, InvalidArgumentException, PeerUnavailableException {
Request request = null;
// sipuri
SipURI requestURI = sipFactory.createAddressFactory().createSipURI(device.getDeviceId(), device.getHostAddress());
// via
ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();
ViaHeader viaHeader = sipFactory.createHeaderFactory().createViaHeader(sipConfig.getSipIp(), sipConfig.getSipPort(),
device.getTransport(), viaTag);
viaHeader.setRPort();
viaHeaders.add(viaHeader);
// from
SipURI fromSipURI = sipFactory.createAddressFactory().createSipURI(sipConfig.getSipId(),
sipConfig.getSipIp() + ":" + sipConfig.getSipPort());
Address fromAddress = sipFactory.createAddressFactory().createAddress(fromSipURI);
FromHeader fromHeader = sipFactory.createHeaderFactory().createFromHeader(fromAddress, fromTag);
// to
SipURI toSipURI = sipFactory.createAddressFactory().createSipURI(device.getDeviceId(), sipConfig.getSipDomain());
Address toAddress = sipFactory.createAddressFactory().createAddress(toSipURI);
ToHeader toHeader = sipFactory.createHeaderFactory().createToHeader(toAddress, toTag);
// Forwards
MaxForwardsHeader maxForwards = sipFactory.createHeaderFactory().createMaxForwardsHeader(70);
// ceq
CSeqHeader cSeqHeader = sipFactory.createHeaderFactory().createCSeqHeader(1L, Request.MESSAGE);
request = sipFactory.createMessageFactory().createRequest(requestURI, Request.MESSAGE, callIdHeader, cSeqHeader, fromHeader,
toHeader, viaHeaders, maxForwards);
ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader("APPLICATION", "MANSCDP+xml");
request.setContent(content, contentTypeHeader);
return request;
}
public Request createInviteRequest(Device device, String channelId, String content, String viaTag, String fromTag, String toTag, String ssrc, CallIdHeader callIdHeader) throws ParseException, InvalidArgumentException, PeerUnavailableException {
Request request = null;
//请求行
SipURI requestLine = sipFactory.createAddressFactory().createSipURI(channelId, device.getHostAddress());
//via
ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();
ViaHeader viaHeader = sipFactory.createHeaderFactory().createViaHeader(device.getIp(), device.getPort(), device.getTransport(), viaTag);
viaHeader.setRPort();
viaHeaders.add(viaHeader);
//from
SipURI fromSipURI = sipFactory.createAddressFactory().createSipURI(sipConfig.getSipId(),sipConfig.getSipDomain());
Address fromAddress = sipFactory.createAddressFactory().createAddress(fromSipURI);
FromHeader fromHeader = sipFactory.createHeaderFactory().createFromHeader(fromAddress, fromTag); //必须要有标记,否则无法创建会话,无法回应ack
//to
SipURI toSipURI = sipFactory.createAddressFactory().createSipURI(channelId,sipConfig.getSipDomain());
Address toAddress = sipFactory.createAddressFactory().createAddress(toSipURI);
ToHeader toHeader = sipFactory.createHeaderFactory().createToHeader(toAddress,null);
//Forwards
MaxForwardsHeader maxForwards = sipFactory.createHeaderFactory().createMaxForwardsHeader(70);
//ceq
CSeqHeader cSeqHeader = sipFactory.createHeaderFactory().createCSeqHeader(1L, Request.INVITE);
request = sipFactory.createMessageFactory().createRequest(requestLine, Request.INVITE, callIdHeader, cSeqHeader,fromHeader, toHeader, viaHeaders, maxForwards);
Address concatAddress = sipFactory.createAddressFactory().createAddress(sipFactory.createAddressFactory().createSipURI(sipConfig.getSipId(), sipConfig.getSipIp()+":"+sipConfig.getSipPort()));
// Address concatAddress = sipFactory.createAddressFactory().createAddress(sipFactory.createAddressFactory().createSipURI(sipConfig.getSipId(), device.getHost().getIp()+":"+device.getHost().getPort()));
request.addHeader(sipFactory.createHeaderFactory().createContactHeader(concatAddress));
// Subject
SubjectHeader subjectHeader = sipFactory.createHeaderFactory().createSubjectHeader(String.format("%s:%s,%s:%s", channelId, ssrc, sipConfig.getSipId(), 0));
request.addHeader(subjectHeader);
ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader("APPLICATION", "SDP");
request.setContent(content, contentTypeHeader);
return request;
}
public Request createPlaybackInviteRequest(Device device, String channelId, String content, String viaTag, String fromTag, String toTag, CallIdHeader callIdHeader) throws ParseException, InvalidArgumentException, PeerUnavailableException {
Request request = null;
//请求行
SipURI requestLine = sipFactory.createAddressFactory().createSipURI(device.getDeviceId(), device.getHostAddress());
// via
ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();
ViaHeader viaHeader = sipFactory.createHeaderFactory().createViaHeader(device.getIp(), device.getPort(), device.getTransport(), viaTag);
viaHeader.setRPort();
viaHeaders.add(viaHeader);
//from
SipURI fromSipURI = sipFactory.createAddressFactory().createSipURI(sipConfig.getSipId(),sipConfig.getSipDomain());
Address fromAddress = sipFactory.createAddressFactory().createAddress(fromSipURI);
FromHeader fromHeader = sipFactory.createHeaderFactory().createFromHeader(fromAddress, fromTag); //必须要有标记,否则无法创建会话,无法回应ack
//to
SipURI toSipURI = sipFactory.createAddressFactory().createSipURI(channelId,sipConfig.getSipDomain());
Address toAddress = sipFactory.createAddressFactory().createAddress(toSipURI);
ToHeader toHeader = sipFactory.createHeaderFactory().createToHeader(toAddress,null);
//Forwards
MaxForwardsHeader maxForwards = sipFactory.createHeaderFactory().createMaxForwardsHeader(70);
//ceq
CSeqHeader cSeqHeader = sipFactory.createHeaderFactory().createCSeqHeader(1L, Request.INVITE);
request = sipFactory.createMessageFactory().createRequest(requestLine, Request.INVITE, callIdHeader, cSeqHeader,fromHeader, toHeader, viaHeaders, maxForwards);
Address concatAddress = sipFactory.createAddressFactory().createAddress(sipFactory.createAddressFactory().createSipURI(sipConfig.getSipId(), sipConfig.getSipIp()+":"+sipConfig.getSipPort()));
// Address concatAddress = sipFactory.createAddressFactory().createAddress(sipFactory.createAddressFactory().createSipURI(sipConfig.getSipId(), device.getHost().getIp()+":"+device.getHost().getPort()));
request.addHeader(sipFactory.createHeaderFactory().createContactHeader(concatAddress));
ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader("APPLICATION", "SDP");
request.setContent(content, contentTypeHeader);
return request;
}
public Request createSubscribeRequest(Device device, String content, String viaTag, String fromTag, String toTag, Integer expires, String event, CallIdHeader callIdHeader) throws ParseException, InvalidArgumentException, PeerUnavailableException {
Request request = null;
// sipuri
SipURI requestURI = sipFactory.createAddressFactory().createSipURI(device.getDeviceId(), device.getHostAddress());
// via
ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();
ViaHeader viaHeader = sipFactory.createHeaderFactory().createViaHeader(sipConfig.getSipIp(), sipConfig.getSipPort(),
device.getTransport(), viaTag);
viaHeader.setRPort();
viaHeaders.add(viaHeader);
// from
SipURI fromSipURI = sipFactory.createAddressFactory().createSipURI(sipConfig.getSipId(),
sipConfig.getSipIp() + ":" + sipConfig.getSipPort());
Address fromAddress = sipFactory.createAddressFactory().createAddress(fromSipURI);
FromHeader fromHeader = sipFactory.createHeaderFactory().createFromHeader(fromAddress, fromTag);
// to
SipURI toSipURI = sipFactory.createAddressFactory().createSipURI(device.getDeviceId(), sipConfig.getSipDomain());
Address toAddress = sipFactory.createAddressFactory().createAddress(toSipURI);
ToHeader toHeader = sipFactory.createHeaderFactory().createToHeader(toAddress, toTag);
// Forwards
MaxForwardsHeader maxForwards = sipFactory.createHeaderFactory().createMaxForwardsHeader(70);
// ceq
CSeqHeader cSeqHeader = sipFactory.createHeaderFactory().createCSeqHeader(1L, Request.SUBSCRIBE);
request = sipFactory.createMessageFactory().createRequest(requestURI, Request.SUBSCRIBE, callIdHeader, cSeqHeader, fromHeader,
toHeader, viaHeaders, maxForwards);
Address concatAddress = sipFactory.createAddressFactory().createAddress(sipFactory.createAddressFactory().createSipURI(sipConfig.getSipId(), sipConfig.getSipIp()+":"+sipConfig.getSipPort()));
request.addHeader(sipFactory.createHeaderFactory().createContactHeader(concatAddress));
// Expires
ExpiresHeader expireHeader = sipFactory.createHeaderFactory().createExpiresHeader(expires);
request.addHeader(expireHeader);
// Event
EventHeader eventHeader = sipFactory.createHeaderFactory().createEventHeader(event);
request.addHeader(eventHeader);
ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader("APPLICATION", "MANSCDP+xml");
request.setContent(content, contentTypeHeader);
return request;
}
@Autowired
private SipConfig sipConfig;
@Autowired
private SipFactory sipFactory;
public Request createMessageRequest(Device device, String content, String viaTag, String fromTag, String toTag, CallIdHeader callIdHeader) throws ParseException, InvalidArgumentException, PeerUnavailableException {
Request request = null;
// sipuri
SipURI requestURI = sipFactory.createAddressFactory().createSipURI(device.getDeviceId(), device.getHostAddress());
// via
ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();
ViaHeader viaHeader = sipFactory.createHeaderFactory().createViaHeader(sipConfig.getSipIp(), sipConfig.getSipPort(),
device.getTransport(), viaTag);
viaHeader.setRPort();
viaHeaders.add(viaHeader);
// from
SipURI fromSipURI = sipFactory.createAddressFactory().createSipURI(sipConfig.getSipId(),
sipConfig.getSipIp() + ":" + sipConfig.getSipPort());
Address fromAddress = sipFactory.createAddressFactory().createAddress(fromSipURI);
FromHeader fromHeader = sipFactory.createHeaderFactory().createFromHeader(fromAddress, fromTag);
// to
SipURI toSipURI = sipFactory.createAddressFactory().createSipURI(device.getDeviceId(), sipConfig.getSipDomain());
Address toAddress = sipFactory.createAddressFactory().createAddress(toSipURI);
ToHeader toHeader = sipFactory.createHeaderFactory().createToHeader(toAddress, toTag);
// Forwards
MaxForwardsHeader maxForwards = sipFactory.createHeaderFactory().createMaxForwardsHeader(70);
// ceq
CSeqHeader cSeqHeader = sipFactory.createHeaderFactory().createCSeqHeader(1L, Request.MESSAGE);
request = sipFactory.createMessageFactory().createRequest(requestURI, Request.MESSAGE, callIdHeader, cSeqHeader, fromHeader,
toHeader, viaHeaders, maxForwards);
ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader("APPLICATION", "MANSCDP+xml");
request.setContent(content, contentTypeHeader);
return request;
}
public Request createInviteRequest(Device device, String channelId, String content, String viaTag, String fromTag, String toTag, String ssrc, CallIdHeader callIdHeader) throws ParseException, InvalidArgumentException, PeerUnavailableException {
Request request = null;
//请求行
SipURI requestLine = sipFactory.createAddressFactory().createSipURI(channelId, device.getHostAddress());
//via
ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();
ViaHeader viaHeader = sipFactory.createHeaderFactory().createViaHeader(device.getIp(), device.getPort(), device.getTransport(), viaTag);
viaHeader.setRPort();
viaHeaders.add(viaHeader);
//from
SipURI fromSipURI = sipFactory.createAddressFactory().createSipURI(sipConfig.getSipId(), sipConfig.getSipDomain());
Address fromAddress = sipFactory.createAddressFactory().createAddress(fromSipURI);
FromHeader fromHeader = sipFactory.createHeaderFactory().createFromHeader(fromAddress, fromTag); //必须要有标记,否则无法创建会话,无法回应ack
//to
SipURI toSipURI = sipFactory.createAddressFactory().createSipURI(channelId, sipConfig.getSipDomain());
Address toAddress = sipFactory.createAddressFactory().createAddress(toSipURI);
ToHeader toHeader = sipFactory.createHeaderFactory().createToHeader(toAddress, null);
//Forwards
MaxForwardsHeader maxForwards = sipFactory.createHeaderFactory().createMaxForwardsHeader(70);
//ceq
CSeqHeader cSeqHeader = sipFactory.createHeaderFactory().createCSeqHeader(1L, Request.INVITE);
request = sipFactory.createMessageFactory().createRequest(requestLine, Request.INVITE, callIdHeader, cSeqHeader, fromHeader, toHeader, viaHeaders, maxForwards);
Address concatAddress = sipFactory.createAddressFactory().createAddress(sipFactory.createAddressFactory().createSipURI(sipConfig.getSipId(), sipConfig.getSipIp() + ":" + sipConfig.getSipPort()));
// Address concatAddress = sipFactory.createAddressFactory().createAddress(sipFactory.createAddressFactory().createSipURI(sipConfig.getSipId(), device.getHost().getIp()+":"+device.getHost().getPort()));
request.addHeader(sipFactory.createHeaderFactory().createContactHeader(concatAddress));
// Subject
SubjectHeader subjectHeader = sipFactory.createHeaderFactory().createSubjectHeader(String.format("%s:%s,%s:%s", channelId, ssrc, sipConfig.getSipId(), 0));
request.addHeader(subjectHeader);
ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader("APPLICATION", "SDP");
request.setContent(content, contentTypeHeader);
return request;
}
public Request createPlaybackInviteRequest(Device device, String channelId, String content, String viaTag, String fromTag, String toTag, CallIdHeader callIdHeader) throws ParseException, InvalidArgumentException, PeerUnavailableException {
Request request = null;
//请求行
SipURI requestLine = sipFactory.createAddressFactory().createSipURI(device.getDeviceId(), device.getHostAddress());
// via
ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();
ViaHeader viaHeader = sipFactory.createHeaderFactory().createViaHeader(device.getIp(), device.getPort(), device.getTransport(), viaTag);
viaHeader.setRPort();
viaHeaders.add(viaHeader);
//from
SipURI fromSipURI = sipFactory.createAddressFactory().createSipURI(sipConfig.getSipId(), sipConfig.getSipDomain());
Address fromAddress = sipFactory.createAddressFactory().createAddress(fromSipURI);
FromHeader fromHeader = sipFactory.createHeaderFactory().createFromHeader(fromAddress, fromTag); //必须要有标记,否则无法创建会话,无法回应ack
//to
SipURI toSipURI = sipFactory.createAddressFactory().createSipURI(channelId, sipConfig.getSipDomain());
Address toAddress = sipFactory.createAddressFactory().createAddress(toSipURI);
ToHeader toHeader = sipFactory.createHeaderFactory().createToHeader(toAddress, null);
//Forwards
MaxForwardsHeader maxForwards = sipFactory.createHeaderFactory().createMaxForwardsHeader(70);
//ceq
CSeqHeader cSeqHeader = sipFactory.createHeaderFactory().createCSeqHeader(1L, Request.INVITE);
request = sipFactory.createMessageFactory().createRequest(requestLine, Request.INVITE, callIdHeader, cSeqHeader, fromHeader, toHeader, viaHeaders, maxForwards);
Address concatAddress = sipFactory.createAddressFactory().createAddress(sipFactory.createAddressFactory().createSipURI(sipConfig.getSipId(), sipConfig.getSipIp() + ":" + sipConfig.getSipPort()));
// Address concatAddress = sipFactory.createAddressFactory().createAddress(sipFactory.createAddressFactory().createSipURI(sipConfig.getSipId(), device.getHost().getIp()+":"+device.getHost().getPort()));
request.addHeader(sipFactory.createHeaderFactory().createContactHeader(concatAddress));
ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader("APPLICATION", "SDP");
request.setContent(content, contentTypeHeader);
return request;
}
public Request createSubscribeRequest(Device device,
String content,
String viaTag,
String fromTag,
String toTag,
Integer expires,
String event,
CallIdHeader callIdHeader
) throws ParseException, InvalidArgumentException, PeerUnavailableException {
Request request = null;
// sipuri
SipURI requestURI = sipFactory.createAddressFactory().createSipURI(device.getDeviceId(), device.getHostAddress());
// via
ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();
ViaHeader viaHeader = sipFactory.createHeaderFactory().createViaHeader(sipConfig.getSipIp(), sipConfig.getSipPort(),
device.getTransport(), viaTag);
viaHeader.setRPort();
viaHeaders.add(viaHeader);
// from
SipURI fromSipURI = sipFactory.createAddressFactory().createSipURI(sipConfig.getSipId(),
sipConfig.getSipIp() + ":" + sipConfig.getSipPort());
Address fromAddress = sipFactory.createAddressFactory().createAddress(fromSipURI);
FromHeader fromHeader = sipFactory.createHeaderFactory().createFromHeader(fromAddress, fromTag);
// to
SipURI toSipURI = sipFactory.createAddressFactory().createSipURI(device.getDeviceId(), sipConfig.getSipDomain());
Address toAddress = sipFactory.createAddressFactory().createAddress(toSipURI);
ToHeader toHeader = sipFactory.createHeaderFactory().createToHeader(toAddress, toTag);
// Forwards
MaxForwardsHeader maxForwards = sipFactory.createHeaderFactory().createMaxForwardsHeader(70);
// ceq
CSeqHeader cSeqHeader = sipFactory.createHeaderFactory().createCSeqHeader(1L, Request.SUBSCRIBE);
request = sipFactory.createMessageFactory().createRequest(requestURI, Request.SUBSCRIBE, callIdHeader, cSeqHeader, fromHeader,
toHeader, viaHeaders, maxForwards);
Address concatAddress = sipFactory.createAddressFactory().createAddress(sipFactory.createAddressFactory().createSipURI(sipConfig.getSipId(), sipConfig.getSipIp() + ":" + sipConfig.getSipPort()));
request.addHeader(sipFactory.createHeaderFactory().createContactHeader(concatAddress));
// Expires
ExpiresHeader expireHeader = sipFactory.createHeaderFactory().createExpiresHeader(expires);
request.addHeader(expireHeader);
// Event
EventHeader eventHeader = sipFactory.createHeaderFactory().createEventHeader(event);
request.addHeader(eventHeader);
ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader("APPLICATION", "MANSCDP+xml");
request.setContent(content, contentTypeHeader);
return request;
}
}

1500
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java

File diff suppressed because it is too large

233
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/AckRequestProcessor.java

@ -1,113 +1,120 @@
package com.genersoft.iot.vmp.gb28181.transmit.request.impl;
import java.util.HashMap;
import java.util.Map;
import javax.sip.*;
import javax.sip.address.SipURI;
import javax.sip.header.FromHeader;
import javax.sip.header.HeaderAddress;
import javax.sip.header.ToHeader;
import com.genersoft.iot.vmp.common.StreamInfo;
import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
import com.genersoft.iot.vmp.gb28181.transmit.request.SIPRequestAbstractProcessor;
import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
/**
* @Description:ACK请求处理器
* @author: swwheihei
* @date: 2020年5月3日 下午5:31:45
*/
public class AckRequestProcessor extends SIPRequestAbstractProcessor {
private IRedisCatchStorage redisCatchStorage;
private ZLMRTPServerFactory zlmrtpServerFactory;
/**
* 处理 ACK请求
*
* @param evt
*/
@Override
public void process(RequestEvent evt) {
//Request request = evt.getRequest();
Dialog dialog = evt.getDialog();
if (dialog == null) return;
//DialogState state = dialog.getState();
if (/*request.getMecodewwthod().equals(Request.INVITE) &&*/ dialog.getState()== DialogState.CONFIRMED) {
String platformGbId = ((SipURI) ((HeaderAddress) evt.getRequest().getHeader(FromHeader.NAME)).getAddress().getURI()).getUser();
String channelId = ((SipURI) ((HeaderAddress) evt.getRequest().getHeader(ToHeader.NAME)).getAddress().getURI()).getUser();
SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(platformGbId, channelId);
String is_Udp = sendRtpItem.isTcp() ? "0" : "1";
String deviceId = sendRtpItem.getDeviceId();
StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(deviceId, channelId);
sendRtpItem.setStreamId(streamInfo.getStreamId());
redisCatchStorage.updateSendRTPSever(sendRtpItem);
System.out.println(platformGbId);
System.out.println(channelId);
Map<String, Object> param = new HashMap<>();
param.put("vhost","__defaultVhost__");
param.put("app","rtp");
param.put("stream",streamInfo.getStreamId());
param.put("ssrc", sendRtpItem.getSsrc());
param.put("dst_url",sendRtpItem.getIp());
param.put("dst_port", sendRtpItem.getPort());
param.put("is_udp", is_Udp);
//param.put ("src_port", sendRtpItem.getLocalPort());
// 设备推流查询,成功后才能转推
boolean rtpPushed = false;
long startTime = System.currentTimeMillis();
while (!rtpPushed) {
try {
if (System.currentTimeMillis() - startTime < 30 * 1000) {
if (zlmrtpServerFactory.isRtpReady(streamInfo.getStreamId())) {
rtpPushed = true;
System.out.println("已获取设备推流,开始向上级推流");
zlmrtpServerFactory.startSendRtpStream(param);
} else {
System.out.println("等待设备推流.......");
Thread.sleep(2000);
continue;
}
} else {
rtpPushed = true;
System.out.println("设备推流超时,终止向上级推流");
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
// 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();
// }
}
public IRedisCatchStorage getRedisCatchStorage() {
return redisCatchStorage;
}
public void setRedisCatchStorage(IRedisCatchStorage redisCatchStorage) {
this.redisCatchStorage = redisCatchStorage;
}
public ZLMRTPServerFactory getZlmrtpServerFactory() {
return zlmrtpServerFactory;
}
public void setZlmrtpServerFactory(ZLMRTPServerFactory zlmrtpServerFactory) {
this.zlmrtpServerFactory = zlmrtpServerFactory;
}
}
package com.genersoft.iot.vmp.gb28181.transmit.request.impl;
import java.util.HashMap;
import java.util.Map;
import javax.sip.*;
import javax.sip.address.SipURI;
import javax.sip.header.FromHeader;
import javax.sip.header.HeaderAddress;
import javax.sip.header.ToHeader;
import com.genersoft.iot.vmp.common.StreamInfo;
import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
import com.genersoft.iot.vmp.gb28181.transmit.request.SIPRequestAbstractProcessor;
import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import org.springframework.beans.factory.annotation.Autowired;
/**
* @Description:ACK请求处理器
* @author: swwheihei
* @date: 2020年5月3日 下午5:31:45
*/
public class AckRequestProcessor extends SIPRequestAbstractProcessor {
private IRedisCatchStorage redisCatchStorage;
private ZLMRTPServerFactory zlmrtpServerFactory;
@Autowired
private VideoStreamSessionManager streamSession;
/**
* 处理 ACK请求
*
* @param evt
*/
@Override
public void process(RequestEvent evt) {
//Request request = evt.getRequest();
Dialog dialog = evt.getDialog();
if (dialog == null) {
return;
}
//DialogState state = dialog.getState();
if (/*request.getMecodewwthod().equals(Request.INVITE) &&*/ dialog.getState()== DialogState.CONFIRMED) {
String platformGbId = ((SipURI) ((HeaderAddress) evt.getRequest().getHeader(FromHeader.NAME)).getAddress().getURI()).getUser();
String channelId = ((SipURI) ((HeaderAddress) evt.getRequest().getHeader(ToHeader.NAME)).getAddress().getURI()).getUser();
SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(platformGbId, channelId);
String is_Udp = sendRtpItem.isTcp() ? "0" : "1";
String deviceId = sendRtpItem.getDeviceId();
StreamInfo streamInfo = redisCatchStorage.queryPlayByChannel(channelId);
sendRtpItem.setStreamId(streamInfo.getStreamId());
redisCatchStorage.updateSendRTPSever(sendRtpItem);
System.out.println(platformGbId);
System.out.println(channelId);
Map<String, Object> param = new HashMap<>();
param.put("vhost","__defaultVhost__");
param.put("app","rtp");
param.put("stream",streamInfo.getStreamId());
param.put("ssrc", sendRtpItem.getSsrc());
param.put("dst_url",sendRtpItem.getIp());
param.put("dst_port", sendRtpItem.getPort());
param.put("is_udp", is_Udp);
//param.put ("src_port", sendRtpItem.getLocalPort());
// 设备推流查询,成功后才能转推
boolean rtpPushed = false;
long startTime = System.currentTimeMillis();
while (!rtpPushed) {
try {
if (System.currentTimeMillis() - startTime < 30 * 1000) {
if (zlmrtpServerFactory.isRtpReady(streamInfo.getStreamId())) {
rtpPushed = true;
System.out.println("已获取设备推流,开始向上级推流");
zlmrtpServerFactory.startSendRtpStream(param);
} else {
System.out.println("等待设备推流.......");
Thread.sleep(2000);
continue;
}
} else {
rtpPushed = true;
System.out.println("设备推流超时,终止向上级推流");
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
// 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();
// }
}
public IRedisCatchStorage getRedisCatchStorage() {
return redisCatchStorage;
}
public void setRedisCatchStorage(IRedisCatchStorage redisCatchStorage) {
this.redisCatchStorage = redisCatchStorage;
}
public ZLMRTPServerFactory getZlmrtpServerFactory() {
return zlmrtpServerFactory;
}
public void setZlmrtpServerFactory(ZLMRTPServerFactory zlmrtpServerFactory) {
this.zlmrtpServerFactory = zlmrtpServerFactory;
}
}

225
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/ByeRequestProcessor.java

@ -1,109 +1,116 @@
package com.genersoft.iot.vmp.gb28181.transmit.request.impl;
import javax.sip.address.SipURI;
import javax.sip.Dialog;
import javax.sip.DialogState;
import javax.sip.InvalidArgumentException;
import javax.sip.RequestEvent;
import javax.sip.SipException;
import javax.sip.header.FromHeader;
import javax.sip.header.HeaderAddress;
import javax.sip.header.ToHeader;
import javax.sip.message.Response;
import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander;
import com.genersoft.iot.vmp.gb28181.transmit.request.SIPRequestAbstractProcessor;
import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import java.text.ParseException;
import java.util.HashMap;
import java.util.Map;
/**
* @Description: BYE请求处理器
* @author: lawrencehj
* @date: 2021年3月9日
*/
public class ByeRequestProcessor extends SIPRequestAbstractProcessor {
private ISIPCommander cmder;
private IRedisCatchStorage redisCatchStorage;
private ZLMRTPServerFactory zlmrtpServerFactory;
/**
* 处理BYE请求
* @param evt
*/
@Override
public void process(RequestEvent evt) {
try {
responseAck(evt);
Dialog dialog = evt.getDialog();
if (dialog == null) return;
if (dialog.getState().equals(DialogState.TERMINATED)) {
String platformGbId = ((SipURI) ((HeaderAddress) evt.getRequest().getHeader(FromHeader.NAME)).getAddress().getURI()).getUser();
String channelId = ((SipURI) ((HeaderAddress) evt.getRequest().getHeader(ToHeader.NAME)).getAddress().getURI()).getUser();
SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(platformGbId, channelId);
String streamId = sendRtpItem.getStreamId();
Map<String, Object> param = new HashMap<>();
param.put("vhost","__defaultVhost__");
param.put("app","rtp");
param.put("stream",streamId);
System.out.println("停止向上级推流:" + streamId);
zlmrtpServerFactory.stopSendRtpStream(param);
redisCatchStorage.deleteSendRTPServer(platformGbId, channelId);
if (zlmrtpServerFactory.totalReaderCount(streamId) == 0) {
System.out.println(streamId + "无其它观看者,通知设备停止推流");
cmder.streamByeCmd(streamId);
}
}
} catch (SipException e) {
e.printStackTrace();
} catch (InvalidArgumentException e) {
e.printStackTrace();
} catch (ParseException e) {
e.printStackTrace();
}
}
/***
* 回复200 OK
* @param evt
* @throws SipException
* @throws InvalidArgumentException
* @throws ParseException
*/
private void responseAck(RequestEvent evt) throws SipException, InvalidArgumentException, ParseException {
Response response = getMessageFactory().createResponse(Response.OK, evt.getRequest());
getServerTransaction(evt).sendResponse(response);
}
public IRedisCatchStorage getRedisCatchStorage() {
return redisCatchStorage;
}
public void setRedisCatchStorage(IRedisCatchStorage redisCatchStorage) {
this.redisCatchStorage = redisCatchStorage;
}
public ZLMRTPServerFactory getZlmrtpServerFactory() {
return zlmrtpServerFactory;
}
public void setZlmrtpServerFactory(ZLMRTPServerFactory zlmrtpServerFactory) {
this.zlmrtpServerFactory = zlmrtpServerFactory;
}
public ISIPCommander getSIPCommander() {
return cmder;
}
public void setSIPCommander(ISIPCommander cmder) {
this.cmder = cmder;
}
}
package com.genersoft.iot.vmp.gb28181.transmit.request.impl;
import javax.sip.address.SipURI;
import javax.sip.Dialog;
import javax.sip.DialogState;
import javax.sip.InvalidArgumentException;
import javax.sip.RequestEvent;
import javax.sip.SipException;
import javax.sip.header.FromHeader;
import javax.sip.header.HeaderAddress;
import javax.sip.header.ToHeader;
import javax.sip.message.Response;
import com.genersoft.iot.vmp.common.StreamInfo;
import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander;
import com.genersoft.iot.vmp.gb28181.transmit.request.SIPRequestAbstractProcessor;
import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import org.springframework.beans.factory.annotation.Autowired;
import java.text.ParseException;
import java.util.HashMap;
import java.util.Map;
/**
* @Description: BYE请求处理器
* @author: lawrencehj
* @date: 2021年3月9日
*/
public class ByeRequestProcessor extends SIPRequestAbstractProcessor {
private ISIPCommander cmder;
private IRedisCatchStorage redisCatchStorage;
private ZLMRTPServerFactory zlmrtpServerFactory;
@Autowired
private VideoStreamSessionManager streamSession;
/**
* 处理BYE请求
* @param evt
*/
@Override
public void process(RequestEvent evt) {
try {
responseAck(evt);
Dialog dialog = evt.getDialog();
if (dialog == null) return;
if (dialog.getState().equals(DialogState.TERMINATED)) {
String platformGbId = ((SipURI) ((HeaderAddress) evt.getRequest().getHeader(FromHeader.NAME)).getAddress().getURI()).getUser();
String channelId = ((SipURI) ((HeaderAddress) evt.getRequest().getHeader(ToHeader.NAME)).getAddress().getURI()).getUser();
SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(platformGbId, channelId);
String streamId = sendRtpItem.getStreamId();
Map<String, Object> param = new HashMap<>();
param.put("vhost","__defaultVhost__");
param.put("app","rtp");
param.put("stream",streamId);
System.out.println("停止向上级推流:" + streamId);
StreamInfo streamInfo = streamSession.getStreamInfo(channelId, streamId);
zlmrtpServerFactory.stopSendRtpStream(param);
redisCatchStorage.deleteSendRTPServer(platformGbId, channelId);
if (zlmrtpServerFactory.totalReaderCount(streamId) == 0) {
System.out.println(streamId + "无其它观看者,通知设备停止推流");
cmder.stopStreamByeCmd(streamInfo, null);
}
}
} catch (SipException e) {
e.printStackTrace();
} catch (InvalidArgumentException e) {
e.printStackTrace();
} catch (ParseException e) {
e.printStackTrace();
}
}
/***
* 回复200 OK
* @param evt
* @throws SipException
* @throws InvalidArgumentException
* @throws ParseException
*/
private void responseAck(RequestEvent evt) throws SipException, InvalidArgumentException, ParseException {
Response response = getMessageFactory().createResponse(Response.OK, evt.getRequest());
getServerTransaction(evt).sendResponse(response);
}
public IRedisCatchStorage getRedisCatchStorage() {
return redisCatchStorage;
}
public void setRedisCatchStorage(IRedisCatchStorage redisCatchStorage) {
this.redisCatchStorage = redisCatchStorage;
}
public ZLMRTPServerFactory getZlmrtpServerFactory() {
return zlmrtpServerFactory;
}
public void setZlmrtpServerFactory(ZLMRTPServerFactory zlmrtpServerFactory) {
this.zlmrtpServerFactory = zlmrtpServerFactory;
}
public ISIPCommander getSIPCommander() {
return cmder;
}
public void setSIPCommander(ISIPCommander cmder) {
this.cmder = cmder;
}
}

761
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/InviteRequestProcessor.java

@ -1,384 +1,377 @@
package com.genersoft.iot.vmp.gb28181.transmit.request.impl;
import javax.sdp.*;
import javax.sip.InvalidArgumentException;
import javax.sip.RequestEvent;
import javax.sip.SipException;
import javax.sip.SipFactory;
import javax.sip.address.Address;
import javax.sip.address.SipURI;
import javax.sip.header.*;
import javax.sip.message.Request;
import javax.sip.message.Response;
import com.genersoft.iot.vmp.conf.MediaServerConfig;
import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform;
import com.genersoft.iot.vmp.gb28181.transmit.request.SIPRequestAbstractProcessor;
import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
import com.genersoft.iot.vmp.vmanager.play.bean.PlayResult;
import com.genersoft.iot.vmp.vmanager.service.IPlayService;
import gov.nist.javax.sip.address.AddressImpl;
import gov.nist.javax.sip.address.SipUri;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.text.ParseException;
import java.util.Vector;
/**
* @Description:处理INVITE请求
* @author: panll
* @date: 2021年1月14日
*/
@SuppressWarnings("rawtypes")
public class InviteRequestProcessor extends SIPRequestAbstractProcessor {
private final static Logger logger = LoggerFactory.getLogger(MessageRequestProcessor.class);
private SIPCommanderFroPlatform cmderFroPlatform;
private IVideoManagerStorager storager;
private IRedisCatchStorage redisCatchStorage;
private SIPCommander cmder;
private IPlayService playService;
private ZLMRTPServerFactory zlmrtpServerFactory;
public ZLMRTPServerFactory getZlmrtpServerFactory() {
return zlmrtpServerFactory;
}
public void setZlmrtpServerFactory(ZLMRTPServerFactory zlmrtpServerFactory) {
this.zlmrtpServerFactory = zlmrtpServerFactory;
}
/**
* 处理invite请求
*
* @param evt
* 请求消息
*/
@Override
public void process(RequestEvent evt) {
// Invite Request消息实现,此消息一般为级联消息,上级给下级发送请求视频指令
try {
Request request = evt.getRequest();
SipURI sipURI = (SipURI) request.getRequestURI();
String channelId = sipURI.getUser();
String requesterId = null;
FromHeader fromHeader = (FromHeader)request.getHeader(FromHeader.NAME);
AddressImpl address = (AddressImpl) fromHeader.getAddress();
SipUri uri = (SipUri) address.getURI();
requesterId = uri.getUser();
if (requesterId == null || channelId == null) {
logger.info("无法从FromHeader的Address中获取到平台id,返回400");
responseAck(evt, Response.BAD_REQUEST); // 参数不全, 发400,请求错误
return;
}
// 查询请求方是否上级平台
ParentPlatform platform = storager.queryParentPlatById(requesterId);
if (platform != null) {
// 查询平台下是否有该通道
DeviceChannel channel = storager.queryChannelInParentPlatform(requesterId, channelId);
if (channel == null) {
logger.info("通道不存在,返回404");
responseAck(evt, Response.NOT_FOUND); // 通道不存在,发404,资源不存在
return;
}else {
responseAck(evt, Response.CALL_IS_BEING_FORWARDED); // 通道存在,发181,呼叫转接中
}
// 解析sdp消息, 使用jainsip 自带的sdp解析方式
String contentString = new String(request.getRawContent());
// jainSip不支持y=字段, 移除移除以解析。
int ssrcIndex = contentString.indexOf("y=");
//ssrc规定长度为10字节,不取余下长度以避免后续还有“f=”字段
String ssrc = contentString.substring(ssrcIndex + 2, ssrcIndex + 12);
String substring = contentString.substring(0, contentString.indexOf("y="));
SessionDescription sdp = SdpFactory.getInstance().createSessionDescription(substring);
// 获取支持的格式
Vector mediaDescriptions = sdp.getMediaDescriptions(true);
// 查看是否支持PS 负载96
//String ip = null;
int port = -1;
//boolean recvonly = false;
boolean mediaTransmissionTCP = false;
Boolean tcpActive = null;
for (int i = 0; i < mediaDescriptions.size(); i++) {
MediaDescription mediaDescription = (MediaDescription)mediaDescriptions.get(i);
Media media = mediaDescription.getMedia();
Vector mediaFormats = media.getMediaFormats(false);
if (mediaFormats.contains("96")) {
port = media.getMediaPort();
//String mediaType = media.getMediaType();
String protocol = media.getProtocol();
// 区分TCP发流还是udp, 当前默认udp
if ("TCP/RTP/AVP".equals(protocol)) {
String setup = mediaDescription.getAttribute("setup");
if (setup != null) {
mediaTransmissionTCP = true;
if ("active".equals(setup)) {
tcpActive = true;
}else if ("passive".equals(setup)) {
tcpActive = false;
}
}
}
break;
}
}
if (port == -1) {
logger.info("不支持的媒体格式,返回415");
// 回复不支持的格式
responseAck(evt, Response.UNSUPPORTED_MEDIA_TYPE); // 不支持的格式,发415
return;
}
String username = sdp.getOrigin().getUsername();
String addressStr = sdp.getOrigin().getAddress();
//String sessionName = sdp.getSessionName().getValue();
logger.info("[上级点播]用户:{}, 地址:{}:{}, ssrc:{}", username, addressStr, port, ssrc);
Device device = storager.queryVideoDeviceByPlatformIdAndChannelId(requesterId, channelId);
if (device == null) {
logger.warn("点播平台{}的通道{}时未找到设备信息", requesterId, channel);
responseAck(evt, Response.SERVER_INTERNAL_ERROR);
return;
}
SendRtpItem sendRtpItem = zlmrtpServerFactory.createSendRtpItem(addressStr, port, ssrc, requesterId, device.getDeviceId(), channelId,
mediaTransmissionTCP);
if (tcpActive != null) {
sendRtpItem.setTcpActive(tcpActive);
}
if (sendRtpItem == null) {
logger.warn("服务器端口资源不足");
responseAck(evt, Response.BUSY_HERE);
return;
}
// 写入redis, 超时时回复
redisCatchStorage.updateSendRTPSever(sendRtpItem);
// 通知下级推流,
PlayResult playResult = playService.play(device.getDeviceId(), channelId, (responseJSON)->{
// 收到推流, 回复200OK, 等待ack
sendRtpItem.setStatus(1);
redisCatchStorage.updateSendRTPSever(sendRtpItem);
// TODO 添加对tcp的支持
MediaServerConfig mediaInfo = redisCatchStorage.getMediaInfo();
StringBuffer content = new StringBuffer(200);
content.append("v=0\r\n");
content.append("o="+"00000"+" 0 0 IN IP4 "+mediaInfo.getWanIp()+"\r\n");
content.append("s=Play\r\n");
content.append("c=IN IP4 "+mediaInfo.getWanIp()+"\r\n");
content.append("t=0 0\r\n");
content.append("m=video "+ sendRtpItem.getLocalPort()+" RTP/AVP 96\r\n");
content.append("a=sendonly\r\n");
content.append("a=rtpmap:96 PS/90000\r\n");
content.append("y="+ ssrc + "\r\n");
content.append("f=\r\n");
try {
responseAck(evt, content.toString());
} catch (SipException e) {
e.printStackTrace();
} catch (InvalidArgumentException e) {
e.printStackTrace();
} catch (ParseException e) {
e.printStackTrace();
}
},(event -> {
// 未知错误。直接转发设备点播的错误
Response response = null;
try {
response = getMessageFactory().createResponse(event.getResponse().getStatusCode(), evt.getRequest());
getServerTransaction(evt).sendResponse(response);
} catch (ParseException | SipException | InvalidArgumentException e) {
e.printStackTrace();
}
}));
if (logger.isDebugEnabled()) {
logger.debug(playResult.getResult().toString());
}
} else {
// 非上级平台请求,查询是否设备请求(通常为接收语音广播的设备)
Device device = storager.queryVideoDevice(requesterId);
if (device != null) {
logger.info("收到设备" + requesterId + "的语音广播Invite请求");
responseAck(evt, Response.TRYING);
String contentString = new String(request.getRawContent());
// jainSip不支持y=字段, 移除移除以解析。
String substring = contentString;
String ssrc = "0000000404";
int ssrcIndex = contentString.indexOf("y=");
if (ssrcIndex > 0) {
substring = contentString.substring(0, ssrcIndex);
ssrc = contentString.substring(ssrcIndex + 2, ssrcIndex + 12);
}
ssrcIndex = substring.indexOf("f=");
if (ssrcIndex > 0) {
substring = contentString.substring(0, ssrcIndex);
}
SessionDescription sdp = SdpFactory.getInstance().createSessionDescription(substring);
// 获取支持的格式
Vector mediaDescriptions = sdp.getMediaDescriptions(true);
// 查看是否支持PS 负载96
int port = -1;
//boolean recvonly = false;
boolean mediaTransmissionTCP = false;
Boolean tcpActive = null;
for (int i = 0; i < mediaDescriptions.size(); i++) {
MediaDescription mediaDescription = (MediaDescription)mediaDescriptions.get(i);
Media media = mediaDescription.getMedia();
Vector mediaFormats = media.getMediaFormats(false);
if (mediaFormats.contains("8")) {
port = media.getMediaPort();
String protocol = media.getProtocol();
// 区分TCP发流还是udp, 当前默认udp
if ("TCP/RTP/AVP".equals(protocol)) {
String setup = mediaDescription.getAttribute("setup");
if (setup != null) {
mediaTransmissionTCP = true;
if ("active".equals(setup)) {
tcpActive = true;
} else if ("passive".equals(setup)) {
tcpActive = false;
}
}
}
break;
}
}
if (port == -1) {
logger.info("不支持的媒体格式,返回415");
// 回复不支持的格式
responseAck(evt, Response.UNSUPPORTED_MEDIA_TYPE); // 不支持的格式,发415
return;
}
String username = sdp.getOrigin().getUsername();
String addressStr = sdp.getOrigin().getAddress();
logger.info("设备{}请求语音流,地址:{}:{},ssrc:{}", username, addressStr, port, ssrc);
} else {
logger.warn("来自无效设备/平台的请求");
responseAck(evt, Response.BAD_REQUEST);
}
}
} catch (SipException | InvalidArgumentException | ParseException e) {
e.printStackTrace();
logger.warn("sdp解析错误");
e.printStackTrace();
} catch (SdpParseException e) {
e.printStackTrace();
} catch (SdpException e) {
e.printStackTrace();
}
}
/***
* 回复状态码
* 100 trying
* 200 OK
* 400
* 404
* @param evt
* @throws SipException
* @throws InvalidArgumentException
* @throws ParseException
*/
private void responseAck(RequestEvent evt, int statusCode) throws SipException, InvalidArgumentException, ParseException {
Response response = getMessageFactory().createResponse(statusCode, evt.getRequest());
getServerTransaction(evt).sendResponse(response);
}
/**
* 回复带sdp的200
* @param evt
* @param sdp
* @throws SipException
* @throws InvalidArgumentException
* @throws ParseException
*/
private void responseAck(RequestEvent evt, String sdp) throws SipException, InvalidArgumentException, ParseException {
Response response = getMessageFactory().createResponse(Response.OK, evt.getRequest());
SipFactory sipFactory = SipFactory.getInstance();
ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader("APPLICATION", "SDP");
response.setContent(sdp, contentTypeHeader);
SipURI sipURI = (SipURI)evt.getRequest().getRequestURI();
Address concatAddress = sipFactory.createAddressFactory().createAddress(
sipFactory.createAddressFactory().createSipURI(sipURI.getUser(), sipURI.getHost()+":"+sipURI.getPort()
));
response.addHeader(sipFactory.createHeaderFactory().createContactHeader(concatAddress));
getServerTransaction(evt).sendResponse(response);
}
public SIPCommanderFroPlatform getCmderFroPlatform() {
return cmderFroPlatform;
}
public void setCmderFroPlatform(SIPCommanderFroPlatform cmderFroPlatform) {
this.cmderFroPlatform = cmderFroPlatform;
}
public IVideoManagerStorager getStorager() {
return storager;
}
public void setStorager(IVideoManagerStorager storager) {
this.storager = storager;
}
public SIPCommander getCmder() {
return cmder;
}
public void setCmder(SIPCommander cmder) {
this.cmder = cmder;
}
public IPlayService getPlayService() {
return playService;
}
public void setPlayService(IPlayService playService) {
this.playService = playService;
}
public IRedisCatchStorage getRedisCatchStorage() {
return redisCatchStorage;
}
public void setRedisCatchStorage(IRedisCatchStorage redisCatchStorage) {
this.redisCatchStorage = redisCatchStorage;
}
}
package com.genersoft.iot.vmp.gb28181.transmit.request.impl;
import com.genersoft.iot.vmp.conf.MediaServerConfig;
import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform;
import com.genersoft.iot.vmp.gb28181.transmit.request.SIPRequestAbstractProcessor;
import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
import com.genersoft.iot.vmp.vmanager.service.IPlayService;
import gov.nist.javax.sip.address.AddressImpl;
import gov.nist.javax.sip.address.SipUri;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.ResponseEntity;
import org.springframework.web.context.request.async.DeferredResult;
import javax.sdp.*;
import javax.sip.InvalidArgumentException;
import javax.sip.RequestEvent;
import javax.sip.SipException;
import javax.sip.SipFactory;
import javax.sip.address.Address;
import javax.sip.address.SipURI;
import javax.sip.header.ContentTypeHeader;
import javax.sip.header.FromHeader;
import javax.sip.message.Request;
import javax.sip.message.Response;
import java.text.ParseException;
import java.util.Vector;
/**
* @Description:处理INVITE请求
* @author: panll
* @date: 2021年1月14日
*/
@SuppressWarnings("rawtypes")
public class InviteRequestProcessor extends SIPRequestAbstractProcessor {
private final static Logger logger = LoggerFactory.getLogger(MessageRequestProcessor.class);
private SIPCommanderFroPlatform cmderFroPlatform;
private IVideoManagerStorager storager;
private IRedisCatchStorage redisCatchStorage;
private SIPCommander cmder;
private IPlayService playService;
private ZLMRTPServerFactory zlmrtpServerFactory;
public ZLMRTPServerFactory getZlmrtpServerFactory() {
return zlmrtpServerFactory;
}
public void setZlmrtpServerFactory(ZLMRTPServerFactory zlmrtpServerFactory) {
this.zlmrtpServerFactory = zlmrtpServerFactory;
}
/**
* 处理invite请求
*
* @param evt 请求消息
*/
@Override
public void process(RequestEvent evt) {
// Invite Request消息实现,此消息一般为级联消息,上级给下级发送请求视频指令
try {
Request request = evt.getRequest();
SipURI sipURI = (SipURI) request.getRequestURI();
String channelId = sipURI.getUser();
String requesterId = null;
FromHeader fromHeader = (FromHeader) request.getHeader(FromHeader.NAME);
AddressImpl address = (AddressImpl) fromHeader.getAddress();
SipUri uri = (SipUri) address.getURI();
requesterId = uri.getUser();
if (requesterId == null || channelId == null) {
logger.info("无法从FromHeader的Address中获取到平台id,返回400");
responseAck(evt, Response.BAD_REQUEST); // 参数不全, 发400,请求错误
return;
}
// 查询请求方是否上级平台
ParentPlatform platform = storager.queryParentPlatById(requesterId);
if (platform != null) {
// 查询平台下是否有该通道
DeviceChannel channel = storager.queryChannelInParentPlatform(requesterId, channelId);
if (channel == null) {
logger.info("通道不存在,返回404");
responseAck(evt, Response.NOT_FOUND); // 通道不存在,发404,资源不存在
return;
} else {
responseAck(evt, Response.CALL_IS_BEING_FORWARDED); // 通道存在,发181,呼叫转接中
}
// 解析sdp消息, 使用jainsip 自带的sdp解析方式
String contentString = new String(request.getRawContent());
// jainSip不支持y=字段, 移除移除以解析。
int ssrcIndex = contentString.indexOf("y=");
//ssrc规定长度为10字节,不取余下长度以避免后续还有“f=”字段
String ssrc = contentString.substring(ssrcIndex + 2, ssrcIndex + 12);
String substring = contentString.substring(0, contentString.indexOf("y="));
SessionDescription sdp = SdpFactory.getInstance().createSessionDescription(substring);
// 获取支持的格式
Vector mediaDescriptions = sdp.getMediaDescriptions(true);
// 查看是否支持PS 负载96
//String ip = null;
int port = -1;
//boolean recvonly = false;
boolean mediaTransmissionTCP = false;
Boolean tcpActive = null;
for (int i = 0; i < mediaDescriptions.size(); i++) {
MediaDescription mediaDescription = (MediaDescription) mediaDescriptions.get(i);
Media media = mediaDescription.getMedia();
Vector mediaFormats = media.getMediaFormats(false);
if (mediaFormats.contains("96")) {
port = media.getMediaPort();
//String mediaType = media.getMediaType();
String protocol = media.getProtocol();
// 区分TCP发流还是udp, 当前默认udp
if ("TCP/RTP/AVP".equals(protocol)) {
String setup = mediaDescription.getAttribute("setup");
if (setup != null) {
mediaTransmissionTCP = true;
if ("active".equals(setup)) {
tcpActive = true;
} else if ("passive".equals(setup)) {
tcpActive = false;
}
}
}
break;
}
}
if (port == -1) {
logger.info("不支持的媒体格式,返回415");
// 回复不支持的格式
responseAck(evt, Response.UNSUPPORTED_MEDIA_TYPE); // 不支持的格式,发415
return;
}
String username = sdp.getOrigin().getUsername();
String addressStr = sdp.getOrigin().getAddress();
//String sessionName = sdp.getSessionName().getValue();
logger.info("[上级点播]用户:{}, 地址:{}:{}, ssrc:{}", username, addressStr, port, ssrc);
Device device = storager.queryVideoDeviceByPlatformIdAndChannelId(requesterId, channelId);
if (device == null) {
logger.warn("点播平台{}的通道{}时未找到设备信息", requesterId, channel);
responseAck(evt, Response.SERVER_INTERNAL_ERROR);
return;
}
SendRtpItem sendRtpItem = zlmrtpServerFactory.createSendRtpItem(addressStr, port, ssrc, requesterId, device, channelId,
mediaTransmissionTCP);
if (tcpActive != null) {
sendRtpItem.setTcpActive(tcpActive);
}
if (sendRtpItem == null) {
logger.warn("服务器端口资源不足");
responseAck(evt, Response.BUSY_HERE);
return;
}
// 写入redis, 超时时回复
redisCatchStorage.updateSendRTPSever(sendRtpItem);
// 通知下级推流,
DeferredResult<ResponseEntity<String>> playResult = playService.play(device.getDeviceId(), channelId, (responseJSON) -> {
// 收到推流, 回复200OK, 等待ack
sendRtpItem.setStatus(1);
redisCatchStorage.updateSendRTPSever(sendRtpItem);
// TODO 添加对tcp的支持
MediaServerConfig mediaInfo = redisCatchStorage.getMediaInfo();
StringBuffer content = new StringBuffer(200);
content.append("v=0\r\n");
content.append("o=" + "00000" + " 0 0 IN IP4 " + mediaInfo.getWanIp() + "\r\n");
content.append("s=Play\r\n");
content.append("c=IN IP4 " + mediaInfo.getWanIp() + "\r\n");
content.append("t=0 0\r\n");
content.append("m=video " + sendRtpItem.getLocalPort() + " RTP/AVP 96\r\n");
content.append("a=sendonly\r\n");
content.append("a=rtpmap:96 PS/90000\r\n");
content.append("y=" + ssrc + "\r\n");
content.append("f=\r\n");
try {
responseAck(evt, content.toString());
} catch (SipException e) {
e.printStackTrace();
} catch (InvalidArgumentException e) {
e.printStackTrace();
} catch (ParseException e) {
e.printStackTrace();
}
}, (event -> {
// 未知错误。直接转发设备点播的错误
Response response = null;
try {
response = getMessageFactory().createResponse(event.getResponse().getStatusCode(), evt.getRequest());
getServerTransaction(evt).sendResponse(response);
} catch (ParseException | SipException | InvalidArgumentException e) {
e.printStackTrace();
}
}));
if (logger.isDebugEnabled()) {
logger.debug(playResult.getResult().toString());
}
} else {
// 非上级平台请求,查询是否设备请求(通常为接收语音广播的设备)
Device device = storager.queryVideoDevice(requesterId);
if (device != null) {
logger.info("收到设备" + requesterId + "的语音广播Invite请求");
responseAck(evt, Response.TRYING);
String contentString = new String(request.getRawContent());
// jainSip不支持y=字段, 移除移除以解析。
String substring = contentString;
String ssrc = "0000000404";
int ssrcIndex = contentString.indexOf("y=");
if (ssrcIndex > 0) {
substring = contentString.substring(0, ssrcIndex);
ssrc = contentString.substring(ssrcIndex + 2, ssrcIndex + 12);
}
ssrcIndex = substring.indexOf("f=");
if (ssrcIndex > 0) {
substring = contentString.substring(0, ssrcIndex);
}
SessionDescription sdp = SdpFactory.getInstance().createSessionDescription(substring);
// 获取支持的格式
Vector mediaDescriptions = sdp.getMediaDescriptions(true);
// 查看是否支持PS 负载96
int port = -1;
//boolean recvonly = false;
boolean mediaTransmissionTCP = false;
Boolean tcpActive = null;
for (int i = 0; i < mediaDescriptions.size(); i++) {
MediaDescription mediaDescription = (MediaDescription) mediaDescriptions.get(i);
Media media = mediaDescription.getMedia();
Vector mediaFormats = media.getMediaFormats(false);
if (mediaFormats.contains("8")) {
port = media.getMediaPort();
String protocol = media.getProtocol();
// 区分TCP发流还是udp, 当前默认udp
if ("TCP/RTP/AVP".equals(protocol)) {
String setup = mediaDescription.getAttribute("setup");
if (setup != null) {
mediaTransmissionTCP = true;
if ("active".equals(setup)) {
tcpActive = true;
} else if ("passive".equals(setup)) {
tcpActive = false;
}
}
}
break;
}
}
if (port == -1) {
logger.info("不支持的媒体格式,返回415");
// 回复不支持的格式
responseAck(evt, Response.UNSUPPORTED_MEDIA_TYPE); // 不支持的格式,发415
return;
}
String username = sdp.getOrigin().getUsername();
String addressStr = sdp.getOrigin().getAddress();
logger.info("设备{}请求语音流,地址:{}:{},ssrc:{}", username, addressStr, port, ssrc);
} else {
logger.warn("来自无效设备/平台的请求");
responseAck(evt, Response.BAD_REQUEST);
}
}
} catch (SipException | InvalidArgumentException | ParseException e) {
e.printStackTrace();
logger.warn("sdp解析错误");
e.printStackTrace();
} catch (SdpParseException e) {
e.printStackTrace();
} catch (SdpException e) {
e.printStackTrace();
}
}
/***
* 回复状态码
* 100 trying
* 200 OK
* 400
* 404
* @param evt
* @throws SipException
* @throws InvalidArgumentException
* @throws ParseException
*/
private void responseAck(RequestEvent evt, int statusCode) throws SipException, InvalidArgumentException, ParseException {
Response response = getMessageFactory().createResponse(statusCode, evt.getRequest());
getServerTransaction(evt).sendResponse(response);
}
/**
* 回复带sdp的200
*
* @param evt
* @param sdp
* @throws SipException
* @throws InvalidArgumentException
* @throws ParseException
*/
private void responseAck(RequestEvent evt, String sdp) throws SipException, InvalidArgumentException, ParseException {
Response response = getMessageFactory().createResponse(Response.OK, evt.getRequest());
SipFactory sipFactory = SipFactory.getInstance();
ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader("APPLICATION", "SDP");
response.setContent(sdp, contentTypeHeader);
SipURI sipURI = (SipURI) evt.getRequest().getRequestURI();
Address concatAddress = sipFactory.createAddressFactory().createAddress(
sipFactory.createAddressFactory().createSipURI(sipURI.getUser(), sipURI.getHost() + ":" + sipURI.getPort()
));
response.addHeader(sipFactory.createHeaderFactory().createContactHeader(concatAddress));
getServerTransaction(evt).sendResponse(response);
}
public SIPCommanderFroPlatform getCmderFroPlatform() {
return cmderFroPlatform;
}
public void setCmderFroPlatform(SIPCommanderFroPlatform cmderFroPlatform) {
this.cmderFroPlatform = cmderFroPlatform;
}
public IVideoManagerStorager getStorager() {
return storager;
}
public void setStorager(IVideoManagerStorager storager) {
this.storager = storager;
}
public SIPCommander getCmder() {
return cmder;
}
public void setCmder(SIPCommander cmder) {
this.cmder = cmder;
}
public IPlayService getPlayService() {
return playService;
}
public void setPlayService(IPlayService playService) {
this.playService = playService;
}
public IRedisCatchStorage getRedisCatchStorage() {
return redisCatchStorage;
}
public void setRedisCatchStorage(IRedisCatchStorage redisCatchStorage) {
this.redisCatchStorage = redisCatchStorage;
}
}

799
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/MessageRequestProcessor.java

@ -1,23 +1,5 @@
package com.genersoft.iot.vmp.gb28181.transmit.request.impl;
import java.io.ByteArrayInputStream;
import java.text.ParseException;
import java.util.*;
import javax.sip.address.SipURI;
import javax.sip.header.FromHeader;
import javax.sip.header.HeaderAddress;
import javax.sip.header.ToHeader;
import javax.sip.InvalidArgumentException;
import javax.sip.ListeningPoint;
import javax.sip.ObjectInUseException;
import javax.sip.RequestEvent;
import javax.sip.SipException;
import javax.sip.SipProvider;
import javax.sip.message.Request;
import javax.sip.message.Response;
import com.alibaba.fastjson.JSONObject;
import com.genersoft.iot.vmp.VManageBootstrap;
import com.genersoft.iot.vmp.common.StreamInfo;
@ -26,7 +8,6 @@ import com.genersoft.iot.vmp.conf.UserSetup;
import com.genersoft.iot.vmp.gb28181.bean.*;
import com.genersoft.iot.vmp.gb28181.event.DeviceOffLineDetector;
import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
import com.genersoft.iot.vmp.gb28181.transmit.callback.CheckForAllRecordsThread;
import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
@ -42,11 +23,9 @@ import com.genersoft.iot.vmp.utils.GpsUtil;
import com.genersoft.iot.vmp.utils.SpringBeanFactory;
import com.genersoft.iot.vmp.utils.redis.RedisUtil;
import com.genersoft.iot.vmp.vmanager.platform.bean.ChannelReduce;
import gov.nist.javax.sip.SipStackImpl;
import gov.nist.javax.sip.address.AddressImpl;
import gov.nist.javax.sip.address.SipUri;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
@ -55,9 +34,11 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;
import javax.sip.InvalidArgumentException;
import javax.sip.RequestEvent;
import javax.sip.SipException;
import javax.sip.*;
import javax.sip.address.SipURI;
import javax.sip.header.FromHeader;
import javax.sip.header.HeaderAddress;
import javax.sip.header.ToHeader;
import javax.sip.message.Request;
import javax.sip.message.Response;
import java.io.ByteArrayInputStream;
@ -84,14 +65,10 @@ public class MessageRequestProcessor extends SIPRequestAbstractProcessor {
private SIPCommander cmder;
private IVideoManagerStorager storager;
private SIPCommanderFroPlatform cmderFroPlatform;
private IVideoManagerStorager storager;
private SIPCommanderFroPlatform cmderFroPlatform;
private IRedisCatchStorage redisCatchStorage;
private VideoStreamSessionManager streamSession;
private EventPublisher publisher;
private RedisUtil redis;
@ -167,7 +144,7 @@ public class MessageRequestProcessor extends SIPRequestAbstractProcessor {
responseAck(evt);
}
} catch (DocumentException | SipException | InvalidArgumentException | ParseException e) {
log.error("MessageRequestProcessor.process error!", e);
logger.error("MessageRequestProcessor.process error!", e);
}
}
@ -279,83 +256,83 @@ public class MessageRequestProcessor extends SIPRequestAbstractProcessor {
}
}
/**
* 处理DeviceControl设备状态Message
*
* @param evt
*/
private void processMessageDeviceControl(RequestEvent evt) {
try {
Element rootElement = getRootElement(evt);
String deviceId = XmlUtil.getText(rootElement, "DeviceID");
//String result = XmlUtil.getText(rootElement, "Result");
// 回复200 OK
responseAck(evt);
if (rootElement.getName().equals("Response")) {//} !XmlUtil.isEmpty(result)) {
// 此处是对本平台发出DeviceControl指令的应答
JSONObject json = new JSONObject();
XmlUtil.node2Json(rootElement, json);
if (logger.isDebugEnabled()) {
logger.debug(json.toJSONString());
}
RequestMessage msg = new RequestMessage();
msg.setDeviceId(deviceId);
msg.setType(DeferredResultHolder.CALLBACK_CMD_DEVICECONTROL);
msg.setData(json);
deferredResultHolder.invokeResult(msg);
} else {
// 此处是上级发出的DeviceControl指令
String platformId = ((SipURI) ((HeaderAddress) evt.getRequest().getHeader(FromHeader.NAME)).getAddress().getURI()).getUser();
String targetGBId = ((SipURI) ((HeaderAddress) evt.getRequest().getHeader(ToHeader.NAME)).getAddress().getURI()).getUser();
// 远程启动功能
if (!XmlUtil.isEmpty(XmlUtil.getText(rootElement, "TeleBoot"))) {
if (deviceId.equals(targetGBId)) {
// 远程启动本平台:需要在重新启动程序后先对SipStack解绑
logger.info("执行远程启动本平台命令");
ParentPlatform parentPlatform = storager.queryParentPlatById(platformId);
cmderFroPlatform.unregister(parentPlatform, null, null);
Thread restartThread = new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(3000);
SipProvider up = (SipProvider) SpringBeanFactory.getBean("udpSipProvider");
SipStackImpl stack = (SipStackImpl)up.getSipStack();
stack.stop();
Iterator listener = stack.getListeningPoints();
while (listener.hasNext()) {
stack.deleteListeningPoint((ListeningPoint) listener.next());
}
Iterator providers = stack.getSipProviders();
while (providers.hasNext()) {
stack.deleteSipProvider((SipProvider) providers.next());
}
VManageBootstrap.restart();
} catch (InterruptedException ignored) {
} catch (ObjectInUseException e) {
e.printStackTrace();
}
}
});
restartThread.setDaemon(false);
restartThread.start();
} else {
// 远程启动指定设备
}
}
// 云台/前端控制命令
if (!XmlUtil.isEmpty(XmlUtil.getText(rootElement,"PTZCmd")) && !deviceId.equals(targetGBId)) {
String cmdString = XmlUtil.getText(rootElement,"PTZCmd");
Device device = storager.queryVideoDeviceByPlatformIdAndChannelId(platformId, deviceId);
cmder.fronEndCmd(device, deviceId, cmdString);
}
}
} catch (ParseException | SipException | InvalidArgumentException | DocumentException e) {
e.printStackTrace();
}
}
/**
* 处理DeviceControl设备状态Message
*
* @param evt
*/
private void processMessageDeviceControl(RequestEvent evt) {
try {
Element rootElement = getRootElement(evt);
String deviceId = XmlUtil.getText(rootElement, "DeviceID");
//String result = XmlUtil.getText(rootElement, "Result");
// 回复200 OK
responseAck(evt);
if (rootElement.getName().equals("Response")) {//} !XmlUtil.isEmpty(result)) {
// 此处是对本平台发出DeviceControl指令的应答
JSONObject json = new JSONObject();
XmlUtil.node2Json(rootElement, json);
if (logger.isDebugEnabled()) {
logger.debug(json.toJSONString());
}
RequestMessage msg = new RequestMessage();
msg.setDeviceId(deviceId);
msg.setType(DeferredResultHolder.CALLBACK_CMD_DEVICECONTROL);
msg.setData(json);
deferredResultHolder.invokeResult(msg);
} else {
// 此处是上级发出的DeviceControl指令
String platformId = ((SipURI) ((HeaderAddress) evt.getRequest().getHeader(FromHeader.NAME)).getAddress().getURI()).getUser();
String targetGBId = ((SipURI) ((HeaderAddress) evt.getRequest().getHeader(ToHeader.NAME)).getAddress().getURI()).getUser();
// 远程启动功能
if (!XmlUtil.isEmpty(XmlUtil.getText(rootElement, "TeleBoot"))) {
if (deviceId.equals(targetGBId)) {
// 远程启动本平台:需要在重新启动程序后先对SipStack解绑
logger.info("执行远程启动本平台命令");
ParentPlatform parentPlatform = storager.queryParentPlatById(platformId);
cmderFroPlatform.unregister(parentPlatform, null, null);
Thread restartThread = new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(3000);
SipProvider up = (SipProvider) SpringBeanFactory.getBean("udpSipProvider");
SipStackImpl stack = (SipStackImpl) up.getSipStack();
stack.stop();
Iterator listener = stack.getListeningPoints();
while (listener.hasNext()) {
stack.deleteListeningPoint((ListeningPoint) listener.next());
}
Iterator providers = stack.getSipProviders();
while (providers.hasNext()) {
stack.deleteSipProvider((SipProvider) providers.next());
}
VManageBootstrap.restart();
} catch (InterruptedException ignored) {
} catch (ObjectInUseException e) {
e.printStackTrace();
}
}
});
restartThread.setDaemon(false);
restartThread.start();
} else {
// 远程启动指定设备
}
}
// 云台/前端控制命令
if (!XmlUtil.isEmpty(XmlUtil.getText(rootElement, "PTZCmd")) && !deviceId.equals(targetGBId)) {
String cmdString = XmlUtil.getText(rootElement, "PTZCmd");
Device device = storager.queryVideoDeviceByPlatformIdAndChannelId(platformId, deviceId);
cmder.fronEndCmd(device, deviceId, cmdString);
}
}
} catch (ParseException | SipException | InvalidArgumentException | DocumentException e) {
e.printStackTrace();
}
}
/**
* 处理DeviceConfig设备状态Message
@ -450,224 +427,224 @@ public class MessageRequestProcessor extends SIPRequestAbstractProcessor {
}
}
/**
* 处理DeviceInfo设备信息Message
*
* @param evt
*/
private void processMessageDeviceInfo(RequestEvent evt) {
try {
Element rootElement = getRootElement(evt);
String requestName = rootElement.getName();
Element deviceIdElement = rootElement.element("DeviceID");
String deviceId = deviceIdElement.getTextTrim().toString();
if (requestName.equals("Query")) {
logger.info("接收到DeviceInfo查询消息");
FromHeader fromHeader = (FromHeader) evt.getRequest().getHeader(FromHeader.NAME);
String platformId = ((SipUri) fromHeader.getAddress().getURI()).getUser();
if (platformId == null) {
response404Ack(evt);
return;
} else {
// 回复200 OK
responseAck(evt);
String sn = rootElement.element("SN").getText();
ParentPlatform parentPlatform = storager.queryParentPlatById(platformId);
cmderFroPlatform.deviceInfoResponse(parentPlatform, sn, fromHeader.getTag());
}
} else {
logger.info("接收到DeviceInfo应答消息");
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"));
if (StringUtils.isEmpty(device.getStreamMode())) {
device.setStreamMode("UDP");
}
storager.updateDevice(device);
RequestMessage msg = new RequestMessage();
msg.setDeviceId(deviceId);
msg.setType(DeferredResultHolder.CALLBACK_CMD_DEVICEINFO);
msg.setData(device);
deferredResultHolder.invokeResult(msg);
// 回复200 OK
responseAck(evt);
if (offLineDetector.isOnline(deviceId)) {
publisher.onlineEventPublish(deviceId, VideoManagerConstants.EVENT_ONLINE_KEEPLIVE);
}
}
} catch (DocumentException | SipException | InvalidArgumentException | ParseException e) {
e.printStackTrace();
}
}
/***
* 收到catalog设备目录列表请求 处理
*
* @param evt
*/
private void processMessageCatalogList(RequestEvent evt) {
try {
Element rootElement = getRootElement(evt);
String name = rootElement.getName();
Element deviceIdElement = rootElement.element("DeviceID");
String deviceId = deviceIdElement.getText();
Element deviceListElement = rootElement.element("DeviceList");
FromHeader fromHeader = (FromHeader) evt.getRequest().getHeader(FromHeader.NAME);
AddressImpl address = (AddressImpl) fromHeader.getAddress();
SipUri uri = (SipUri) address.getURI();
String platformId = uri.getUser();
// if (deviceListElement == null) { // 存在DeviceList则为响应 catalog, 不存在DeviceList则为查询请求
if (name.equalsIgnoreCase("Query")) { // 区分是Response——查询响应,还是Query——查询请求
// TODO 后续将代码拆分
ParentPlatform parentPlatform = storager.queryParentPlatById(platformId);
if (parentPlatform == null) {
response404Ack(evt);
return;
} else {
// 回复200 OK
responseAck(evt);
Element snElement = rootElement.element("SN");
String sn = snElement.getText();
// 准备回复通道信息
List<ChannelReduce> channelReduces = storager.queryChannelListInParentPlatform(parentPlatform.getServerGBId());
if (channelReduces.size() > 0) {
for (ChannelReduce channelReduce : channelReduces) {
DeviceChannel deviceChannel = storager.queryChannel(channelReduce.getDeviceId(), channelReduce.getChannelId());
cmderFroPlatform.catalogQuery(deviceChannel, parentPlatform, sn, fromHeader.getTag(), channelReduces.size());
}
}
}
} else {
Iterator<Element> deviceListIterator = deviceListElement.elementIterator();
if (deviceListIterator != null) {
Device device = storager.queryVideoDevice(deviceId);
if (device == null) {
return;
}
// 遍历DeviceList
while (deviceListIterator.hasNext()) {
Element itemDevice = deviceListIterator.next();
Element channelDeviceElement = itemDevice.element("DeviceID");
if (channelDeviceElement == null) {
continue;
}
String channelDeviceId = channelDeviceElement.getText();
Element channdelNameElement = itemDevice.element("Name");
String channelName = channdelNameElement != null ? channdelNameElement.getTextTrim().toString() : "";
Element statusElement = itemDevice.element("Status");
String status = statusElement != null ? statusElement.getText().toString() : "ON";
DeviceChannel deviceChannel = new DeviceChannel();
deviceChannel.setName(channelName);
deviceChannel.setChannelId(channelDeviceId);
// ONLINE OFFLINE HIKVISION DS-7716N-E4 NVR的兼容性处理
if (status.equals("ON") || status.equals("On") || status.equals("ONLINE")) {
deviceChannel.setStatus(1);
}
if (status.equals("OFF") || status.equals("Off") || status.equals("OFFLINE")) {
deviceChannel.setStatus(0);
}
deviceChannel.setManufacture(XmlUtil.getText(itemDevice, "Manufacturer"));
deviceChannel.setModel(XmlUtil.getText(itemDevice, "Model"));
deviceChannel.setOwner(XmlUtil.getText(itemDevice, "Owner"));
deviceChannel.setCivilCode(XmlUtil.getText(itemDevice, "CivilCode"));
deviceChannel.setBlock(XmlUtil.getText(itemDevice, "Block"));
deviceChannel.setAddress(XmlUtil.getText(itemDevice, "Address"));
if (XmlUtil.getText(itemDevice, "Parental") == null || XmlUtil.getText(itemDevice, "Parental") == "") {
deviceChannel.setParental(0);
} else {
deviceChannel.setParental(Integer.parseInt(XmlUtil.getText(itemDevice, "Parental")));
}
deviceChannel.setParentId(XmlUtil.getText(itemDevice, "ParentID"));
if (XmlUtil.getText(itemDevice, "SafetyWay") == null || XmlUtil.getText(itemDevice, "SafetyWay") == "") {
deviceChannel.setSafetyWay(0);
} else {
deviceChannel.setSafetyWay(Integer.parseInt(XmlUtil.getText(itemDevice, "SafetyWay")));
}
if (XmlUtil.getText(itemDevice, "RegisterWay") == null || XmlUtil.getText(itemDevice, "RegisterWay") == "") {
deviceChannel.setRegisterWay(1);
} else {
deviceChannel.setRegisterWay(Integer.parseInt(XmlUtil.getText(itemDevice, "RegisterWay")));
}
deviceChannel.setCertNum(XmlUtil.getText(itemDevice, "CertNum"));
if (XmlUtil.getText(itemDevice, "Certifiable") == null || XmlUtil.getText(itemDevice, "Certifiable") == "") {
deviceChannel.setCertifiable(0);
} else {
deviceChannel.setCertifiable(Integer.parseInt(XmlUtil.getText(itemDevice, "Certifiable")));
}
if (XmlUtil.getText(itemDevice, "ErrCode") == null || XmlUtil.getText(itemDevice, "ErrCode") == "") {
deviceChannel.setErrCode(0);
} else {
deviceChannel.setErrCode(Integer.parseInt(XmlUtil.getText(itemDevice, "ErrCode")));
}
deviceChannel.setEndTime(XmlUtil.getText(itemDevice, "EndTime"));
deviceChannel.setSecrecy(XmlUtil.getText(itemDevice, "Secrecy"));
deviceChannel.setIpAddress(XmlUtil.getText(itemDevice, "IPAddress"));
if (XmlUtil.getText(itemDevice, "Port") == null || XmlUtil.getText(itemDevice, "Port") == "") {
deviceChannel.setPort(0);
} else {
deviceChannel.setPort(Integer.parseInt(XmlUtil.getText(itemDevice, "Port")));
}
deviceChannel.setPassword(XmlUtil.getText(itemDevice, "Password"));
if (NumericUtil.isDouble(XmlUtil.getText(itemDevice, "Longitude"))) {
deviceChannel.setLongitude(Double.parseDouble(XmlUtil.getText(itemDevice, "Longitude")));
} else {
deviceChannel.setLongitude(0.00);
}
if (NumericUtil.isDouble(XmlUtil.getText(itemDevice, "Latitude"))) {
deviceChannel.setLatitude(Double.parseDouble(XmlUtil.getText(itemDevice, "Latitude")));
} else {
deviceChannel.setLatitude(0.00);
}
if (XmlUtil.getText(itemDevice, "PTZType") == null || XmlUtil.getText(itemDevice, "PTZType") == "") {
deviceChannel.setPTZType(0);
} else {
deviceChannel.setPTZType(Integer.parseInt(XmlUtil.getText(itemDevice, "PTZType")));
}
deviceChannel.setHasAudio(true); // 默认含有音频,播放时再检查是否有音频及是否AAC
storager.updateChannel(device.getDeviceId(), deviceChannel);
}
RequestMessage msg = new RequestMessage();
msg.setDeviceId(deviceId);
msg.setType(DeferredResultHolder.CALLBACK_CMD_CATALOG);
msg.setData(device);
deferredResultHolder.invokeResult(msg);
// 回复200 OK
responseAck(evt);
if (offLineDetector.isOnline(deviceId)) {
publisher.onlineEventPublish(deviceId, VideoManagerConstants.EVENT_ONLINE_KEEPLIVE);
}
}
}
} catch (DocumentException | SipException | InvalidArgumentException | ParseException e) {
e.printStackTrace();
}
}
/***
* 收到alarm设备报警信息 处理
*
* @param evt
*/
private void processMessageAlarm(RequestEvent evt) {
try {
Element rootElement = getRootElement(evt);
Element deviceIdElement = rootElement.element("DeviceID");
String deviceId = deviceIdElement.getText().toString();
// 回复200 OK
responseAck(evt);
/**
* 处理DeviceInfo设备信息Message
*
* @param evt
*/
private void processMessageDeviceInfo(RequestEvent evt) {
try {
Element rootElement = getRootElement(evt);
String requestName = rootElement.getName();
Element deviceIdElement = rootElement.element("DeviceID");
String deviceId = deviceIdElement.getTextTrim().toString();
if (requestName.equals("Query")) {
logger.info("接收到DeviceInfo查询消息");
FromHeader fromHeader = (FromHeader) evt.getRequest().getHeader(FromHeader.NAME);
String platformId = ((SipUri) fromHeader.getAddress().getURI()).getUser();
if (platformId == null) {
response404Ack(evt);
return;
} else {
// 回复200 OK
responseAck(evt);
String sn = rootElement.element("SN").getText();
ParentPlatform parentPlatform = storager.queryParentPlatById(platformId);
cmderFroPlatform.deviceInfoResponse(parentPlatform, sn, fromHeader.getTag());
}
} else {
logger.info("接收到DeviceInfo应答消息");
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"));
if (StringUtils.isEmpty(device.getStreamMode())) {
device.setStreamMode("UDP");
}
storager.updateDevice(device);
RequestMessage msg = new RequestMessage();
msg.setDeviceId(deviceId);
msg.setType(DeferredResultHolder.CALLBACK_CMD_DEVICEINFO);
msg.setData(device);
deferredResultHolder.invokeResult(msg);
// 回复200 OK
responseAck(evt);
if (offLineDetector.isOnline(deviceId)) {
publisher.onlineEventPublish(deviceId, VideoManagerConstants.EVENT_ONLINE_KEEPLIVE);
}
}
} catch (DocumentException | SipException | InvalidArgumentException | ParseException e) {
e.printStackTrace();
}
}
/***
* 收到catalog设备目录列表请求 处理
*
* @param evt
*/
private void processMessageCatalogList(RequestEvent evt) {
try {
Element rootElement = getRootElement(evt);
String name = rootElement.getName();
Element deviceIdElement = rootElement.element("DeviceID");
String deviceId = deviceIdElement.getText();
Element deviceListElement = rootElement.element("DeviceList");
FromHeader fromHeader = (FromHeader) evt.getRequest().getHeader(FromHeader.NAME);
AddressImpl address = (AddressImpl) fromHeader.getAddress();
SipUri uri = (SipUri) address.getURI();
String platformId = uri.getUser();
// if (deviceListElement == null) { // 存在DeviceList则为响应 catalog, 不存在DeviceList则为查询请求
if (name.equalsIgnoreCase("Query")) { // 区分是Response——查询响应,还是Query——查询请求
// TODO 后续将代码拆分
ParentPlatform parentPlatform = storager.queryParentPlatById(platformId);
if (parentPlatform == null) {
response404Ack(evt);
return;
} else {
// 回复200 OK
responseAck(evt);
Element snElement = rootElement.element("SN");
String sn = snElement.getText();
// 准备回复通道信息
List<ChannelReduce> channelReduces = storager.queryChannelListInParentPlatform(parentPlatform.getServerGBId());
if (channelReduces.size() > 0) {
for (ChannelReduce channelReduce : channelReduces) {
DeviceChannel deviceChannel = storager.queryChannel(channelReduce.getDeviceId(), channelReduce.getChannelId());
cmderFroPlatform.catalogQuery(deviceChannel, parentPlatform, sn, fromHeader.getTag(), channelReduces.size());
}
}
}
} else {
Iterator<Element> deviceListIterator = deviceListElement.elementIterator();
if (deviceListIterator != null) {
Device device = storager.queryVideoDevice(deviceId);
if (device == null) {
return;
}
// 遍历DeviceList
while (deviceListIterator.hasNext()) {
Element itemDevice = deviceListIterator.next();
Element channelDeviceElement = itemDevice.element("DeviceID");
if (channelDeviceElement == null) {
continue;
}
String channelDeviceId = channelDeviceElement.getText();
Element channdelNameElement = itemDevice.element("Name");
String channelName = channdelNameElement != null ? channdelNameElement.getTextTrim().toString() : "";
Element statusElement = itemDevice.element("Status");
String status = statusElement != null ? statusElement.getText().toString() : "ON";
DeviceChannel deviceChannel = new DeviceChannel();
deviceChannel.setName(channelName);
deviceChannel.setChannelId(channelDeviceId);
// ONLINE OFFLINE HIKVISION DS-7716N-E4 NVR的兼容性处理
if (status.equals("ON") || status.equals("On") || status.equals("ONLINE")) {
deviceChannel.setStatus(1);
}
if (status.equals("OFF") || status.equals("Off") || status.equals("OFFLINE")) {
deviceChannel.setStatus(0);
}
deviceChannel.setManufacture(XmlUtil.getText(itemDevice, "Manufacturer"));
deviceChannel.setModel(XmlUtil.getText(itemDevice, "Model"));
deviceChannel.setOwner(XmlUtil.getText(itemDevice, "Owner"));
deviceChannel.setCivilCode(XmlUtil.getText(itemDevice, "CivilCode"));
deviceChannel.setBlock(XmlUtil.getText(itemDevice, "Block"));
deviceChannel.setAddress(XmlUtil.getText(itemDevice, "Address"));
if (XmlUtil.getText(itemDevice, "Parental") == null || XmlUtil.getText(itemDevice, "Parental") == "") {
deviceChannel.setParental(0);
} else {
deviceChannel.setParental(Integer.parseInt(XmlUtil.getText(itemDevice, "Parental")));
}
deviceChannel.setParentId(XmlUtil.getText(itemDevice, "ParentID"));
if (XmlUtil.getText(itemDevice, "SafetyWay") == null || XmlUtil.getText(itemDevice, "SafetyWay") == "") {
deviceChannel.setSafetyWay(0);
} else {
deviceChannel.setSafetyWay(Integer.parseInt(XmlUtil.getText(itemDevice, "SafetyWay")));
}
if (XmlUtil.getText(itemDevice, "RegisterWay") == null || XmlUtil.getText(itemDevice, "RegisterWay") == "") {
deviceChannel.setRegisterWay(1);
} else {
deviceChannel.setRegisterWay(Integer.parseInt(XmlUtil.getText(itemDevice, "RegisterWay")));
}
deviceChannel.setCertNum(XmlUtil.getText(itemDevice, "CertNum"));
if (XmlUtil.getText(itemDevice, "Certifiable") == null || XmlUtil.getText(itemDevice, "Certifiable") == "") {
deviceChannel.setCertifiable(0);
} else {
deviceChannel.setCertifiable(Integer.parseInt(XmlUtil.getText(itemDevice, "Certifiable")));
}
if (XmlUtil.getText(itemDevice, "ErrCode") == null || XmlUtil.getText(itemDevice, "ErrCode") == "") {
deviceChannel.setErrCode(0);
} else {
deviceChannel.setErrCode(Integer.parseInt(XmlUtil.getText(itemDevice, "ErrCode")));
}
deviceChannel.setEndTime(XmlUtil.getText(itemDevice, "EndTime"));
deviceChannel.setSecrecy(XmlUtil.getText(itemDevice, "Secrecy"));
deviceChannel.setIpAddress(XmlUtil.getText(itemDevice, "IPAddress"));
if (XmlUtil.getText(itemDevice, "Port") == null || XmlUtil.getText(itemDevice, "Port") == "") {
deviceChannel.setPort(0);
} else {
deviceChannel.setPort(Integer.parseInt(XmlUtil.getText(itemDevice, "Port")));
}
deviceChannel.setPassword(XmlUtil.getText(itemDevice, "Password"));
if (NumericUtil.isDouble(XmlUtil.getText(itemDevice, "Longitude"))) {
deviceChannel.setLongitude(Double.parseDouble(XmlUtil.getText(itemDevice, "Longitude")));
} else {
deviceChannel.setLongitude(0.00);
}
if (NumericUtil.isDouble(XmlUtil.getText(itemDevice, "Latitude"))) {
deviceChannel.setLatitude(Double.parseDouble(XmlUtil.getText(itemDevice, "Latitude")));
} else {
deviceChannel.setLatitude(0.00);
}
if (XmlUtil.getText(itemDevice, "PTZType") == null || XmlUtil.getText(itemDevice, "PTZType") == "") {
deviceChannel.setPTZType(0);
} else {
deviceChannel.setPTZType(Integer.parseInt(XmlUtil.getText(itemDevice, "PTZType")));
}
deviceChannel.setHasAudio(true); // 默认含有音频,播放时再检查是否有音频及是否AAC
storager.updateChannel(device.getDeviceId(), deviceChannel);
}
RequestMessage msg = new RequestMessage();
msg.setDeviceId(deviceId);
msg.setType(DeferredResultHolder.CALLBACK_CMD_CATALOG);
msg.setData(device);
deferredResultHolder.invokeResult(msg);
// 回复200 OK
responseAck(evt);
if (offLineDetector.isOnline(deviceId)) {
publisher.onlineEventPublish(deviceId, VideoManagerConstants.EVENT_ONLINE_KEEPLIVE);
}
}
}
} catch (DocumentException | SipException | InvalidArgumentException | ParseException e) {
e.printStackTrace();
}
}
/***
* 收到alarm设备报警信息 处理
*
* @param evt
*/
private void processMessageAlarm(RequestEvent evt) {
try {
Element rootElement = getRootElement(evt);
Element deviceIdElement = rootElement.element("DeviceID");
String deviceId = deviceIdElement.getText().toString();
// 回复200 OK
responseAck(evt);
Device device = storager.queryVideoDevice(deviceId);
if (device == null) {
@ -735,7 +712,7 @@ public class MessageRequestProcessor extends SIPRequestAbstractProcessor {
}
} catch (DocumentException | SipException | InvalidArgumentException | ParseException e) {
// } catch (DocumentException e) {
log.error("MessageRequestProcessor.processMessageAlarm error!", e);
logger.error("MessageRequestProcessor.processMessageAlarm error!", e);
}
}
@ -758,7 +735,7 @@ public class MessageRequestProcessor extends SIPRequestAbstractProcessor {
}
}
} catch (ParseException | SipException | InvalidArgumentException | DocumentException e) {
log.error("MessageRequestProcessor.processMessageKeepAlive error!", e);
logger.error("MessageRequestProcessor.processMessageKeepAlive error!", e);
}
}
@ -824,30 +801,30 @@ public class MessageRequestProcessor extends SIPRequestAbstractProcessor {
recordInfo.setRecordList(recordList);
}
// 改用单独线程统计已获取录像文件数量,避免多包并行分别统计不完整的问题
String cacheKey = CACHE_RECORDINFO_KEY + deviceId + sn;
redis.set(cacheKey + "_" + uuid, recordList, 90);
if (!threadNameList.contains(cacheKey)) {
threadNameList.add(cacheKey);
CheckForAllRecordsThread chk = new CheckForAllRecordsThread(cacheKey, recordInfo);
chk.setName(cacheKey);
chk.setDeferredResultHolder(deferredResultHolder);
chk.setRedis(redis);
chk.setLogger(logger);
chk.start();
if (logger.isDebugEnabled()) {
logger.debug("Start Thread " + cacheKey + ".");
}
} else {
if (logger.isDebugEnabled()) {
logger.debug("Thread " + cacheKey + " already started.");
}
}
// 存在录像且如果当前录像明细个数小于总条数,说明拆包返回,需要组装,暂不返回
// if (recordInfo.getSumNum() > 0 && recordList.size() > 0 && recordList.size() < recordInfo.getSumNum()) {
// // 为防止连续请求该设备的录像数据,返回数据错乱,特增加sn进行区分
// String cacheKey = CACHE_RECORDINFO_KEY + deviceId + sn;
// 改用单独线程统计已获取录像文件数量,避免多包并行分别统计不完整的问题
String cacheKey = CACHE_RECORDINFO_KEY + deviceId + sn;
redis.set(cacheKey + "_" + uuid, recordList, 90);
if (!threadNameList.contains(cacheKey)) {
threadNameList.add(cacheKey);
CheckForAllRecordsThread chk = new CheckForAllRecordsThread(cacheKey, recordInfo);
chk.setName(cacheKey);
chk.setDeferredResultHolder(deferredResultHolder);
chk.setRedis(redis);
chk.setLogger(logger);
chk.start();
if (logger.isDebugEnabled()) {
logger.debug("Start Thread " + cacheKey + ".");
}
} else {
if (logger.isDebugEnabled()) {
logger.debug("Thread " + cacheKey + " already started.");
}
}
// 存在录像且如果当前录像明细个数小于总条数,说明拆包返回,需要组装,暂不返回
// if (recordInfo.getSumNum() > 0 && recordList.size() > 0 && recordList.size() < recordInfo.getSumNum()) {
// // 为防止连续请求该设备的录像数据,返回数据错乱,特增加sn进行区分
// String cacheKey = CACHE_RECORDINFO_KEY + deviceId + sn;
// redis.set(cacheKey + "_" + uuid, recordList, 90);
// List<Object> cacheKeys = redis.scan(cacheKey + "_*");
@ -879,7 +856,7 @@ public class MessageRequestProcessor extends SIPRequestAbstractProcessor {
// deferredResultHolder.invokeResult(msg);
// logger.info("处理完成,返回结果");
} catch (DocumentException | SipException | InvalidArgumentException | ParseException e) {
log.error("MessageRequestProcessor.processMessageRecordInfo error!", e);
logger.error("MessageRequestProcessor.processMessageRecordInfo error!", e);
}
}
@ -905,40 +882,40 @@ public class MessageRequestProcessor extends SIPRequestAbstractProcessor {
}
}
} catch (ParseException | SipException | InvalidArgumentException | DocumentException e) {
log.error("MessageRequestProcessor.processMessageMediaStatus error!", e);
logger.error("MessageRequestProcessor.processMessageMediaStatus error!", e);
}
}
/**
* 处理AudioBroadcast语音广播Message
*
* @param evt
*/
private void processMessageBroadcast(RequestEvent evt) {
try {
Element rootElement = getRootElement(evt);
String deviceId = XmlUtil.getText(rootElement, "DeviceID");
// 回复200 OK
responseAck(evt);
if (rootElement.getName().equals("Response")) {
// 此处是对本平台发出Broadcast指令的应答
JSONObject json = new JSONObject();
XmlUtil.node2Json(rootElement, json);
if (logger.isDebugEnabled()) {
logger.debug(json.toJSONString());
}
RequestMessage msg = new RequestMessage();
msg.setDeviceId(deviceId);
msg.setType(DeferredResultHolder.CALLBACK_CMD_BROADCAST);
msg.setData(json);
deferredResultHolder.invokeResult(msg);
} else {
// 此处是上级发出的Broadcast指令
}
} catch (ParseException | SipException | InvalidArgumentException | DocumentException e) {
e.printStackTrace();
}
}
/**
* 处理AudioBroadcast语音广播Message
*
* @param evt
*/
private void processMessageBroadcast(RequestEvent evt) {
try {
Element rootElement = getRootElement(evt);
String deviceId = XmlUtil.getText(rootElement, "DeviceID");
// 回复200 OK
responseAck(evt);
if (rootElement.getName().equals("Response")) {
// 此处是对本平台发出Broadcast指令的应答
JSONObject json = new JSONObject();
XmlUtil.node2Json(rootElement, json);
if (logger.isDebugEnabled()) {
logger.debug(json.toJSONString());
}
RequestMessage msg = new RequestMessage();
msg.setDeviceId(deviceId);
msg.setType(DeferredResultHolder.CALLBACK_CMD_BROADCAST);
msg.setData(json);
deferredResultHolder.invokeResult(msg);
} else {
// 此处是上级发出的Broadcast指令
}
} catch (ParseException | SipException | InvalidArgumentException | DocumentException e) {
e.printStackTrace();
}
}
/***
@ -953,25 +930,25 @@ public class MessageRequestProcessor extends SIPRequestAbstractProcessor {
getServerTransaction(evt).sendResponse(response);
}
/***
* 回复404
* @param evt
* @throws SipException
* @throws InvalidArgumentException
* @throws ParseException
*/
private void response404Ack(RequestEvent evt) throws SipException, InvalidArgumentException, ParseException {
Response response = getMessageFactory().createResponse(Response.NOT_FOUND, evt.getRequest());
getServerTransaction(evt).sendResponse(response);
}
private Element getRootElement(RequestEvent evt) throws DocumentException {
Request request = evt.getRequest();
SAXReader reader = new SAXReader();
reader.setEncoding("gbk");
Document xml = reader.read(new ByteArrayInputStream(request.getRawContent()));
return xml.getRootElement();
}
/***
* 回复404
* @param evt
* @throws SipException
* @throws InvalidArgumentException
* @throws ParseException
*/
private void response404Ack(RequestEvent evt) throws SipException, InvalidArgumentException, ParseException {
Response response = getMessageFactory().createResponse(Response.NOT_FOUND, evt.getRequest());
getServerTransaction(evt).sendResponse(response);
}
private Element getRootElement(RequestEvent evt) throws DocumentException {
Request request = evt.getRequest();
SAXReader reader = new SAXReader();
reader.setEncoding("gbk");
Document xml = reader.read(new ByteArrayInputStream(request.getRawContent()));
return xml.getRootElement();
}
public void setCmder(SIPCommander cmder) {
this.cmder = cmder;
@ -1001,15 +978,15 @@ public class MessageRequestProcessor extends SIPRequestAbstractProcessor {
return redisCatchStorage;
}
public void setRedisCatchStorage(IRedisCatchStorage redisCatchStorage) {
this.redisCatchStorage = redisCatchStorage;
}
public void setRedisCatchStorage(IRedisCatchStorage redisCatchStorage) {
this.redisCatchStorage = redisCatchStorage;
}
public SIPCommanderFroPlatform getCmderFroPlatform() {
return cmderFroPlatform;
}
public SIPCommanderFroPlatform getCmderFroPlatform() {
return cmderFroPlatform;
}
public void setCmderFroPlatform(SIPCommanderFroPlatform cmderFroPlatform) {
this.cmderFroPlatform = cmderFroPlatform;
}
public void setCmderFroPlatform(SIPCommanderFroPlatform cmderFroPlatform) {
this.cmderFroPlatform = cmderFroPlatform;
}
}

322
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java

@ -45,11 +45,9 @@ public class ZLMHttpHookListener {
@Autowired
private IRedisCatchStorage redisCatchStorage;
@Autowired
private ZLMMediaListManager zlmMediaListManager;
@Autowired
private ZLMMediaListManager zlmMediaListManager;
@Autowired
private ZLMHttpHookSubscribe subscribe;
@Autowired
private ZLMHttpHookSubscribe subscribe;
@ -59,161 +57,153 @@ public class ZLMHttpHookListener {
@Autowired
private VideoStreamSessionManager streamSession;
/**
* 流量统计事件播放器或推流器断开时并且耗用流量超过特定阈值时会触发此事件阈值通过配置文件general.flowThreshold配置此事件对回复不敏感
*
*/
@ResponseBody
@PostMapping(value = "/on_flow_report", produces = "application/json;charset=UTF-8")
public ResponseEntity<String> onFlowReport(@RequestBody JSONObject json){
if (logger.isDebugEnabled()) {
logger.debug("ZLM HOOK on_flow_report API调用,参数:" + json.toString());
}
JSONObject ret = new JSONObject();
ret.put("code", 0);
ret.put("msg", "success");
return new ResponseEntity<String>(ret.toString(),HttpStatus.OK);
}
/**
* 访问http文件服务器上hls之外的文件时触发
*
*/
@ResponseBody
@PostMapping(value = "/on_http_access", produces = "application/json;charset=UTF-8")
public ResponseEntity<String> onHttpAccess(@RequestBody JSONObject json){
if (logger.isDebugEnabled()) {
logger.debug("ZLM HOOK on_http_access API 调用,参数:" + json.toString());
}
JSONObject ret = new JSONObject();
ret.put("code", 0);
ret.put("err", "");
ret.put("path", "");
ret.put("second", 600);
return new ResponseEntity<String>(ret.toString(),HttpStatus.OK);
}
/**
* 播放器鉴权事件rtsp/rtmp/http-flv/ws-flv/hls的播放都将触发此鉴权事件
*
*/
@ResponseBody
@PostMapping(value = "/on_play", produces = "application/json;charset=UTF-8")
public ResponseEntity<String> onPlay(@RequestBody JSONObject json){
if (logger.isDebugEnabled()) {
logger.debug("ZLM HOOK on_play API调用,参数:" + json.toString());
}
JSONObject ret = new JSONObject();
ret.put("code", 0);
ret.put("msg", "success");
return new ResponseEntity<String>(ret.toString(),HttpStatus.OK);
}
/**
* rtsp/rtmp/rtp推流鉴权事件
*
*/
@ResponseBody
@PostMapping(value = "/on_publish", produces = "application/json;charset=UTF-8")
public ResponseEntity<String> onPublish(@RequestBody JSONObject json){
if (logger.isDebugEnabled()) {
logger.debug("ZLM HOOK on_publish API调用,参数:" + json.toString());
}
/**
* 流量统计事件播放器或推流器断开时并且耗用流量超过特定阈值时会触发此事件阈值通过配置文件general.flowThreshold配置此事件对回复不敏感
*/
@ResponseBody
@PostMapping(value = "/on_flow_report", produces = "application/json;charset=UTF-8")
public ResponseEntity<String> onFlowReport(@RequestBody JSONObject json) {
if (logger.isDebugEnabled()) {
logger.debug("ZLM HOOK on_flow_report API调用,参数:" + json.toString());
}
JSONObject ret = new JSONObject();
ret.put("code", 0);
ret.put("msg", "success");
return new ResponseEntity<String>(ret.toString(), HttpStatus.OK);
}
/**
* 访问http文件服务器上hls之外的文件时触发
*/
@ResponseBody
@PostMapping(value = "/on_http_access", produces = "application/json;charset=UTF-8")
public ResponseEntity<String> onHttpAccess(@RequestBody JSONObject json) {
if (logger.isDebugEnabled()) {
logger.debug("ZLM HOOK on_http_access API 调用,参数:" + json.toString());
}
JSONObject ret = new JSONObject();
ret.put("code", 0);
ret.put("err", "");
ret.put("path", "");
ret.put("second", 600);
return new ResponseEntity<String>(ret.toString(), HttpStatus.OK);
}
/**
* 播放器鉴权事件rtsp/rtmp/http-flv/ws-flv/hls的播放都将触发此鉴权事件
*/
@ResponseBody
@PostMapping(value = "/on_play", produces = "application/json;charset=UTF-8")
public ResponseEntity<String> onPlay(@RequestBody JSONObject json) {
if (logger.isDebugEnabled()) {
logger.debug("ZLM HOOK on_play API调用,参数:" + json.toString());
}
JSONObject ret = new JSONObject();
ret.put("code", 0);
ret.put("msg", "success");
return new ResponseEntity<String>(ret.toString(), HttpStatus.OK);
}
/**
* rtsp/rtmp/rtp推流鉴权事件
*/
@ResponseBody
@PostMapping(value = "/on_publish", produces = "application/json;charset=UTF-8")
public ResponseEntity<String> onPublish(@RequestBody JSONObject json) {
if (logger.isDebugEnabled()) {
logger.debug("ZLM HOOK on_publish API调用,参数:" + json.toString());
}
ZLMHttpHookSubscribe.Event subscribe = this.subscribe.getSubscribe(ZLMHttpHookSubscribe.HookType.on_publish, json);
if (subscribe != null) {
subscribe.response(json);
}
JSONObject ret = new JSONObject();
ret.put("code", 0);
ret.put("msg", "success");
ret.put("enableHls", true);
ret.put("enableMP4", false);
ret.put("enableRtxp", true);
return new ResponseEntity<String>(ret.toString(),HttpStatus.OK);
}
/**
* 录制mp4完成后通知事件此事件对回复不敏感
*
*/
@ResponseBody
@PostMapping(value = "/on_record_mp4", produces = "application/json;charset=UTF-8")
public ResponseEntity<String> onRecordMp4(@RequestBody JSONObject json){
if (logger.isDebugEnabled()) {
logger.debug("ZLM HOOK on_record_mp4 API调用,参数:" + json.toString());
}
JSONObject ret = new JSONObject();
ret.put("code", 0);
ret.put("msg", "success");
return new ResponseEntity<String>(ret.toString(),HttpStatus.OK);
}
/**
* rtsp专用的鉴权事件先触发on_rtsp_realm事件然后才会触发on_rtsp_auth事件
*
*/
@ResponseBody
@PostMapping(value = "/on_rtsp_realm", produces = "application/json;charset=UTF-8")
public ResponseEntity<String> onRtspRealm(@RequestBody JSONObject json){
if (logger.isDebugEnabled()) {
logger.debug("ZLM HOOK on_rtsp_realm API调用,参数:" + json.toString());
}
JSONObject ret = new JSONObject();
ret.put("code", 0);
ret.put("realm", "");
return new ResponseEntity<String>(ret.toString(),HttpStatus.OK);
}
/**
* 该rtsp流是否开启rtsp专用方式的鉴权事件开启后才会触发on_rtsp_auth事件需要指出的是rtsp也支持url参数鉴权它支持两种方式鉴权
*
*/
@ResponseBody
@PostMapping(value = "/on_rtsp_auth", produces = "application/json;charset=UTF-8")
public ResponseEntity<String> onRtspAuth(@RequestBody JSONObject json){
if (logger.isDebugEnabled()) {
logger.debug("ZLM HOOK on_rtsp_auth API调用,参数:" + json.toString());
}
JSONObject ret = new JSONObject();
ret.put("code", 0);
ret.put("encrypted", false);
ret.put("passwd", "test");
return new ResponseEntity<String>(ret.toString(),HttpStatus.OK);
}
/**
* shell登录鉴权ZLMediaKit提供简单的telnet调试方式使用telnet 127.0.0.1 9000能进入MediaServer进程的shell界面
*
*/
@ResponseBody
@PostMapping(value = "/on_shell_login", produces = "application/json;charset=UTF-8")
public ResponseEntity<String> onShellLogin(@RequestBody JSONObject json){
if (logger.isDebugEnabled()) {
logger.debug("ZLM HOOK on_shell_login API调用,参数:" + json.toString());
}
// TODO 如果是带有rtpstream则开启按需拉流
// String app = json.getString("app");
// String stream = json.getString("stream");
ZLMHttpHookSubscribe.Event subscribe = this.subscribe.getSubscribe(ZLMHttpHookSubscribe.HookType.on_publish, json);
if (subscribe != null) subscribe.response(json);
JSONObject ret = new JSONObject();
ret.put("code", 0);
ret.put("msg", "success");
return new ResponseEntity<String>(ret.toString(),HttpStatus.OK);
}
JSONObject ret = new JSONObject();
ret.put("code", 0);
ret.put("msg", "success");
ret.put("enableHls", true);
ret.put("enableMP4", false);
ret.put("enableRtxp", true);
return new ResponseEntity<String>(ret.toString(), HttpStatus.OK);
}
/**
* 录制mp4完成后通知事件此事件对回复不敏感
*/
@ResponseBody
@PostMapping(value = "/on_record_mp4", produces = "application/json;charset=UTF-8")
public ResponseEntity<String> onRecordMp4(@RequestBody JSONObject json) {
if (logger.isDebugEnabled()) {
logger.debug("ZLM HOOK on_record_mp4 API调用,参数:" + json.toString());
}
JSONObject ret = new JSONObject();
ret.put("code", 0);
ret.put("msg", "success");
return new ResponseEntity<String>(ret.toString(), HttpStatus.OK);
}
/**
* rtsp专用的鉴权事件先触发on_rtsp_realm事件然后才会触发on_rtsp_auth事件
*/
@ResponseBody
@PostMapping(value = "/on_rtsp_realm", produces = "application/json;charset=UTF-8")
public ResponseEntity<String> onRtspRealm(@RequestBody JSONObject json) {
if (logger.isDebugEnabled()) {
logger.debug("ZLM HOOK on_rtsp_realm API调用,参数:" + json.toString());
}
JSONObject ret = new JSONObject();
ret.put("code", 0);
ret.put("realm", "");
return new ResponseEntity<String>(ret.toString(), HttpStatus.OK);
}
/**
* 该rtsp流是否开启rtsp专用方式的鉴权事件开启后才会触发on_rtsp_auth事件需要指出的是rtsp也支持url参数鉴权它支持两种方式鉴权
*/
@ResponseBody
@PostMapping(value = "/on_rtsp_auth", produces = "application/json;charset=UTF-8")
public ResponseEntity<String> onRtspAuth(@RequestBody JSONObject json) {
if (logger.isDebugEnabled()) {
logger.debug("ZLM HOOK on_rtsp_auth API调用,参数:" + json.toString());
}
JSONObject ret = new JSONObject();
ret.put("code", 0);
ret.put("encrypted", false);
ret.put("passwd", "test");
return new ResponseEntity<String>(ret.toString(), HttpStatus.OK);
}
/**
* shell登录鉴权ZLMediaKit提供简单的telnet调试方式使用telnet 127.0.0.1 9000能进入MediaServer进程的shell界面
*/
@ResponseBody
@PostMapping(value = "/on_shell_login", produces = "application/json;charset=UTF-8")
public ResponseEntity<String> onShellLogin(@RequestBody JSONObject json) {
if (logger.isDebugEnabled()) {
logger.debug("ZLM HOOK on_shell_login API调用,参数:" + json.toString());
}
// TODO 如果是带有rtpstream则开启按需拉流
// String app = json.getString("app");
// String stream = json.getString("stream");
ZLMHttpHookSubscribe.Event subscribe = this.subscribe.getSubscribe(ZLMHttpHookSubscribe.HookType.on_publish, json);
if (subscribe != null) subscribe.response(json);
JSONObject ret = new JSONObject();
ret.put("code", 0);
ret.put("msg", "success");
return new ResponseEntity<String>(ret.toString(), HttpStatus.OK);
}
/**
* rtsp/rtmp流注册或注销时触发此事件此事件对回复不敏感
@ -233,9 +223,10 @@ public class ZLMHttpHookListener {
// 流消失移除redis play
String app = json.getString("app");
String streamId = json.getString("stream");
String schema = json.getString("schema");
boolean regist = json.getBoolean("regist");
if (!"rtp".equals(app) || regist) {
if (!"rtp".equals(app) && "rtsp".equals(schema)){
if (!"rtp".equals(app) && "rtsp".equals(schema)) {
zlmMediaListManager.updateMediaList();
}
return new ResponseEntity<>(ret.toString(), HttpStatus.OK);
@ -335,18 +326,17 @@ public class ZLMHttpHookListener {
}
return new ResponseEntity<>(ret.toString(), HttpStatus.OK);
}
/**
* 服务器启动事件可以用于监听服务器崩溃重启此事件对回复不敏感
*
*/
@ResponseBody
@PostMapping(value = "/on_server_started", produces = "application/json;charset=UTF-8")
public ResponseEntity<String> onServerStarted(HttpServletRequest request, @RequestBody JSONObject json){
if (logger.isDebugEnabled()) {
logger.debug("ZLM HOOK on_server_started API调用,参数:" + json.toString());
}
/**
* 服务器启动事件可以用于监听服务器崩溃重启此事件对回复不敏感
*/
@ResponseBody
@PostMapping(value = "/on_server_started", produces = "application/json;charset=UTF-8")
public ResponseEntity<String> onServerStarted(HttpServletRequest request, @RequestBody JSONObject json) {
if (logger.isDebugEnabled()) {
logger.debug("ZLM HOOK on_server_started API调用,参数:" + json.toString());
}
MediaServerConfig mediaServerConfig = JSON.toJavaObject(json, MediaServerConfig.class);
redisCatchStorage.updateMediaInfo(mediaServerConfig);

13
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMMediaListManager.java

@ -1,19 +1,14 @@
package com.genersoft.iot.vmp.media.zlm;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.genersoft.iot.vmp.common.RealVideo;
import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
import com.genersoft.iot.vmp.gb28181.session.SsrcUtil;
import com.genersoft.iot.vmp.media.zlm.dto.MediaItem;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import com.genersoft.iot.vmp.storager.impl.RedisCatchStorageImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.util.*;
@ -36,9 +31,10 @@ public class ZLMMediaListManager {
Integer code = mediaList.getInteger("code");
Map<String, RealVideo> result = new HashMap<>();
if (code == 0 ) {
if (code == 0) {
if (dataStr != null) {
List<MediaItem> mediaItems = JSON.parseObject(dataStr, new TypeReference<List<MediaItem>>() {});
List<MediaItem> mediaItems = JSON.parseObject(dataStr, new TypeReference<List<MediaItem>>() {
});
for (MediaItem item : mediaItems) {
if ("rtp".equals(item.getApp())) {
continue;
@ -73,7 +69,7 @@ public class ZLMMediaListManager {
}
}
}else {
} else {
logger.warn("更新视频流失败,错误code: " + code);
}
@ -83,5 +79,4 @@ public class ZLMMediaListManager {
}
}

29
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRESTfulUtils.java

@ -80,17 +80,21 @@ public class ZLMRESTfulUtils {
// return sendPost("getMediaInfo", param);
// }
public JSONObject getMediaList(){
return sendPost("getMediaList",null);
public JSONObject getMediaList() {
// TODO mediaServerIp 要作为参数传递进来,
String mediaServerIp = mediaConfig.getMediaIp();
return sendPost(mediaServerIp, "getMediaList", null);
}
public JSONObject getMediaInfo(String app, String schema, String stream){
public JSONObject getMediaInfo(String app, String schema, String stream) {
// TODO mediaServerIp 要作为参数传递进来,
String mediaServerIp = mediaConfig.getMediaIp();
Map<String, Object> param = new HashMap<>();
param.put("app",app);
param.put("schema",schema);
param.put("stream",stream);
param.put("vhost","__defaultVhost__");
return sendPost("getMediaInfo",param);
param.put("app", app);
param.put("schema", schema);
param.put("stream", stream);
param.put("vhost", "__defaultVhost__");
return sendPost(mediaServerIp, "getMediaInfo", param);
}
public JSONObject getRtpInfo(String mediaServerIp, String stream_id) {
@ -178,10 +182,15 @@ public class ZLMRESTfulUtils {
}
public JSONObject startSendRtp(Map<String, Object> param) {
return sendPost("startSendRtp",param);
// TODO mediaServerIp 要作为参数传递进来,
String mediaServerIp = mediaConfig.getMediaIp();
return sendPost(mediaServerIp, "startSendRtp", param);
}
public JSONObject stopSendRtp(Map<String, Object> param) {
return sendPost("stopSendRtp",param);
// TODO mediaServerIp 要作为参数传递进来,
String mediaServerIp = mediaConfig.getMediaIp();
return sendPost(mediaServerIp, "stopSendRtp", param);
}
}

47
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRTPServerFactory.java

@ -1,9 +1,11 @@
package com.genersoft.iot.vmp.media.zlm;
import com.alibaba.fastjson.JSONObject;
import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
import com.genersoft.iot.vmp.gb28181.session.SsrcUtil;
import com.genersoft.iot.vmp.common.StreamInfo;
import com.genersoft.iot.vmp.conf.MediaConfig;
import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@ -24,6 +26,9 @@ public class ZLMRTPServerFactory {
@Autowired
private ZLMRESTfulUtils zlmresTfulUtils;
@Autowired
private VideoStreamSessionManager streamSession;
private int[] udpPortRangeArray = new int[2];
private ConcurrentHashMap<String, Integer> currentPortMap = new ConcurrentHashMap<>();
@ -110,20 +115,27 @@ public class ZLMRTPServerFactory {
/**
* 创建一个推流
* @param ip 推流ip
* @param port 推流端口
* @param ssrc 推流唯一标识
*
* @param ip 推流ip
* @param port 推流端口
* @param ssrc 推流唯一标识
* @param platformId 平台id
* @param channelId 通道id
* @param tcp 是否为tcp
* @param device 平台id
* @param channelId 通道id
* @param tcp 是否为tcp
* @return SendRtpItem
*/
public SendRtpItem createSendRtpItem(String ip, int port, String ssrc, String platformId, String deviceId, String channelId, boolean tcp){
String playSsrc = SsrcUtil.getPlaySsrc();
int localPort = createRTPServer(SsrcUtil.getPlaySsrc());
public SendRtpItem createSendRtpItem(String ip, int port, String ssrc, String platformId, Device device, String channelId, boolean tcp) {
StreamInfo playStreamInfo = streamSession.createPlayStreamInfo(device, channelId);
String mediaServerIp = playStreamInfo.getMediaServerIp();
String streamId = playStreamInfo.getStreamId();
int localPort = createRTPServer(mediaServerIp, streamId);
if (localPort != -1) {
closeRTPServer(playSsrc);
}else {
// TODO 没看懂这块逻辑,-1代表失败吗?分配端口后为什么要再把端口关掉?
closeRTPServer(mediaServerIp, streamId);
streamSession.remove(playStreamInfo);
} else {
streamSession.remove(playStreamInfo);
logger.error("没有可用的端口");
return null;
}
@ -132,7 +144,7 @@ public class ZLMRTPServerFactory {
sendRtpItem.setPort(port);
sendRtpItem.setSsrc(ssrc);
sendRtpItem.setPlatformId(platformId);
sendRtpItem.setDeviceId(deviceId);
sendRtpItem.setDeviceId(device.getDeviceId());
sendRtpItem.setChannelId(channelId);
sendRtpItem.setTcp(tcp);
sendRtpItem.setLocalPort(localPort);
@ -142,14 +154,14 @@ public class ZLMRTPServerFactory {
/**
* 调用zlm RESTful API startSendRtp
*/
public Boolean startSendRtpStream(Map<String, Object>param) {
public Boolean startSendRtpStream(Map<String, Object> param) {
Boolean result = false;
JSONObject jsonObject = zlmresTfulUtils.startSendRtp(param);
System.out.println(jsonObject);
if (jsonObject == null) {
logger.error("RTP推流失败: 请检查ZLM服务");
} else if (jsonObject.getInteger("code") == 0) {
result= true;
result = true;
logger.error("RTP推流请求成功,本地推流端口:" + jsonObject.getString("local_port"));
} else {
logger.error("RTP推流失败: " + jsonObject.getString("msg"));
@ -167,6 +179,7 @@ public class ZLMRTPServerFactory {
/**
* 查询转推的流是否有其它观看者
*
* @param streamId
* @return
*/
@ -178,14 +191,14 @@ public class ZLMRTPServerFactory {
/**
* 调用zlm RESTful API stopSendRtp
*/
public Boolean stopSendRtpStream(Map<String, Object>param) {
public Boolean stopSendRtpStream(Map<String, Object> param) {
Boolean result = false;
JSONObject jsonObject = zlmresTfulUtils.stopSendRtp(param);
System.out.println(jsonObject);
if (jsonObject == null) {
logger.error("停止RTP推流失败: 请检查ZLM服务");
} else if (jsonObject.getInteger("code") == 0) {
result= true;
result = true;
logger.error("停止RTP推流成功");
} else {
logger.error("停止RTP推流失败: " + jsonObject.getString("msg"));

17
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRunner.java

@ -7,7 +7,8 @@ import com.genersoft.iot.vmp.conf.MediaConfig;
import com.genersoft.iot.vmp.conf.MediaServerConfig;
import com.genersoft.iot.vmp.conf.SipConfig;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.CommandLineRunner;
@ -18,10 +19,10 @@ import org.springframework.util.StringUtils;
import java.util.HashMap;
import java.util.Map;
@Slf4j
@Component
@Order(value = 1)
public class ZLMRunner implements CommandLineRunner {
private final Logger logger = LoggerFactory.getLogger(ZLMRunner.class);
@Autowired
private IRedisCatchStorage redisCatchStorage;
@ -44,10 +45,10 @@ public class ZLMRunner implements CommandLineRunner {
String[] mediaIpArr = mediaConfig.getMediaIpArr();
for (String mediaIp : mediaIpArr) {
// 获取zlm信息
log.info("等待zlm {} 接入...", mediaIp);
logger.info("等待zlm {} 接入...", mediaIp);
MediaServerConfig mediaServerConfig = getMediaServerConfig(mediaIp);
if (mediaServerConfig != null) {
log.info("zlm {} 接入成功...", mediaIp);
logger.info("zlm {} 接入成功...", mediaIp);
if (mediaConfig.getAutoConfig()) {
// 自动配置zlm
saveZLMConfig(mediaIp);
@ -71,7 +72,7 @@ public class ZLMRunner implements CommandLineRunner {
mediaServerConfig = JSON.parseObject(JSON.toJSONString(data.get(0)), MediaServerConfig.class);
}
} else {
log.error("getMediaServerConfig失败, 1s后重试");
logger.error("getMediaServerConfig失败, 1s后重试");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
@ -83,7 +84,7 @@ public class ZLMRunner implements CommandLineRunner {
}
private void saveZLMConfig(String mediaIp) {
log.info("设置zlm {} ...", mediaIp);
logger.info("设置zlm {} ...", mediaIp);
String mediaHookIp = mediaConfig.getMediaHookIp();
if (StringUtils.isEmpty(mediaHookIp)) {
mediaHookIp = sipConfig.getSipIp();
@ -112,9 +113,9 @@ public class ZLMRunner implements CommandLineRunner {
JSONObject responseJSON = zlmresTfulUtils.setServerConfig(mediaIp, param);
if (responseJSON != null && responseJSON.getInteger("code") == 0) {
log.info("设置zlm {} 成功", mediaIp);
logger.info("设置zlm {} 成功", mediaIp);
} else {
log.info("设置zlm {} 失败: {}", mediaIp, responseJSON);
logger.info("设置zlm {} 失败: {}", mediaIp, responseJSON);
}
}
}

9
src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java

@ -8,7 +8,6 @@ import com.genersoft.iot.vmp.gb28181.bean.ParentPlatformCatch;
import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
import java.util.List;
import java.util.Map;
public interface IRedisCatchStorage {
@ -56,7 +55,8 @@ public interface IRedisCatchStorage {
StreamInfo queryPlaybackByChannel(String channelId);
List<StreamInfo> queryPlayBackByDeviceId(String deviceId);
StreamInfo queryPlaybackByDevice(String deviceId, String code);
StreamInfo queryPlaybackByDevice(String deviceId, String channelId);
void updatePlatformCatchInfo(ParentPlatformCatch parentPlatformCatch);
@ -84,6 +84,7 @@ public interface IRedisCatchStorage {
/**
* 查询RTP推送信息缓存
*
* @param platformGbId
* @param channelId
* @return sendRtpItem
@ -92,6 +93,7 @@ public interface IRedisCatchStorage {
/**
* 删除RTP推送信息缓存
*
* @param platformGbId
* @param channelId
*/
@ -99,18 +101,21 @@ public interface IRedisCatchStorage {
/**
* 查询某个通道是否存在上级点播RTP推送
*
* @param channelId
*/
boolean isChannelSendingRTP(String channelId);
/**
* 更新媒体流列表
*
* @param mediaList
*/
void updateMediaList(List<RealVideo> mediaList);
/**
* 获取当前媒体流列表
*
* @return List<RealVideo>
*/
List<Object> getMediaList(int start, int end);

203
src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorager.java

@ -2,9 +2,9 @@ package com.genersoft.iot.vmp.storager;
import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
import com.genersoft.iot.vmp.gb28181.bean.MobilePosition;
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
import com.genersoft.iot.vmp.vmanager.platform.bean.ChannelReduce;
import com.genersoft.iot.vmp.gb28181.bean.MobilePosition;
import com.github.pagehelper.PageInfo;
import java.util.List;
@ -22,7 +22,7 @@ public interface IVideoManagerStorager {
* @param deviceId 设备ID
* @return true:存在 false不存在
*/
public boolean exists(String deviceId);
boolean exists(String deviceId);
/**
* 视频设备创建
@ -30,7 +30,7 @@ public interface IVideoManagerStorager {
* @param device 设备对象
* @return true创建成功 false创建失败
*/
public boolean create(Device device);
boolean create(Device device);
/**
* 视频设备更新
@ -38,7 +38,7 @@ public interface IVideoManagerStorager {
* @param device 设备对象
* @return true创建成功 false创建失败
*/
public boolean updateDevice(Device device);
boolean updateDevice(Device device);
/**
* 添加设备通道
@ -46,7 +46,7 @@ public interface IVideoManagerStorager {
* @param deviceId 设备id
* @param channel 通道
*/
public void updateChannel(String deviceId, DeviceChannel channel);
void updateChannel(String deviceId, DeviceChannel channel);
/**
* 开始播放
@ -55,7 +55,7 @@ public interface IVideoManagerStorager {
* @param channelId 通道ID
* @param streamId 流地址
*/
public void startPlay(String deviceId, String channelId, String streamId);
void startPlay(String deviceId, String channelId, String streamId);
/**
* 停止播放
@ -63,7 +63,7 @@ public interface IVideoManagerStorager {
* @param deviceId 设备id
* @param channelId 通道ID
*/
public void stopPlay(String deviceId, String channelId);
void stopPlay(String deviceId, String channelId);
/**
* 获取设备
@ -71,7 +71,7 @@ public interface IVideoManagerStorager {
* @param deviceId 设备ID
* @return DShadow 设备对象
*/
public Device queryVideoDevice(String deviceId);
Device queryVideoDevice(String deviceId);
/**
* 获取某个设备的通道列表
@ -81,7 +81,7 @@ public interface IVideoManagerStorager {
* @param count 每页数量
* @return
*/
public PageInfo queryChannelsByDeviceId(String deviceId, String query, Boolean hasSubChannel, Boolean online, int page, int count);
PageInfo queryChannelsByDeviceId(String deviceId, String query, Boolean hasSubChannel, Boolean online, int page, int count);
/**
* 获取某个设备的通道列表
@ -89,7 +89,7 @@ public interface IVideoManagerStorager {
* @param deviceId 设备ID
* @return
*/
public List<DeviceChannel> queryChannelsByDeviceId(String deviceId);
List<DeviceChannel> queryChannelsByDeviceId(String deviceId);
/**
* 获取某个设备的通道
@ -97,7 +97,7 @@ public interface IVideoManagerStorager {
* @param deviceId 设备ID
* @param channelId 通道ID
*/
public DeviceChannel queryChannel(String deviceId, String channelId);
DeviceChannel queryChannel(String deviceId, String channelId);
/**
* 获取多个设备
@ -106,14 +106,14 @@ public interface IVideoManagerStorager {
* @param count 每页数量
* @return List<Device> 设备对象数组
*/
public PageInfo<Device> queryVideoDeviceList(int page, int count);
PageInfo<Device> queryVideoDeviceList(int page, int count);
/**
* 获取多个设备
*
* @return List<Device> 设备对象数组
*/
public List<Device> queryVideoDeviceList();
List<Device> queryVideoDeviceList();
/**
* 删除设备
@ -121,7 +121,7 @@ public interface IVideoManagerStorager {
* @param deviceId 设备ID
* @return true删除成功 false删除失败
*/
public boolean delete(String deviceId);
boolean delete(String deviceId);
/**
* 更新设备在线
@ -129,7 +129,7 @@ public interface IVideoManagerStorager {
* @param deviceId 设备ID
* @return true更新成功 false更新失败
*/
public boolean online(String deviceId);
boolean online(String deviceId);
/**
* 更新设备离线
@ -137,7 +137,7 @@ public interface IVideoManagerStorager {
* @param deviceId 设备ID
* @return true更新成功 false更新失败
*/
public boolean outline(String deviceId);
boolean outline(String deviceId);
/**
@ -160,85 +160,85 @@ public interface IVideoManagerStorager {
void cleanChannelsForDevice(String deviceId);
/**
* 添加Mobile Position设备移动位置
* 更新上级平台
*
* @param parentPlatform
*/
boolean updateParentPlatform(ParentPlatform parentPlatform);
/**
* 添加上级平台
*
* @param parentPlatform
*/
boolean addParentPlatform(ParentPlatform parentPlatform);
/**
* 删除上级平台
*
* @param parentPlatform
*/
boolean deleteParentPlatform(ParentPlatform parentPlatform);
/**
* 分页获取上级平台
*
* @param page
* @param count
* @return
*/
PageInfo<ParentPlatform> queryParentPlatformList(int page, int count);
/**
* 获取所有已启用的平台
*
* @return
*/
List<ParentPlatform> queryEnableParentPlatformList(boolean enable);
/**
* 获取上级平台
*
* @param MobilePosition
* @param platformGbId
* @return
*/
public boolean insertMobilePosition(MobilePosition mobilePosition);
/**
* 更新上级平台
* @param parentPlatform
*/
boolean updateParentPlatform(ParentPlatform parentPlatform);
/**
* 添加上级平台
* @param parentPlatform
*/
boolean addParentPlatform(ParentPlatform parentPlatform);
/**
* 删除上级平台
* @param parentPlatform
*/
boolean deleteParentPlatform(ParentPlatform parentPlatform);
/**
* 分页获取上级平台
* @param page
* @param count
* @return
*/
PageInfo<ParentPlatform> queryParentPlatformList(int page, int count);
/**
* 获取所有已启用的平台
* @return
*/
List<ParentPlatform> queryEnableParentPlatformList(boolean enable);
/**
* 获取上级平台
* @param platformGbId
* @return
*/
ParentPlatform queryParentPlatById(String platformGbId);
/**
* 所有平台离线
*/
void outlineForAllParentPlatform();
/**
* 查询通道信息不区分设备(已关联平台或全部)
*/
PageInfo<ChannelReduce> queryAllChannelList(int page, int count, String query, Boolean online, Boolean channelType, String platformId, Boolean inPlatform);
/**
* 查询设备的通道信息
*/
List<ChannelReduce> queryChannelListInParentPlatform(String platformId);
/**
* 更新上级平台的通道信息
* @param platformId
* @param channelReduces
* @return
*/
int updateChannelForGB(String platformId, List<ChannelReduce> channelReduces);
/**
* 移除上级平台的通道信息
* @param platformId
* @param channelReduces
* @return
*/
int delChannelForGB(String platformId, List<ChannelReduce> channelReduces);
ParentPlatform queryParentPlatById(String platformGbId);
/**
* 所有平台离线
*/
void outlineForAllParentPlatform();
/**
* 查询通道信息不区分设备(已关联平台或全部)
*/
PageInfo<ChannelReduce> queryAllChannelList(int page, int count, String query, Boolean online, Boolean channelType, String platformId, Boolean inPlatform);
/**
* 查询设备的通道信息
*/
List<ChannelReduce> queryChannelListInParentPlatform(String platformId);
/**
* 更新上级平台的通道信息
*
* @param platformId
* @param channelReduces
* @return
*/
int updateChannelForGB(String platformId, List<ChannelReduce> channelReduces);
/**
* 移除上级平台的通道信息
*
* @param platformId
* @param channelReduces
* @return
*/
int delChannelForGB(String platformId, List<ChannelReduce> channelReduces);
DeviceChannel queryChannelInParentPlatform(String platformId, String channelId);
@ -246,12 +246,13 @@ public interface IVideoManagerStorager {
Device queryVideoDeviceByPlatformIdAndChannelId(String platformId, String channelId);
/**
* 添加Mobile Position设备移动位置
* @param MobilePosition
* @return
*/
public boolean insertMobilePosition(MobilePosition mobilePosition);
/**
* 添加Mobile Position设备移动位置
*
* @param mobilePosition
* @return
*/
boolean insertMobilePosition(MobilePosition mobilePosition);
/**
* 查询移动位置轨迹
@ -260,19 +261,19 @@ public interface IVideoManagerStorager {
* @param startTime
* @param endTime
*/
public List<MobilePosition> queryMobilePositions(String deviceId, String startTime, String endTime);
List<MobilePosition> queryMobilePositions(String deviceId, String startTime, String endTime);
/**
* 查询最新移动位置
*
* @param deviceId
*/
public MobilePosition queryLatestPosition(String deviceId);
MobilePosition queryLatestPosition(String deviceId);
/**
* 删除指定设备的所有移动位置
*
* @param deviceId
*/
public int clearMobilePositionsByDeviceId(String deviceId);
int clearMobilePositionsByDeviceId(String deviceId);
}

39
src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java

@ -4,7 +4,10 @@ import com.genersoft.iot.vmp.common.RealVideo;
import com.genersoft.iot.vmp.common.StreamInfo;
import com.genersoft.iot.vmp.common.VideoManagerConstants;
import com.genersoft.iot.vmp.conf.MediaServerConfig;
import com.genersoft.iot.vmp.gb28181.bean.*;
import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatformCatch;
import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import com.genersoft.iot.vmp.storager.dao.DeviceChannelMapper;
import com.genersoft.iot.vmp.utils.redis.RedisUtil;
@ -12,9 +15,9 @@ import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
@SuppressWarnings("rawtypes")
@Component
@ -142,6 +145,28 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage {
return redis.del(key);
}
@Override
public StreamInfo queryPlaybackByDevice(String deviceId, String channelId) {
String keyByChannel = getKey(VideoManagerConstants.PLAY_BLACK_PREFIX,
null,
channelId,
deviceId
);
List<Object> playLeys = redis.scan(keyByChannel);
if (playLeys == null || playLeys.size() == 0) {
String keyByDevice = getKey(VideoManagerConstants.PLAY_BLACK_PREFIX,
null,
null,
deviceId
);
playLeys = redis.scan(keyByDevice);
}
if (playLeys == null || playLeys.size() == 0) {
return null;
}
return (StreamInfo) redis.get(playLeys.get(0).toString());
}
@Override
public StreamInfo queryPlaybackByStreamId(String channelId, String steamId) {
String key = getKey(VideoManagerConstants.PLAY_BLACK_PREFIX,
@ -211,7 +236,7 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage {
@Override
public ParentPlatformCatch queryPlatformCatchInfo(String platformGbId) {
return (ParentPlatformCatch)redis.get(VideoManagerConstants.PLATFORM_CATCH_PREFIX + platformGbId);
return (ParentPlatformCatch) redis.get(VideoManagerConstants.PLATFORM_CATCH_PREFIX + platformGbId);
}
@Override
@ -239,7 +264,7 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage {
@Override
public String queryPlatformRegisterInfo(String callId) {
return (String)redis.get(VideoManagerConstants.PLATFORM_REGISTER_INFO_PREFIX + callId);
return (String) redis.get(VideoManagerConstants.PLATFORM_REGISTER_INFO_PREFIX + callId);
}
@Override
@ -264,11 +289,12 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage {
@Override
public SendRtpItem querySendRTPServer(String platformGbId, String channelId) {
String key = VideoManagerConstants.PLATFORM_SEND_RTP_INFO_PREFIX + platformGbId + "_" + channelId;
return (SendRtpItem)redis.get(key);
return (SendRtpItem) redis.get(key);
}
/**
* 删除RTP推送信息缓存
*
* @param platformGbId
* @param channelId
*/
@ -280,6 +306,7 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage {
/**
* 查询某个通道是否存在上级点播RTP推送
*
* @param channelId
*/
@Override
@ -296,6 +323,7 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage {
/**
* 更新媒体流列表
*
* @param mediaList
*/
@Override
@ -311,6 +339,7 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage {
/**
* 获取当前媒体流列表
*
* @return List<RealVideo>
*/
@Override

719
src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStoragerImpl.java

@ -1,391 +1,388 @@
package com.genersoft.iot.vmp.storager.impl;
import java.util.*;
import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatformCatch;
import com.genersoft.iot.vmp.gb28181.bean.*;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import com.genersoft.iot.vmp.gb28181.bean.MobilePosition;
import com.genersoft.iot.vmp.storager.dao.DeviceChannelMapper;
import com.genersoft.iot.vmp.storager.dao.DeviceMapper;
import com.genersoft.iot.vmp.storager.dao.ParentPlatformMapper;
import com.genersoft.iot.vmp.storager.dao.PatformChannelMapper;
import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
import com.genersoft.iot.vmp.storager.dao.*;
import com.genersoft.iot.vmp.vmanager.platform.bean.ChannelReduce;
import com.genersoft.iot.vmp.storager.dao.DeviceMobilePositionMapper;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
import org.springframework.transaction.annotation.Transactional;
/**
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @Description:视频设备数据存储-jdbc实现
* @author: swwheihei
* @date: 2020年5月6日 下午2:31:42
* @date: 2020年5月6日 下午2:31:42
*/
@SuppressWarnings("rawtypes")
@Component
public class VideoManagerStoragerImpl implements IVideoManagerStorager {
@Autowired
@Autowired
private DeviceMapper deviceMapper;
@Autowired
private DeviceChannelMapper deviceChannelMapper;
@Autowired
private DeviceChannelMapper deviceChannelMapper;
@Autowired
private DeviceMobilePositionMapper deviceMobilePositionMapper;
@Autowired
private DeviceMobilePositionMapper deviceMobilePositionMapper;
@Autowired
@Autowired
private ParentPlatformMapper platformMapper;
@Autowired
@Autowired
private IRedisCatchStorage redisCatchStorage;
@Autowired
@Autowired
private PatformChannelMapper patformChannelMapper;
/**
* 根据设备ID判断设备是否存在
*
* @param deviceId 设备ID
* @return true:存在 false不存在
*/
@Override
public boolean exists(String deviceId) {
return deviceMapper.getDeviceByDeviceId(deviceId) != null;
}
/**
* 视频设备创建
*
* @param device 设备对象
* @return true创建成功 false创建失败
*/
@Override
public synchronized boolean create(Device device) {
return deviceMapper.add(device) > 0;
}
/**
* 视频设备更新
*
* @param device 设备对象
* @return true更新成功 false更新失败
*/
@Override
public synchronized boolean updateDevice(Device device) {
Device deviceByDeviceId = deviceMapper.getDeviceByDeviceId(device.getDeviceId());
if (deviceByDeviceId == null) {
return deviceMapper.add(device) > 0;
}else {
return deviceMapper.update(device) > 0;
}
}
@Override
public synchronized void updateChannel(String deviceId, DeviceChannel channel) {
String channelId = channel.getChannelId();
channel.setDeviceId(deviceId);
DeviceChannel deviceChannel = deviceChannelMapper.queryChannel(deviceId, channelId);
if (deviceChannel == null) {
deviceChannelMapper.add(channel);
}else {
deviceChannelMapper.update(channel);
}
}
@Override
public void startPlay(String deviceId, String channelId, String streamId) {
deviceChannelMapper.startPlay(deviceId, channelId, streamId);
}
@Override
public void stopPlay(String deviceId, String channelId) {
deviceChannelMapper.stopPlay(deviceId, channelId);
}
/**
* 获取设备
*
* @param deviceId 设备ID
* @return Device 设备对象
*/
@Override
public Device queryVideoDevice(String deviceId) {
return deviceMapper.getDeviceByDeviceId(deviceId);
}
@Override
public PageInfo queryChannelsByDeviceId(String deviceId, String query, Boolean hasSubChannel, Boolean online, int page, int count) {
// 获取到所有正在播放的流
PageHelper.startPage(page, count);
List<DeviceChannel> all = deviceChannelMapper.queryChannelsByDeviceId(deviceId, null, query, hasSubChannel, online);
return new PageInfo<>(all);
}
@Override
public List<DeviceChannel> queryChannelsByDeviceId(String deviceId) {
return deviceChannelMapper.queryChannelsByDeviceId(deviceId, null,null, null, null);
}
@Override
public PageInfo<DeviceChannel> querySubChannels(String deviceId, String parentChannelId, String query, Boolean hasSubChannel, String online, int page, int count) {
PageHelper.startPage(page, count);
List<DeviceChannel> all = deviceChannelMapper.queryChannelsByDeviceId(deviceId, parentChannelId, null, null, null);
return new PageInfo<>(all);
}
@Override
public DeviceChannel queryChannel(String deviceId, String channelId) {
return deviceChannelMapper.queryChannel(deviceId, channelId);
}
/**
* 获取多个设备
*
* @param page 当前页数
* @param count 每页数量
* @return PageInfo<Device> 分页设备对象数组
*/
@Override
public PageInfo<Device> queryVideoDeviceList(int page, int count) {
PageHelper.startPage(page, count);
List<Device> all = deviceMapper.getDevices();
return new PageInfo<>(all);
}
/**
* 获取多个设备
*
* @return List<Device> 设备对象数组
*/
@Override
public List<Device> queryVideoDeviceList() {
List<Device> deviceList = deviceMapper.getDevices();
return deviceList;
}
/**
* 删除设备
*
* @param deviceId 设备ID
* @return true删除成功 false删除失败
*/
@Override
public boolean delete(String deviceId) {
int result = deviceMapper.del(deviceId);
return result > 0;
}
/**
* 更新设备在线
*
* @param deviceId 设备ID
* @return true更新成功 false更新失败
*/
@Override
public synchronized boolean online(String deviceId) {
Device device = deviceMapper.getDeviceByDeviceId(deviceId);
if (device == null) {
return false;
}
device.setOnline(1);
System.out.println("更新设备在线");
return deviceMapper.update(device) > 0;
}
/**
* 更新设备离线
*
* @param deviceId 设备ID
* @return true更新成功 false更新失败
*/
@Override
public synchronized boolean outline(String deviceId) {
Device device = deviceMapper.getDeviceByDeviceId(deviceId);
device.setOnline(0);
System.out.println("更新设备离线");
return deviceMapper.update(device) > 0;
}
/**
* 清空通道
* @param deviceId
*/
@Override
public void cleanChannelsForDevice(String deviceId) {
deviceChannelMapper.cleanChannelsByDeviceId(deviceId);
}
/**
* 添加Mobile Position设备移动位置
* @param MobilePosition
*/
@Override
public synchronized boolean insertMobilePosition(MobilePosition mobilePosition) {
return deviceMobilePositionMapper.insertNewPosition(mobilePosition) > 0;
}
/**
* 查询移动位置轨迹
* @param deviceId
* @param startTime
* @param endTime
*/
@Override
public synchronized List<MobilePosition> queryMobilePositions(String deviceId, String startTime, String endTime) {
return deviceMobilePositionMapper.queryPositionByDeviceIdAndTime(deviceId, startTime, endTime);
}
@Override
public boolean addParentPlatform(ParentPlatform parentPlatform) {
int result = platformMapper.addParentPlatform(parentPlatform);
return result > 0;
}
@Override
public boolean updateParentPlatform(ParentPlatform parentPlatform) {
int result = 0;
ParentPlatformCatch parentPlatformCatch = redisCatchStorage.queryPlatformCatchInfo(parentPlatform.getServerGBId()); // .getDeviceGBId());
if ( platformMapper.getParentPlatById(parentPlatform.getServerGBId()) == null) {
result = platformMapper.addParentPlatform(parentPlatform);
if (parentPlatformCatch == null) {
parentPlatformCatch = new ParentPlatformCatch();
parentPlatformCatch.setParentPlatform(parentPlatform);
parentPlatformCatch.setId(parentPlatform.getServerGBId());
}
}else {
result = platformMapper.updateParentPlatform(parentPlatform);
}
// 更新缓存
parentPlatformCatch.setParentPlatform(parentPlatform);
redisCatchStorage.updatePlatformCatchInfo(parentPlatformCatch);
return result > 0;
}
@Transactional
@Override
public boolean deleteParentPlatform(ParentPlatform parentPlatform) {
int result = platformMapper.delParentPlatform(parentPlatform);
// 删除关联的通道
patformChannelMapper.cleanChannelForGB(parentPlatform.getServerGBId());
return result > 0;
}
@Override
public PageInfo<ParentPlatform> queryParentPlatformList(int page, int count) {
PageHelper.startPage(page, count);
List<ParentPlatform> all = platformMapper.getParentPlatformList();
return new PageInfo<>(all);
}
@Override
public ParentPlatform queryParentPlatById(String platformGbId) {
return platformMapper.getParentPlatById(platformGbId);
}
@Override
public List<ParentPlatform> queryEnableParentPlatformList(boolean enable) {
return platformMapper.getEnableParentPlatformList(enable);
}
@Override
public void outlineForAllParentPlatform() {
platformMapper.outlineForAllParentPlatform();
}
@Override
public PageInfo<ChannelReduce> queryAllChannelList(int page, int count, String query, Boolean online,
Boolean channelType, String platformId, Boolean inPlatform) {
PageHelper.startPage(page, count);
List<ChannelReduce> all = deviceChannelMapper.queryChannelListInAll(query, online, channelType, platformId, inPlatform);
return new PageInfo<>(all);
}
@Override
public List<ChannelReduce> queryChannelListInParentPlatform(String platformId) {
return deviceChannelMapper.queryChannelListInAll(null, null, null, platformId, true);
}
@Override
public int updateChannelForGB(String platformId, List<ChannelReduce> channelReduces) {
Map<String, ChannelReduce> deviceAndChannels = new HashMap<>();
for (ChannelReduce channelReduce : channelReduces) {
deviceAndChannels.put(channelReduce.getDeviceId() + "_" + channelReduce.getChannelId(), channelReduce);
}
List<String> deviceAndChannelList = new ArrayList<>(deviceAndChannels.keySet());
// 查询当前已经存在的
List<String> relatedPlatformchannels = patformChannelMapper.findChannelRelatedPlatform(platformId, deviceAndChannelList);
if (relatedPlatformchannels != null) {
deviceAndChannelList.removeAll(relatedPlatformchannels);
}
for (String relatedPlatformchannel : relatedPlatformchannels) {
deviceAndChannels.remove(relatedPlatformchannel);
}
List<ChannelReduce> channelReducesToAdd = new ArrayList<>(deviceAndChannels.values());
// 对剩下的数据进行存储
int result = 0;
if (channelReducesToAdd.size() > 0) {
result = patformChannelMapper.addChannels(platformId, channelReducesToAdd);
}
return result;
}
@Override
public int delChannelForGB(String platformId, List<ChannelReduce> channelReduces) {
int result = patformChannelMapper.delChannelForGB(platformId, channelReduces);
return result;
}
@Override
public DeviceChannel queryChannelInParentPlatform(String platformId, String channelId) {
DeviceChannel channel = patformChannelMapper.queryChannelInParentPlatform(platformId, channelId);
return channel;
}
@Override
public Device queryVideoDeviceByPlatformIdAndChannelId(String platformId, String channelId) {
Device device = patformChannelMapper.queryVideoDeviceByPlatformIdAndChannelId(platformId, channelId);
return device;
}
/**
* 查询最新移动位置
* @param deviceId
*/
@Override
public MobilePosition queryLatestPosition(String deviceId) {
return deviceMobilePositionMapper.queryLatestPositionByDevice(deviceId);
}
/**
* 删除指定设备的所有移动位置
* @param deviceId
*/
public int clearMobilePositionsByDeviceId(String deviceId) {
return deviceMobilePositionMapper.clearMobilePositionsByDeviceId(deviceId);
}
/**
* 根据设备ID判断设备是否存在
*
* @param deviceId 设备ID
* @return true:存在 false不存在
*/
@Override
public boolean exists(String deviceId) {
return deviceMapper.getDeviceByDeviceId(deviceId) != null;
}
/**
* 视频设备创建
*
* @param device 设备对象
* @return true创建成功 false创建失败
*/
@Override
public synchronized boolean create(Device device) {
return deviceMapper.add(device) > 0;
}
/**
* 视频设备更新
*
* @param device 设备对象
* @return true更新成功 false更新失败
*/
@Override
public synchronized boolean updateDevice(Device device) {
Device deviceByDeviceId = deviceMapper.getDeviceByDeviceId(device.getDeviceId());
if (deviceByDeviceId == null) {
return deviceMapper.add(device) > 0;
} else {
return deviceMapper.update(device) > 0;
}
}
@Override
public synchronized void updateChannel(String deviceId, DeviceChannel channel) {
String channelId = channel.getChannelId();
channel.setDeviceId(deviceId);
DeviceChannel deviceChannel = deviceChannelMapper.queryChannel(deviceId, channelId);
if (deviceChannel == null) {
deviceChannelMapper.add(channel);
} else {
deviceChannelMapper.update(channel);
}
}
@Override
public void startPlay(String deviceId, String channelId, String streamId) {
deviceChannelMapper.startPlay(deviceId, channelId, streamId);
}
@Override
public void stopPlay(String deviceId, String channelId) {
deviceChannelMapper.stopPlay(deviceId, channelId);
}
/**
* 获取设备
*
* @param deviceId 设备ID
* @return Device 设备对象
*/
@Override
public Device queryVideoDevice(String deviceId) {
return deviceMapper.getDeviceByDeviceId(deviceId);
}
@Override
public PageInfo queryChannelsByDeviceId(String deviceId, String query, Boolean hasSubChannel, Boolean online, int page, int count) {
// 获取到所有正在播放的流
PageHelper.startPage(page, count);
List<DeviceChannel> all = deviceChannelMapper.queryChannelsByDeviceId(deviceId, null, query, hasSubChannel, online);
return new PageInfo<>(all);
}
@Override
public List<DeviceChannel> queryChannelsByDeviceId(String deviceId) {
return deviceChannelMapper.queryChannelsByDeviceId(deviceId, null, null, null, null);
}
@Override
public PageInfo<DeviceChannel> querySubChannels(String deviceId, String parentChannelId, String query, Boolean hasSubChannel, String online, int page, int count) {
PageHelper.startPage(page, count);
List<DeviceChannel> all = deviceChannelMapper.queryChannelsByDeviceId(deviceId, parentChannelId, null, null, null);
return new PageInfo<>(all);
}
@Override
public DeviceChannel queryChannel(String deviceId, String channelId) {
return deviceChannelMapper.queryChannel(deviceId, channelId);
}
/**
* 获取多个设备
*
* @param page 当前页数
* @param count 每页数量
* @return PageInfo<Device> 分页设备对象数组
*/
@Override
public PageInfo<Device> queryVideoDeviceList(int page, int count) {
PageHelper.startPage(page, count);
List<Device> all = deviceMapper.getDevices();
return new PageInfo<>(all);
}
/**
* 获取多个设备
*
* @return List<Device> 设备对象数组
*/
@Override
public List<Device> queryVideoDeviceList() {
List<Device> deviceList = deviceMapper.getDevices();
return deviceList;
}
/**
* 删除设备
*
* @param deviceId 设备ID
* @return true删除成功 false删除失败
*/
@Override
public boolean delete(String deviceId) {
int result = deviceMapper.del(deviceId);
return result > 0;
}
/**
* 更新设备在线
*
* @param deviceId 设备ID
* @return true更新成功 false更新失败
*/
@Override
public synchronized boolean online(String deviceId) {
Device device = deviceMapper.getDeviceByDeviceId(deviceId);
if (device == null) {
return false;
}
device.setOnline(1);
System.out.println("更新设备在线");
return deviceMapper.update(device) > 0;
}
/**
* 更新设备离线
*
* @param deviceId 设备ID
* @return true更新成功 false更新失败
*/
@Override
public synchronized boolean outline(String deviceId) {
Device device = deviceMapper.getDeviceByDeviceId(deviceId);
device.setOnline(0);
System.out.println("更新设备离线");
return deviceMapper.update(device) > 0;
}
/**
* 清空通道
*
* @param deviceId
*/
@Override
public void cleanChannelsForDevice(String deviceId) {
deviceChannelMapper.cleanChannelsByDeviceId(deviceId);
}
/**
* 添加Mobile Position设备移动位置
*
* @param mobilePosition
*/
@Override
public synchronized boolean insertMobilePosition(MobilePosition mobilePosition) {
return deviceMobilePositionMapper.insertNewPosition(mobilePosition) > 0;
}
/**
* 查询移动位置轨迹
*
* @param deviceId
* @param startTime
* @param endTime
*/
@Override
public synchronized List<MobilePosition> queryMobilePositions(String deviceId, String startTime, String endTime) {
return deviceMobilePositionMapper.queryPositionByDeviceIdAndTime(deviceId, startTime, endTime);
}
@Override
public boolean addParentPlatform(ParentPlatform parentPlatform) {
int result = platformMapper.addParentPlatform(parentPlatform);
return result > 0;
}
@Override
public boolean updateParentPlatform(ParentPlatform parentPlatform) {
int result = 0;
ParentPlatformCatch parentPlatformCatch = redisCatchStorage.queryPlatformCatchInfo(parentPlatform.getServerGBId()); // .getDeviceGBId());
if (platformMapper.getParentPlatById(parentPlatform.getServerGBId()) == null) {
result = platformMapper.addParentPlatform(parentPlatform);
if (parentPlatformCatch == null) {
parentPlatformCatch = new ParentPlatformCatch();
parentPlatformCatch.setParentPlatform(parentPlatform);
parentPlatformCatch.setId(parentPlatform.getServerGBId());
}
} else {
result = platformMapper.updateParentPlatform(parentPlatform);
}
// 更新缓存
parentPlatformCatch.setParentPlatform(parentPlatform);
redisCatchStorage.updatePlatformCatchInfo(parentPlatformCatch);
return result > 0;
}
@Transactional
@Override
public boolean deleteParentPlatform(ParentPlatform parentPlatform) {
int result = platformMapper.delParentPlatform(parentPlatform);
// 删除关联的通道
patformChannelMapper.cleanChannelForGB(parentPlatform.getServerGBId());
return result > 0;
}
@Override
public PageInfo<ParentPlatform> queryParentPlatformList(int page, int count) {
PageHelper.startPage(page, count);
List<ParentPlatform> all = platformMapper.getParentPlatformList();
return new PageInfo<>(all);
}
@Override
public ParentPlatform queryParentPlatById(String platformGbId) {
return platformMapper.getParentPlatById(platformGbId);
}
@Override
public List<ParentPlatform> queryEnableParentPlatformList(boolean enable) {
return platformMapper.getEnableParentPlatformList(enable);
}
@Override
public void outlineForAllParentPlatform() {
platformMapper.outlineForAllParentPlatform();
}
@Override
public PageInfo<ChannelReduce> queryAllChannelList(int page, int count, String query, Boolean online,
Boolean channelType, String platformId, Boolean inPlatform) {
PageHelper.startPage(page, count);
List<ChannelReduce> all = deviceChannelMapper.queryChannelListInAll(query, online, channelType, platformId, inPlatform);
return new PageInfo<>(all);
}
@Override
public List<ChannelReduce> queryChannelListInParentPlatform(String platformId) {
return deviceChannelMapper.queryChannelListInAll(null, null, null, platformId, true);
}
@Override
public int updateChannelForGB(String platformId, List<ChannelReduce> channelReduces) {
Map<String, ChannelReduce> deviceAndChannels = new HashMap<>();
for (ChannelReduce channelReduce : channelReduces) {
deviceAndChannels.put(channelReduce.getDeviceId() + "_" + channelReduce.getChannelId(), channelReduce);
}
List<String> deviceAndChannelList = new ArrayList<>(deviceAndChannels.keySet());
// 查询当前已经存在的
List<String> relatedPlatformchannels = patformChannelMapper.findChannelRelatedPlatform(platformId, deviceAndChannelList);
if (relatedPlatformchannels != null) {
deviceAndChannelList.removeAll(relatedPlatformchannels);
}
for (String relatedPlatformchannel : relatedPlatformchannels) {
deviceAndChannels.remove(relatedPlatformchannel);
}
List<ChannelReduce> channelReducesToAdd = new ArrayList<>(deviceAndChannels.values());
// 对剩下的数据进行存储
int result = 0;
if (channelReducesToAdd.size() > 0) {
result = patformChannelMapper.addChannels(platformId, channelReducesToAdd);
}
return result;
}
@Override
public int delChannelForGB(String platformId, List<ChannelReduce> channelReduces) {
int result = patformChannelMapper.delChannelForGB(platformId, channelReduces);
return result;
}
@Override
public DeviceChannel queryChannelInParentPlatform(String platformId, String channelId) {
DeviceChannel channel = patformChannelMapper.queryChannelInParentPlatform(platformId, channelId);
return channel;
}
@Override
public Device queryVideoDeviceByPlatformIdAndChannelId(String platformId, String channelId) {
Device device = patformChannelMapper.queryVideoDeviceByPlatformIdAndChannelId(platformId, channelId);
return device;
}
/**
* 查询最新移动位置
*
* @param deviceId
*/
@Override
public MobilePosition queryLatestPosition(String deviceId) {
return deviceMobilePositionMapper.queryLatestPositionByDevice(deviceId);
}
/**
* 删除指定设备的所有移动位置
*
* @param deviceId
*/
@Override
public int clearMobilePositionsByDeviceId(String deviceId) {
return deviceMobilePositionMapper.clearMobilePositionsByDeviceId(deviceId);
}
}

20
src/main/java/com/genersoft/iot/vmp/utils/redis/RedisUtil.java

@ -420,7 +420,7 @@ public class RedisUtil {
* @param value
* @param score
*/
public void zAdd(String key, String value, double score) {
public void zAdd(Object key, Object value, double score) {
redisTemplate.opsForZSet().add(key, value, score);
}
@ -430,7 +430,7 @@ public class RedisUtil {
* @param key
* @param value
*/
public void zRemove(String key, String value) {
public void zRemove(Object key, Object value) {
redisTemplate.opsForZSet().remove(key, value);
}
@ -441,7 +441,7 @@ public class RedisUtil {
* @param value
* @param score
*/
public Double zIncrScore(String key, String value, double score) {
public Double zIncrScore(Object key, Object value, double score) {
return redisTemplate.opsForZSet().incrementScore(key, value, score);
}
@ -452,7 +452,7 @@ public class RedisUtil {
* @param value
* @return
*/
public Double zScore(String key, String value) {
public Double zScore(Object key, Object value) {
return redisTemplate.opsForZSet().score(key, value);
}
@ -463,7 +463,7 @@ public class RedisUtil {
* @param value
* @return
*/
public Long zRank(String key, String value) {
public Long zRank(Object key, Object value) {
return redisTemplate.opsForZSet().rank(key, value);
}
@ -473,7 +473,7 @@ public class RedisUtil {
* @param key
* @return
*/
public Long zSize(String key) {
public Long zSize(Object key) {
return redisTemplate.opsForZSet().zCard(key);
}
@ -487,7 +487,7 @@ public class RedisUtil {
* @param end
* @return
*/
public Set<String> ZRange(String key, int start, int end) {
public Set<Object> ZRange(Object key, int start, int end) {
return redisTemplate.opsForZSet().range(key, start, end);
}
@ -499,7 +499,7 @@ public class RedisUtil {
* @param end
* @return
*/
public Set<ZSetOperations.TypedTuple<String>> zRangeWithScore(String key, int start, int end) {
public Set<ZSetOperations.TypedTuple<String>> zRangeWithScore(Object key, int start, int end) {
return redisTemplate.opsForZSet().rangeWithScores(key, start, end);
}
@ -513,7 +513,7 @@ public class RedisUtil {
* @param end
* @return
*/
public Set<String> zRevRange(String key, int start, int end) {
public Set<String> zRevRange(Object key, int start, int end) {
return redisTemplate.opsForZSet().reverseRange(key, start, end);
}
@ -525,7 +525,7 @@ public class RedisUtil {
* @param max
* @return
*/
public Set<String> zSortRange(String key, int min, int max) {
public Set<String> zSortRange(Object key, int min, int max) {
return redisTemplate.opsForZSet().rangeByScore(key, min, max);
}

146
src/main/java/com/genersoft/iot/vmp/vmanager/play/PlayController.java

@ -1,19 +1,16 @@
package com.genersoft.iot.vmp.vmanager.play;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.genersoft.iot.vmp.common.StreamInfo;
import com.genersoft.iot.vmp.conf.MediaServerConfig;
import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
import com.genersoft.iot.vmp.vmanager.play.bean.PlayResult;
import com.genersoft.iot.vmp.vmanager.service.IPlayService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -21,20 +18,8 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.alibaba.fastjson.JSONObject;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
import org.springframework.web.context.request.async.DeferredResult;
import java.util.UUID;
import javax.sip.message.Response;
@CrossOrigin
@ -68,66 +53,7 @@ public class PlayController {
@GetMapping("/play/{deviceId}/{channelId}")
public DeferredResult<ResponseEntity<String>> play(@PathVariable String deviceId,
@PathVariable String channelId) {
Device device = storager.queryVideoDevice(deviceId);
RequestMessage msg = playService.createCallbackPlayMsg();
DeferredResult<ResponseEntity<String>> result = new DeferredResult<>();
// 超时处理
result.onTimeout(() -> {
logger.warn(String.format("设备点播超时,deviceId:%s ,channelId:%s", deviceId, channelId));
// 释放rtpserver
cmder.closeRTPServer(device, channelId);
StreamInfo streamInfo = streamSession.getPlayStreamInfo(channelId);
streamSession.remove(streamInfo);
msg.setData("Timeout");
resultHolder.invokeResult(msg);
});
resultHolder.put(msg.getId(), result);
// 判断是否已经存在点播
StreamInfo oldStreamInfo = streamSession.getPlayStreamInfo(channelId);
if (oldStreamInfo == null) {
// 发送点播消息
playStreamCmd(device, channelId, msg);
return result;
}
// 若已有人点播,直接播放
String streamId = oldStreamInfo.getStreamId();
String mediaServerIp = oldStreamInfo.getMediaServerIp();
JSONObject rtpInfo = zlmresTfulUtils.getRtpInfo(mediaServerIp, streamId);
if (rtpInfo.getBoolean("exist")) {
msg.setData(JSON.toJSONString(oldStreamInfo));
resultHolder.invokeResult(msg);
return result;
}
// 若已有人点播,但已超时自动断开,则重新发起点播
storager.stopPlay(oldStreamInfo.getDeviceID(), oldStreamInfo.getChannelId());
streamSession.remove(oldStreamInfo);
playStreamCmd(device, channelId, msg);
return result;
}
private void playStreamCmd(Device device, String channelId, RequestMessage msg) {
cmder.playStreamCmd(device, channelId, (JSONObject response) -> {
logger.info("收到点播回调消息: " + response.toJSONString());
playService.onPublishHandlerForPlay(response, device.getDeviceId(), channelId, msg);
}, event -> {
StreamInfo streamInfo = streamSession.getPlayStreamInfo(channelId);
streamSession.remove(streamInfo);
Response response = event.getResponse();
int statusCode = response.getStatusCode();
String errMsg;
if (503 == statusCode) {
errMsg = "点播失败,请检查在NVR上是否可以正常打开监控,并检查NVR和SIP是否连通, 错误码: %s, %s";
} else {
errMsg = "点播失败,错误码: %s, %s";
}
msg.setData(String.format(errMsg, statusCode, response.getReasonPhrase()));
resultHolder.invokeResult(msg);
});
return playService.play(deviceId, channelId, null, null);
}
@PostMapping("/play/{channelId}/{streamId}/stop")
@ -232,15 +158,15 @@ public class PlayController {
result.put("msg", "success");
} else {
}
}else {
result.put("code", 1);
result.put("msg", "delFFmpegSource fail");
}
return new ResponseEntity<String>( result.toJSONString(), HttpStatus.OK);
}
}
} else {
result.put("code", 1);
result.put("msg", "delFFmpegSource fail");
}
return new ResponseEntity<String>(result.toJSONString(), HttpStatus.OK);
}
/**
/**
* 语音广播命令API接口
*
* @param deviceId
@ -252,34 +178,34 @@ public class PlayController {
logger.debug("语音广播API调用");
}
Device device = storager.queryVideoDevice(deviceId);
cmder.audioBroadcastCmd(device, event -> {
Response response = event.getResponse();
RequestMessage msg = new RequestMessage();
msg.setId(DeferredResultHolder.CALLBACK_CMD_BROADCAST + deviceId);
JSONObject json = new JSONObject();
json.put("DeviceID", deviceId);
json.put("CmdType", "Broadcast");
json.put("Result", "Failed");
json.put("Description", String.format("语音广播操作失败,错误码: %s, %s", response.getStatusCode(), response.getReasonPhrase()));
msg.setData(json);
resultHolder.invokeResult(msg);
});
cmder.audioBroadcastCmd(device, event -> {
Response response = event.getResponse();
RequestMessage msg = new RequestMessage();
msg.setId(DeferredResultHolder.CALLBACK_CMD_BROADCAST + deviceId);
JSONObject json = new JSONObject();
json.put("DeviceID", deviceId);
json.put("CmdType", "Broadcast");
json.put("Result", "Failed");
json.put("Description", String.format("语音广播操作失败,错误码: %s, %s", response.getStatusCode(), response.getReasonPhrase()));
msg.setData(json);
resultHolder.invokeResult(msg);
});
DeferredResult<ResponseEntity<String>> result = new DeferredResult<ResponseEntity<String>>(3 * 1000L);
result.onTimeout(() -> {
logger.warn(String.format("语音广播操作超时, 设备未返回应答指令"));
RequestMessage msg = new RequestMessage();
msg.setId(DeferredResultHolder.CALLBACK_CMD_BROADCAST + deviceId);
JSONObject json = new JSONObject();
json.put("DeviceID", deviceId);
json.put("CmdType", "Broadcast");
json.put("Result", "Failed");
json.put("Error", "Timeout. Device did not response to broadcast command.");
msg.setData(json);
resultHolder.invokeResult(msg);
});
resultHolder.put(DeferredResultHolder.CALLBACK_CMD_BROADCAST + deviceId, result);
return result;
}
result.onTimeout(() -> {
logger.warn(String.format("语音广播操作超时, 设备未返回应答指令"));
RequestMessage msg = new RequestMessage();
msg.setId(DeferredResultHolder.CALLBACK_CMD_BROADCAST + deviceId);
JSONObject json = new JSONObject();
json.put("DeviceID", deviceId);
json.put("CmdType", "Broadcast");
json.put("Result", "Failed");
json.put("Error", "Timeout. Device did not response to broadcast command.");
msg.setData(json);
resultHolder.invokeResult(msg);
});
resultHolder.put(DeferredResultHolder.CALLBACK_CMD_BROADCAST + deviceId, result);
return result;
}
}

37
src/main/java/com/genersoft/iot/vmp/vmanager/play/bean/PlayResult.java

@ -1,37 +0,0 @@
package com.genersoft.iot.vmp.vmanager.play.bean;
import com.genersoft.iot.vmp.gb28181.bean.Device;
import org.springframework.http.ResponseEntity;
import org.springframework.web.context.request.async.DeferredResult;
public class PlayResult {
private DeferredResult<ResponseEntity<String>> result;
private String uuid;
private Device device;
public DeferredResult<ResponseEntity<String>> getResult() {
return result;
}
public void setResult(DeferredResult<ResponseEntity<String>> result) {
this.result = result;
}
public String getUuid() {
return uuid;
}
public void setUuid(String uuid) {
this.uuid = uuid;
}
public Device getDevice() {
return device;
}
public void setDevice(Device device) {
this.device = device;
}
}

7
src/main/java/com/genersoft/iot/vmp/vmanager/service/IPlayService.java

@ -1,10 +1,11 @@
package com.genersoft.iot.vmp.vmanager.service;
import com.alibaba.fastjson.JSONObject;
import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe;
import com.genersoft.iot.vmp.vmanager.play.bean.PlayResult;
import org.springframework.http.ResponseEntity;
import org.springframework.web.context.request.async.DeferredResult;
/**
* 点播处理
@ -16,5 +17,5 @@ public interface IPlayService {
void onPublishHandlerForPlay(JSONObject resonse, String deviceId, String channelId, RequestMessage msg);
PlayResult play(String deviceId, String channelId, ZLMHttpHookSubscribe.Event event, SipSubscribe.Event errorEvent);
DeferredResult<ResponseEntity<String>> play(String deviceId, String channelId, ZLMHttpHookSubscribe.Event event, SipSubscribe.Event errorEvent);
}

126
src/main/java/com/genersoft/iot/vmp/vmanager/service/impl/PlayServiceImpl.java

@ -3,7 +3,6 @@ package com.genersoft.iot.vmp.vmanager.service.impl;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.genersoft.iot.vmp.common.StreamInfo;
import com.genersoft.iot.vmp.conf.MediaServerConfig;
import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
@ -15,7 +14,6 @@ import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe;
import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
import com.genersoft.iot.vmp.vmanager.play.bean.PlayResult;
import com.genersoft.iot.vmp.vmanager.service.IPlayService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -27,8 +25,6 @@ import org.springframework.web.context.request.async.DeferredResult;
import javax.sip.message.Response;
import java.util.UUID;
import java.util.UUID;
@Service
public class PlayServiceImpl implements IPlayService {
@ -52,66 +48,80 @@ public class PlayServiceImpl implements IPlayService {
@Autowired
private ZLMRESTfulUtils zlmresTfulUtils;
@Override
public PlayResult play(String deviceId, String channelId, ZLMHttpHookSubscribe.Event hookEvent, SipSubscribe.Event errorEvent) {
PlayResult playResult = new PlayResult();
public DeferredResult<ResponseEntity<String>> play(String deviceId, String channelId, ZLMHttpHookSubscribe.Event hookEvent, SipSubscribe.Event errorEvent) {
Device device = storager.queryVideoDevice(deviceId);
StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(deviceId, channelId);
playResult.setDevice(device);
UUID uuid = UUID.randomUUID();
playResult.setUuid(uuid.toString());
DeferredResult<ResponseEntity<String>> result = new DeferredResult<ResponseEntity<String>>();
playResult.setResult(result);
// 录像查询以channelId作为deviceId查询
resultHolder.put(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid, result);
if (streamInfo == null) {
RequestMessage msg = this.createCallbackPlayMsg();
DeferredResult<ResponseEntity<String>> result = new DeferredResult<>();
// 超时处理
result.onTimeout(() -> {
logger.warn(String.format("设备点播超时,deviceId:%s ,channelId:%s", deviceId, channelId));
// 释放rtpserver
cmder.closeRTPServer(device, channelId);
StreamInfo streamInfo = streamSession.getPlayStreamInfo(channelId);
streamSession.remove(streamInfo);
msg.setData("Timeout");
resultHolder.invokeResult(msg);
if (errorEvent != null) {
errorEvent.response(null);
}
});
resultHolder.put(msg.getId(), result);
// 判断是否已经存在点播
StreamInfo oldStreamInfo = streamSession.getPlayStreamInfo(channelId);
if (oldStreamInfo == null) {
// 发送点播消息
cmder.playStreamCmd(device, channelId, (JSONObject response) -> {
logger.info("收到订阅消息: " + response.toJSONString());
onPublishHandlerForPlay(response, deviceId, channelId, uuid.toString());
if (hookEvent != null) {
hookEvent.response(response);
}
}, event -> {
RequestMessage msg = new RequestMessage();
msg.setId(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid);
Response response = event.getResponse();
msg.setData(String.format("点播失败, 错误码: %s, %s", response.getStatusCode(), response.getReasonPhrase()));
resultHolder.invokeResult(msg);
if (errorEvent != null) {
errorEvent.response(event);
}
});
} else {
String streamId = streamInfo.getStreamId();
JSONObject rtpInfo = zlmresTfulUtils.getRtpInfo(streamId);
if (rtpInfo.getBoolean("exist")) {
RequestMessage msg = new RequestMessage();
msg.setId(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid);
msg.setData(JSON.toJSONString(streamInfo));
resultHolder.invokeResult(msg);
if (hookEvent != null) {
hookEvent.response(JSONObject.parseObject(JSON.toJSONString(streamInfo)));
}
} else {
redisCatchStorage.stopPlay(streamInfo);
storager.stopPlay(streamInfo.getDeviceID(), streamInfo.getChannelId());
cmder.playStreamCmd(device, channelId, (JSONObject response) -> {
logger.info("收到订阅消息: " + response.toJSONString());
onPublishHandlerForPlay(response, deviceId, channelId, uuid.toString());
}, event -> {
RequestMessage msg = new RequestMessage();
msg.setId(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid);
Response response = event.getResponse();
msg.setData(String.format("点播失败, 错误码: %s, %s", response.getStatusCode(), response.getReasonPhrase()));
resultHolder.invokeResult(msg);
});
playStreamCmd(device, channelId, msg, hookEvent, errorEvent);
return result;
}
// 若已有人点播,直接播放
String streamId = oldStreamInfo.getStreamId();
String mediaServerIp = oldStreamInfo.getMediaServerIp();
JSONObject rtpInfo = zlmresTfulUtils.getRtpInfo(mediaServerIp, streamId);
if (rtpInfo.getBoolean("exist")) {
msg.setData(JSON.toJSONString(oldStreamInfo));
resultHolder.invokeResult(msg);
if (hookEvent != null) {
hookEvent.response(null);
}
return result;
}
return playResult;
// 若已有人点播,但已超时自动断开,则重新发起点播
storager.stopPlay(oldStreamInfo.getDeviceID(), oldStreamInfo.getChannelId());
streamSession.remove(oldStreamInfo);
playStreamCmd(device, channelId, msg, hookEvent, errorEvent);
return result;
}
private void playStreamCmd(Device device, String channelId, RequestMessage msg, ZLMHttpHookSubscribe.Event hookEvent, SipSubscribe.Event errorEvent) {
cmder.playStreamCmd(device, channelId, (JSONObject response) -> {
logger.info("收到点播回调消息: " + response.toJSONString());
this.onPublishHandlerForPlay(response, device.getDeviceId(), channelId, msg);
if (hookEvent != null) {
hookEvent.response(response);
}
}, event -> {
StreamInfo streamInfo = streamSession.getPlayStreamInfo(channelId);
streamSession.remove(streamInfo);
Response response = event.getResponse();
int statusCode = response.getStatusCode();
String errMsg;
if (503 == statusCode) {
errMsg = "点播失败,请检查在NVR上是否可以正常打开监控,并检查NVR和SIP是否连通, 错误码: %s, %s";
} else {
errMsg = "点播失败,错误码: %s, %s";
}
msg.setData(String.format(errMsg, statusCode, response.getReasonPhrase()));
resultHolder.invokeResult(msg);
if (errorEvent != null) {
errorEvent.response(event);
}
});
}
@Override

168
src/main/resources/application-dev.yml

@ -1,102 +1,102 @@
spring:
# REDIS数据库配置
redis:
# [必须修改] Redis服务器IP, REDIS安装在本机的,使用127.0.0.1
host: 127.0.0.1
# [必须修改] 端口号
port: 6379
# [可选] 数据库 DB
database: 6
# [可选] 访问密码,若你的redis服务器没有设置密码,就不需要用密码去连接
password:
# [可选] 超时时间
timeout: 10000
poolMaxTotal: 1000
poolMaxIdle: 50
poolMaxWait: 500
# [可选] jdbc数据库配置, 项目使用sqlite作为数据库,一般不需要配置
datasource:
# name: eiot
# url: jdbc:mysql://127.0.0.1:3306/eiot?useUnicode=true&characterEncoding=UTF8&rewriteBatchedStatements=true
# username:
# password:
# type: com.alibaba.druid.pool.DruidDataSource
# driver-class-name: com.mysql.jdbc.Driver
name: eiot
url: jdbc:sqlite::resource:wvp.sqlite
username:
password:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: org.sqlite.JDBC
max-active: 1
min-idle: 1
# REDIS数据库配置
redis:
# [必须修改] Redis服务器IP, REDIS安装在本机的,使用127.0.0.1
host: 127.0.0.1
# [必须修改] 端口号
port: 6379
# [可选] 数据库 DB
database: 6
# [可选] 访问密码,若你的redis服务器没有设置密码,就不需要用密码去连接
password: 111111
# [可选] 超时时间
timeout: 10000
poolMaxTotal: 1000
poolMaxIdle: 50
poolMaxWait: 500
# [可选] jdbc数据库配置, 项目使用sqlite作为数据库,一般不需要配置
datasource:
# name: eiot
# url: jdbc:mysql://127.0.0.1:3306/eiot?useUnicode=true&characterEncoding=UTF8&rewriteBatchedStatements=true
# username:
# password:
# type: com.alibaba.druid.pool.DruidDataSource
# driver-class-name: com.mysql.jdbc.Driver
name: eiot
url: jdbc:sqlite::resource:wvp.sqlite
username:
password:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: org.sqlite.JDBC
max-active: 1
min-idle: 1
# [可选] WVP监听的HTTP端口, 网页和接口调用都是这个端口
server:
port: 18080
port: 18080
# 作为28181服务器的配置
sip:
# [必须修改] 本机的内网IP, 必须是网卡上的IP
ip: 192.168.0.100
# [可选] 28181服务监听的端口
port: 5060
# 根据国标6.1.2中规定,domain宜采用ID统一编码的前十位编码。国标附录D中定义前8位为中心编码(由省级、市级、区级、基层编号组成,参照GB/T 2260-2007)
# 后两位为行业编码,定义参照附录D.3
# 3701020049标识山东济南历下区 信息行业接入
# [可选]
domain: 4401020049
# [可选]
id: 44010200492000000001
# [可选] 默认设备认证密码,后续扩展使用设备单独密码
password: admin123
# [必须修改] 本机的内网IP, 必须是网卡上的IP
ip: 192.168.1.105
# [可选] 28181服务监听的端口
port: 5060
# 根据国标6.1.2中规定,domain宜采用ID统一编码的前十位编码。国标附录D中定义前8位为中心编码(由省级、市级、区级、基层编号组成,参照GB/T 2260-2007)
# 后两位为行业编码,定义参照附录D.3
# 3701020049标识山东济南历下区 信息行业接入
# [可选]
domain: 4401020049
# [可选]
id: 44010200492000000001
# [可选] 默认设备认证密码,后续扩展使用设备单独密码
password: admin123
# 登陆的用户名密码
auth:
# [可选] 用户名
username: admin
# [可选] 密码, 默认为admin
password: 21232f297a57a5a743894a0e4a801fc3
# [可选] 用户名
username: admin
# [可选] 密码, 默认为admin
password: 21232f297a57a5a743894a0e4a801fc3
#zlm服务器配置
media:
# [必须修改] zlm服务器的IP(内网公网IP均可),配置多台时IP用逗号隔开
ip: 192.168.0.100
# [可选] zlm服务器的公网IP, 内网部署置空即可
wanIp:
# [可选] zlm服务器的hook所使用的IP, 默认使用sip.ip
hookIp:
# [必须修改] zlm服务器的http.port
port: 80
# [可选] 是否自动配置ZLM, 如果希望手动配置ZLM, 可以设为false, 不建议新接触的用户修改
autoConfig: true
# [可选] zlm服务器的hook.admin_params=secret
secret: 035c73f7-bb6b-4889-a715-d9eb2d1925cc
# [可选] zlm服务器的general.streamNoneReaderDelayMS
streamNoneReaderDelayMS: 18000 # 无人观看多久自动关闭流, -1表示永不自动关闭,即 关闭按需拉流
# [可选] 自动点播, 使用固定流地址进行播放时,如果未点播则自动进行点播, 需要rtp.enable=true
autoApplyPlay: false
# [可选] 部分设备需要扩展SDP,需要打开此设置
seniorSdp: false
# 启用udp多端口模式
rtp:
# [可选] 是否启用udp多端口模式, 开启后会在udpPortRange范围内选择端口用于媒体流传输
enable: true
# [可选] 在此范围内选择端口用于媒体流传输, 不只是udp, 使用TCP被动传输模式时,也是从这个范围内选择端口
udpPortRange: 30000,30500 # 端口范围
# [必须修改] zlm服务器的IP(内网公网IP均可),配置多台时IP用逗号隔开
ip: 192.168.1.105
# [可选] zlm服务器的公网IP, 内网部署置空即可
wanIp:
# [可选] zlm服务器的hook所使用的IP, 默认使用sip.ip
hookIp:
# [必须修改] zlm服务器的http.port
port: 80
# [可选] 是否自动配置ZLM, 如果希望手动配置ZLM, 可以设为false, 不建议新接触的用户修改
autoConfig: true
# [可选] zlm服务器的hook.admin_params=secret
secret: 035c73f7-bb6b-4889-a715-d9eb2d1925cc
# [可选] zlm服务器的general.streamNoneReaderDelayMS
streamNoneReaderDelayMS: 18000 # 无人观看多久自动关闭流, -1表示永不自动关闭,即 关闭按需拉流
# [可选] 自动点播, 使用固定流地址进行播放时,如果未点播则自动进行点播, 需要rtp.enable=true
autoApplyPlay: false
# [可选] 部分设备需要扩展SDP,需要打开此设置
seniorSdp: false
# 启用udp多端口模式
rtp:
# [可选] 是否启用udp多端口模式, 开启后会在udpPortRange范围内选择端口用于媒体流传输
enable: true
# [可选] 在此范围内选择端口用于媒体流传输, 不只是udp, 使用TCP被动传输模式时,也是从这个范围内选择端口
udpPortRange: 30000,30500 # 端口范围
# [可选] 日志配置, 一般不需要改
logging:
file:
name: logs/wvp.log
max-history: 30
max-size: 10MB
total-size-cap: 300MB
level:
com:
genersoft:
iot: debug
file:
name: logs/wvp.log
max-history: 30
max-size: 10MB
total-size-cap: 300MB
level:
com:
genersoft:
iot: debug
# [根据业务需求配置]
userSettings:
# 保存移动位置历史轨迹:true:保留历史数据,false:仅保留最后的位置(默认)
savePositionHistory: false
# 保存移动位置历史轨迹:true:保留历史数据,false:仅保留最后的位置(默认)
savePositionHistory: false

2
src/main/resources/application.yml

@ -1,3 +1,3 @@
spring:
profiles:
active: local
active: dev
Loading…
Cancel
Save