Commit 2e7c9a7341670d78f5a1ce061ac225b02d6f606f
Merge branch 'wvp-28181-2.0' into main-dev
# Conflicts: # pom.xml # src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderProvider.java # src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java # src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/ByeRequestProcessor.java # src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java # src/main/java/com/genersoft/iot/vmp/media/zlm/AssistRESTfulUtils.java # src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java # src/main/java/com/genersoft/iot/vmp/media/zlm/dto/HookSubscribeFactory.java # src/main/java/com/genersoft/iot/vmp/service/impl/DeviceServiceImpl.java # src/main/java/com/genersoft/iot/vmp/service/impl/MediaServerServiceImpl.java # src/main/java/com/genersoft/iot/vmp/service/impl/PlatformServiceImpl.java # src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java # src/main/java/com/genersoft/iot/vmp/storager/dao/PlatformChannelMapper.java # src/main/resources/all-application.yml # src/main/resources/application-dev.yml
Showing
70 changed files
with
2282 additions
and
1000 deletions
Too many changes to show.
To preserve performance only 70 of 144 files are displayed.
libs/jdbc-x86/bcprov-jdk15on-1.70.jar
0 → 100644
No preview for this file type
libs/jdbc-x86/kingbase8-8.6.0.jar
0 → 100644
No preview for this file type
libs/jdbc-x86/kingbase8-8.6.0.jre6.jar
0 → 100644
No preview for this file type
libs/jdbc-x86/kingbase8-8.6.0.jre7.jar
0 → 100644
No preview for this file type
libs/jdbc-x86/postgresql-42.2.9.jar
0 → 100644
No preview for this file type
libs/jdbc-x86/postgresql-42.2.9.jre6.jar
0 → 100644
No preview for this file type
libs/jdbc-x86/postgresql-42.2.9.jre7.jar
0 → 100644
No preview for this file type
pom.xml
| 1 | <?xml version="1.0"?> | 1 | <?xml version="1.0"?> |
| 2 | -<project | ||
| 3 | - xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" | ||
| 4 | - xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> | ||
| 5 | - <modelVersion>4.0.0</modelVersion> | ||
| 6 | - <parent> | ||
| 7 | - <groupId>org.springframework.boot</groupId> | ||
| 8 | - <artifactId>spring-boot-starter-parent</artifactId> | ||
| 9 | - <version>2.7.9</version> | ||
| 10 | - </parent> | ||
| 11 | - | ||
| 12 | - <groupId>com.genersoft</groupId> | ||
| 13 | - <artifactId>wvp-pro</artifactId> | ||
| 14 | - <version>2.6.9</version> | ||
| 15 | - <name>web video platform</name> | ||
| 16 | - <description>国标28181视频平台</description> | ||
| 17 | - <packaging>${project.packaging}</packaging> | ||
| 18 | - | ||
| 19 | - <repositories> | ||
| 20 | - <repository> | ||
| 21 | - <id>nexus-aliyun</id> | ||
| 22 | - <name>Nexus aliyun</name> | ||
| 23 | - <url>https://maven.aliyun.com/repository/public</url> | ||
| 24 | - <layout>default</layout> | ||
| 25 | - <snapshots> | ||
| 26 | - <enabled>false</enabled> | ||
| 27 | - </snapshots> | ||
| 28 | - <releases> | ||
| 29 | - <enabled>true</enabled> | ||
| 30 | - </releases> | ||
| 31 | - </repository> | ||
| 32 | - </repositories> | ||
| 33 | - <pluginRepositories> | ||
| 34 | - <pluginRepository> | ||
| 35 | - <id>nexus-aliyun</id> | ||
| 36 | - <name>Nexus aliyun</name> | ||
| 37 | - <url>https://maven.aliyun.com/repository/public</url> | ||
| 38 | - <snapshots> | ||
| 39 | - <enabled>false</enabled> | ||
| 40 | - </snapshots> | ||
| 41 | - <releases> | ||
| 42 | - <enabled>true</enabled> | ||
| 43 | - </releases> | ||
| 44 | - </pluginRepository> | ||
| 45 | - </pluginRepositories> | ||
| 46 | - | ||
| 47 | - <properties> | ||
| 48 | - <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> | ||
| 49 | - <maven.build.timestamp.format>MMddHHmm</maven.build.timestamp.format> | ||
| 50 | - <maven-jar-plugin.version>3.1.1</maven-jar-plugin.version> | ||
| 51 | - | ||
| 52 | - <!-- 依赖版本 --> | ||
| 53 | - <snippetsDirectory>${project.build.directory}/generated-snippets</snippetsDirectory> | ||
| 54 | - <asciidoctor.input.directory>${project.basedir}/docs/asciidoc</asciidoctor.input.directory> | ||
| 55 | - <generated.asciidoc.directory>${project.build.directory}/asciidoc</generated.asciidoc.directory> | ||
| 56 | - <asciidoctor.html.output.directory>${project.build.directory}/asciidoc/html</asciidoctor.html.output.directory> | ||
| 57 | - <asciidoctor.pdf.output.directory>${project.build.directory}/asciidoc/pdf</asciidoctor.pdf.output.directory> | ||
| 58 | - </properties> | ||
| 59 | - | ||
| 60 | - <profiles> | ||
| 61 | - <profile> | ||
| 62 | - <id>jar</id> | ||
| 63 | - <activation> | ||
| 64 | - <activeByDefault>true</activeByDefault> | ||
| 65 | - </activation> | ||
| 66 | - <properties> | ||
| 67 | - <project.packaging>jar</project.packaging> | ||
| 68 | - </properties> | ||
| 69 | - </profile> | ||
| 70 | - <profile> | ||
| 71 | - <id>war</id> | ||
| 72 | - <properties> | ||
| 73 | - <project.packaging>war</project.packaging> | ||
| 74 | - </properties> | ||
| 75 | - <dependencies> | ||
| 76 | - <dependency> | ||
| 77 | - <groupId>org.springframework.boot</groupId> | ||
| 78 | - <artifactId>spring-boot-starter-web</artifactId> | ||
| 79 | - <exclusions> | ||
| 80 | - <exclusion> | ||
| 81 | - <groupId>org.springframework.boot</groupId> | ||
| 82 | - <artifactId>spring-boot-starter-jetty</artifactId> | ||
| 83 | - </exclusion> | ||
| 84 | - </exclusions> | ||
| 85 | - </dependency> | ||
| 86 | - <dependency> | ||
| 87 | - <groupId>javax.servlet</groupId> | ||
| 88 | - <artifactId>javax.servlet-api</artifactId> | ||
| 89 | - <version>3.1.0</version> | ||
| 90 | - <scope>provided</scope> | ||
| 91 | - </dependency> | ||
| 92 | - </dependencies> | ||
| 93 | - </profile> | ||
| 94 | - </profiles> | ||
| 95 | - | ||
| 96 | - <dependencies> | ||
| 97 | - <dependency> | ||
| 98 | - <groupId>org.springframework.boot</groupId> | ||
| 99 | - <artifactId>spring-boot-starter-data-redis</artifactId> | ||
| 100 | - </dependency> | ||
| 101 | - <dependency> | ||
| 102 | - <groupId>org.springframework.boot</groupId> | ||
| 103 | - <artifactId>spring-boot-starter-web</artifactId> | ||
| 104 | - </dependency> | ||
| 105 | - <dependency> | ||
| 106 | - <groupId>org.springframework.boot</groupId> | ||
| 107 | - <artifactId>spring-boot-configuration-processor</artifactId> | ||
| 108 | - <optional>true</optional> | ||
| 109 | - </dependency> | ||
| 110 | - <dependency> | ||
| 111 | - <groupId>org.mybatis.spring.boot</groupId> | ||
| 112 | - <artifactId>mybatis-spring-boot-starter</artifactId> | ||
| 113 | - <version>2.2.2</version> | ||
| 114 | - <exclusions> | ||
| 115 | - <exclusion> | ||
| 116 | - <groupId>com.zaxxer</groupId> | ||
| 117 | - <artifactId>HikariCP</artifactId> | ||
| 118 | - </exclusion> | ||
| 119 | - </exclusions> | ||
| 120 | - </dependency> | ||
| 121 | - <dependency> | ||
| 122 | - <groupId>org.springframework.boot</groupId> | ||
| 123 | - <artifactId>spring-boot-starter-security</artifactId> | ||
| 124 | - </dependency> | ||
| 125 | - | ||
| 126 | - <dependency> | ||
| 127 | - <groupId>org.springframework.boot</groupId> | ||
| 128 | - <artifactId>spring-boot-starter-jdbc</artifactId> | ||
| 129 | - </dependency> | ||
| 130 | - | ||
| 131 | - <!-- mysql数据库 --> | ||
| 132 | - <dependency> | ||
| 133 | - <groupId>mysql</groupId> | ||
| 134 | - <artifactId>mysql-connector-java</artifactId> | ||
| 135 | - <version>8.0.30</version> | ||
| 136 | - </dependency> | ||
| 137 | - | ||
| 138 | - <!--postgresql--> | ||
| 139 | - <dependency> | ||
| 140 | - <groupId>org.postgresql</groupId> | ||
| 141 | - <artifactId>postgresql</artifactId> | ||
| 142 | - <version>42.5.1</version> | ||
| 143 | - </dependency> | 2 | +<project |
| 3 | + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" | ||
| 4 | + xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> | ||
| 5 | + <modelVersion>4.0.0</modelVersion> | ||
| 6 | + <parent> | ||
| 7 | + <groupId>org.springframework.boot</groupId> | ||
| 8 | + <artifactId>spring-boot-starter-parent</artifactId> | ||
| 9 | + <version>2.7.17</version> | ||
| 10 | + </parent> | ||
| 11 | + | ||
| 12 | + <groupId>com.genersoft</groupId> | ||
| 13 | + <artifactId>wvp-pro</artifactId> | ||
| 14 | + <version>2.7.0</version> | ||
| 15 | + <name>web video platform</name> | ||
| 16 | + <description>国标28181视频平台</description> | ||
| 17 | + <packaging>${project.packaging}</packaging> | ||
| 18 | + | ||
| 19 | + <repositories> | ||
| 20 | + <repository> | ||
| 21 | + <id>nexus-aliyun</id> | ||
| 22 | + <name>Nexus aliyun</name> | ||
| 23 | + <url>https://maven.aliyun.com/repository/public</url> | ||
| 24 | + <layout>default</layout> | ||
| 25 | + <snapshots> | ||
| 26 | + <enabled>false</enabled> | ||
| 27 | + </snapshots> | ||
| 28 | + <releases> | ||
| 29 | + <enabled>true</enabled> | ||
| 30 | + </releases> | ||
| 31 | + </repository> | ||
| 32 | + </repositories> | ||
| 33 | + | ||
| 34 | + <pluginRepositories> | ||
| 35 | + <pluginRepository> | ||
| 36 | + <id>nexus-aliyun</id> | ||
| 37 | + <name>Nexus aliyun</name> | ||
| 38 | + <url>https://maven.aliyun.com/repository/public</url> | ||
| 39 | + <snapshots> | ||
| 40 | + <enabled>false</enabled> | ||
| 41 | + </snapshots> | ||
| 42 | + <releases> | ||
| 43 | + <enabled>true</enabled> | ||
| 44 | + </releases> | ||
| 45 | + </pluginRepository> | ||
| 46 | + </pluginRepositories> | ||
| 47 | + | ||
| 48 | + <properties> | ||
| 49 | + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> | ||
| 50 | + <maven.build.timestamp.format>MMddHHmm</maven.build.timestamp.format> | ||
| 51 | + <maven-jar-plugin.version>3.1.1</maven-jar-plugin.version> | ||
| 52 | + | ||
| 53 | + <!-- 依赖版本 --> | ||
| 54 | + <snippetsDirectory>${project.build.directory}/generated-snippets</snippetsDirectory> | ||
| 55 | + <asciidoctor.input.directory>${project.basedir}/docs/asciidoc</asciidoctor.input.directory> | ||
| 56 | + <generated.asciidoc.directory>${project.build.directory}/asciidoc</generated.asciidoc.directory> | ||
| 57 | + <asciidoctor.html.output.directory>${project.build.directory}/asciidoc/html</asciidoctor.html.output.directory> | ||
| 58 | + <asciidoctor.pdf.output.directory>${project.build.directory}/asciidoc/pdf</asciidoctor.pdf.output.directory> | ||
| 59 | + </properties> | ||
| 60 | + | ||
| 61 | + <profiles> | ||
| 62 | + <profile> | ||
| 63 | + <id>jar</id> | ||
| 64 | + <activation> | ||
| 65 | + <activeByDefault>true</activeByDefault> | ||
| 66 | + </activation> | ||
| 67 | + <properties> | ||
| 68 | + <project.packaging>jar</project.packaging> | ||
| 69 | + </properties> | ||
| 70 | + </profile> | ||
| 71 | + <profile> | ||
| 72 | + <id>war</id> | ||
| 73 | + <properties> | ||
| 74 | + <project.packaging>war</project.packaging> | ||
| 75 | + </properties> | ||
| 76 | + <dependencies> | ||
| 77 | + <dependency> | ||
| 78 | + <groupId>org.springframework.boot</groupId> | ||
| 79 | + <artifactId>spring-boot-starter-web</artifactId> | ||
| 80 | + <exclusions> | ||
| 81 | + <exclusion> | ||
| 82 | + <groupId>org.springframework.boot</groupId> | ||
| 83 | + <artifactId>spring-boot-starter-jetty</artifactId> | ||
| 84 | + </exclusion> | ||
| 85 | + </exclusions> | ||
| 86 | + </dependency> | ||
| 87 | + <dependency> | ||
| 88 | + <groupId>javax.servlet</groupId> | ||
| 89 | + <artifactId>javax.servlet-api</artifactId> | ||
| 90 | + <version>3.1.0</version> | ||
| 91 | + <scope>provided</scope> | ||
| 92 | + </dependency> | ||
| 93 | + </dependencies> | ||
| 94 | + </profile> | ||
| 95 | + </profiles> | ||
| 96 | + | ||
| 97 | + <dependencies> | ||
| 98 | + <dependency> | ||
| 99 | + <groupId>org.springframework.boot</groupId> | ||
| 100 | + <artifactId>spring-boot-starter-data-redis</artifactId> | ||
| 101 | + </dependency> | ||
| 102 | + <dependency> | ||
| 103 | + <groupId>org.springframework.boot</groupId> | ||
| 104 | + <artifactId>spring-boot-starter-web</artifactId> | ||
| 105 | + </dependency> | ||
| 106 | + <dependency> | ||
| 107 | + <groupId>org.springframework.boot</groupId> | ||
| 108 | + <artifactId>spring-boot-configuration-processor</artifactId> | ||
| 109 | + <optional>true</optional> | ||
| 110 | + </dependency> | ||
| 111 | + <dependency> | ||
| 112 | + <groupId>org.mybatis.spring.boot</groupId> | ||
| 113 | + <artifactId>mybatis-spring-boot-starter</artifactId> | ||
| 114 | + <version>2.2.2</version> | ||
| 115 | + <exclusions> | ||
| 116 | + <exclusion> | ||
| 117 | + <groupId>com.zaxxer</groupId> | ||
| 118 | + <artifactId>HikariCP</artifactId> | ||
| 119 | + </exclusion> | ||
| 120 | + </exclusions> | ||
| 121 | + </dependency> | ||
| 122 | + <dependency> | ||
| 123 | + <groupId>org.springframework.boot</groupId> | ||
| 124 | + <artifactId>spring-boot-starter-security</artifactId> | ||
| 125 | + </dependency> | ||
| 126 | + | ||
| 127 | + <dependency> | ||
| 128 | + <groupId>org.springframework.boot</groupId> | ||
| 129 | + <artifactId>spring-boot-starter-jdbc</artifactId> | ||
| 130 | + </dependency> | ||
| 131 | + | ||
| 132 | + <!-- mysql数据库 --> | ||
| 133 | + <dependency> | ||
| 134 | + <groupId>com.mysql</groupId> | ||
| 135 | + <artifactId>mysql-connector-j</artifactId> | ||
| 136 | + <version>8.2.0</version> | ||
| 137 | + </dependency> | ||
| 138 | + | ||
| 139 | + <!--postgresql--> | ||
| 140 | + <dependency> | ||
| 141 | + <groupId>org.postgresql</groupId> | ||
| 142 | + <artifactId>postgresql</artifactId> | ||
| 143 | + <version>42.5.1</version> | ||
| 144 | + </dependency> | ||
| 144 | 145 | ||
| 145 | <!-- kingbase人大金仓 --> | 146 | <!-- kingbase人大金仓 --> |
| 146 | <!-- 手动下载驱动后安装 --> | 147 | <!-- 手动下载驱动后安装 --> |
| @@ -153,14 +154,41 @@ | @@ -153,14 +154,41 @@ | ||
| 153 | <scope>system</scope> | 154 | <scope>system</scope> |
| 154 | <systemPath>${basedir}/libs/jdbc-aarch/kingbase8-8.6.0.jar</systemPath> | 155 | <systemPath>${basedir}/libs/jdbc-aarch/kingbase8-8.6.0.jar</systemPath> |
| 155 | </dependency> | 156 | </dependency> |
| 157 | + <dependency> | ||
| 158 | + <groupId>com.kingbase</groupId> | ||
| 159 | + <artifactId>kingbase8</artifactId> | ||
| 160 | + <version>8.6.0</version> | ||
| 161 | + <scope>system</scope> | ||
| 162 | + <systemPath>${basedir}/libs/jdbc-x86/kingbase8-8.6.0.jar</systemPath> | ||
| 163 | + </dependency> | ||
| 156 | 164 | ||
| 157 | - <!--Mybatis分页插件 --> | 165 | + <!--Mybatis分页插件 --> |
| 166 | + <dependency> | ||
| 167 | + <groupId>com.github.pagehelper</groupId> | ||
| 168 | + <artifactId>pagehelper-spring-boot-starter</artifactId> | ||
| 169 | + <version>1.4.6</version> | ||
| 170 | + </dependency> | ||
| 171 | + | ||
| 172 | + <!--在线文档 --> | ||
| 173 | + <!--在线文档 --> | ||
| 174 | + <dependency> | ||
| 175 | + <groupId>org.springdoc</groupId> | ||
| 176 | + <artifactId>springdoc-openapi-ui</artifactId> | ||
| 177 | + <version>1.6.10</version> | ||
| 178 | + </dependency> | ||
| 179 | + <dependency> | ||
| 180 | + <groupId>org.springdoc</groupId> | ||
| 181 | + <artifactId>springdoc-openapi-security</artifactId> | ||
| 182 | + <version>1.6.10</version> | ||
| 183 | + </dependency> | ||
| 184 | + <!-- https://mvnrepository.com/artifact/com.baomidou/dynamic-datasource-spring-boot-starter --> | ||
| 158 | <dependency> | 185 | <dependency> |
| 159 | - <groupId>com.github.pagehelper</groupId> | ||
| 160 | - <artifactId>pagehelper-spring-boot-starter</artifactId> | ||
| 161 | - <version>1.4.6</version> | 186 | + <groupId>com.baomidou</groupId> |
| 187 | + <artifactId>dynamic-datasource-spring-boot-starter</artifactId> | ||
| 188 | + <version>3.6.1</version> | ||
| 162 | </dependency> | 189 | </dependency> |
| 163 | 190 | ||
| 191 | + | ||
| 164 | <!--在线文档 --> | 192 | <!--在线文档 --> |
| 165 | <dependency> | 193 | <dependency> |
| 166 | <groupId>org.springdoc</groupId> | 194 | <groupId>org.springdoc</groupId> |
| @@ -168,199 +196,203 @@ | @@ -168,199 +196,203 @@ | ||
| 168 | <version>1.6.10</version> | 196 | <version>1.6.10</version> |
| 169 | </dependency> | 197 | </dependency> |
| 170 | 198 | ||
| 171 | - <dependency> | ||
| 172 | - <groupId>com.github.xiaoymin</groupId> | ||
| 173 | - <artifactId>knife4j-springdoc-ui</artifactId> | ||
| 174 | - <version>3.0.3</version> | ||
| 175 | - </dependency> | ||
| 176 | - | ||
| 177 | - <!--参数校验 --> | ||
| 178 | - <dependency> | ||
| 179 | - <groupId>javax.validation</groupId> | ||
| 180 | - <artifactId>validation-api</artifactId> | ||
| 181 | - </dependency> | ||
| 182 | - | ||
| 183 | - <!-- 日志相关 --> | ||
| 184 | - <dependency> | ||
| 185 | - <groupId>org.springframework.boot</groupId> | ||
| 186 | - <artifactId>spring-boot-starter-aop</artifactId> | ||
| 187 | - </dependency> | ||
| 188 | - | ||
| 189 | - <!-- sip协议栈 --> | ||
| 190 | - <dependency> | ||
| 191 | - <groupId>javax.sip</groupId> | ||
| 192 | - <artifactId>jain-sip-ri</artifactId> | ||
| 193 | - <version>1.3.0-91</version> | ||
| 194 | - </dependency> | ||
| 195 | - | ||
| 196 | - <!-- 取代log4j --> | ||
| 197 | - <dependency> | ||
| 198 | - <groupId>org.slf4j</groupId> | ||
| 199 | - <artifactId>log4j-over-slf4j</artifactId> | ||
| 200 | - <version>1.7.36</version> | ||
| 201 | - </dependency> | ||
| 202 | - | ||
| 203 | - <!-- xml解析库 --> | ||
| 204 | - <dependency> | ||
| 205 | - <groupId>org.dom4j</groupId> | ||
| 206 | - <artifactId>dom4j</artifactId> | ||
| 207 | - <version>2.1.3</version> | ||
| 208 | - </dependency> | ||
| 209 | - | ||
| 210 | - <dependency> | ||
| 211 | - <groupId>com.google.guava</groupId> | ||
| 212 | - <artifactId>guava</artifactId> | ||
| 213 | - <version>20.0</version> | ||
| 214 | - </dependency> | ||
| 215 | - | ||
| 216 | - <!-- json解析库fastjson2 --> | ||
| 217 | - <dependency> | ||
| 218 | - <groupId>com.alibaba.fastjson2</groupId> | ||
| 219 | - <artifactId>fastjson2</artifactId> | ||
| 220 | - <version>2.0.17</version> | ||
| 221 | - </dependency> | ||
| 222 | - <dependency> | ||
| 223 | - <groupId>com.alibaba.fastjson2</groupId> | ||
| 224 | - <artifactId>fastjson2-extension</artifactId> | ||
| 225 | - <version>2.0.17</version> | ||
| 226 | - </dependency> | ||
| 227 | - | ||
| 228 | - <!-- okhttp --> | ||
| 229 | - <dependency> | ||
| 230 | - <groupId>com.squareup.okhttp3</groupId> | ||
| 231 | - <artifactId>okhttp</artifactId> | ||
| 232 | - <version>4.10.0</version> | ||
| 233 | - </dependency> | ||
| 234 | - | ||
| 235 | - <!-- okhttp 调试日志 --> | ||
| 236 | - <dependency> | ||
| 237 | - <groupId>com.squareup.okhttp3</groupId> | ||
| 238 | - <artifactId>logging-interceptor</artifactId> | ||
| 239 | - <version>4.10.0</version> | ||
| 240 | - </dependency> | ||
| 241 | - | ||
| 242 | - <!-- okhttp-digest --> | ||
| 243 | - <dependency> | ||
| 244 | - <groupId>io.github.rburgst</groupId> | ||
| 245 | - <artifactId>okhttp-digest</artifactId> | ||
| 246 | - <version>2.7</version> | ||
| 247 | - </dependency> | ||
| 248 | - | ||
| 249 | - <!-- https://mvnrepository.com/artifact/net.sf.kxml/kxml2 --> | ||
| 250 | -<!-- <dependency>--> | ||
| 251 | -<!-- <groupId>net.sf.kxml</groupId>--> | ||
| 252 | -<!-- <artifactId>kxml2</artifactId>--> | ||
| 253 | -<!-- <version>2.3.0</version>--> | ||
| 254 | -<!-- </dependency>--> | ||
| 255 | - | ||
| 256 | - <!-- jwt实现 --> | ||
| 257 | - <dependency> | ||
| 258 | - <groupId>org.bitbucket.b_c</groupId> | ||
| 259 | - <artifactId>jose4j</artifactId> | ||
| 260 | - <version>0.9.3</version> | ||
| 261 | - </dependency> | ||
| 262 | - | ||
| 263 | - <!--反向代理--> | ||
| 264 | - <dependency> | ||
| 265 | - <groupId>org.mitre.dsmiley.httpproxy</groupId> | ||
| 266 | - <artifactId>smiley-http-proxy-servlet</artifactId> | ||
| 267 | - <version>1.12.1</version> | ||
| 268 | - </dependency> | ||
| 269 | - | ||
| 270 | - <!--excel解析库--> | ||
| 271 | - <dependency> | ||
| 272 | - <groupId>com.alibaba</groupId> | ||
| 273 | - <artifactId>easyexcel</artifactId> | ||
| 274 | - <version>3.1.1</version> | ||
| 275 | - </dependency> | ||
| 276 | - | ||
| 277 | - <!-- 获取系统信息 --> | ||
| 278 | - <dependency> | ||
| 279 | - <groupId>com.github.oshi</groupId> | ||
| 280 | - <artifactId>oshi-core</artifactId> | ||
| 281 | - <version>6.2.2</version> | ||
| 282 | - </dependency> | ||
| 283 | - | ||
| 284 | - <dependency> | ||
| 285 | - <groupId>org.springframework.session</groupId> | ||
| 286 | - <artifactId>spring-session-core</artifactId> | ||
| 287 | - </dependency> | ||
| 288 | - | ||
| 289 | -<!-- <!– 检测文件编码 –>--> | ||
| 290 | -<!-- <!– https://mvnrepository.com/artifact/cpdetector/cpdetector –>--> | ||
| 291 | -<!-- <dependency>--> | ||
| 292 | -<!-- <groupId>cpdetector</groupId>--> | ||
| 293 | -<!-- <artifactId>cpdetector</artifactId>--> | ||
| 294 | -<!-- <version>1.0.8</version>--> | ||
| 295 | -<!-- </dependency>--> | ||
| 296 | - | ||
| 297 | - <!-- https://mvnrepository.com/artifact/com.google.guava/guava --> | ||
| 298 | - <dependency> | ||
| 299 | - <groupId>com.google.guava</groupId> | ||
| 300 | - <artifactId>guava</artifactId> | ||
| 301 | - <version>31.1-jre</version> | ||
| 302 | - </dependency> | ||
| 303 | - | ||
| 304 | - | ||
| 305 | - <dependency> | ||
| 306 | - <groupId>org.springframework.boot</groupId> | ||
| 307 | - <artifactId>spring-boot-starter-test</artifactId> | ||
| 308 | -<!-- <scope>test</scope>--> | ||
| 309 | - </dependency> | ||
| 310 | - | ||
| 311 | - </dependencies> | ||
| 312 | - | ||
| 313 | - | ||
| 314 | - <build> | ||
| 315 | - <finalName>${project.artifactId}-${project.version}-${maven.build.timestamp}</finalName> | ||
| 316 | - <plugins> | ||
| 317 | - <plugin> | ||
| 318 | - <groupId>org.springframework.boot</groupId> | ||
| 319 | - <artifactId>spring-boot-maven-plugin</artifactId> | ||
| 320 | - <version>2.7.2</version> | ||
| 321 | - <configuration> | ||
| 322 | - <includeSystemScope>true</includeSystemScope> | ||
| 323 | - </configuration> | ||
| 324 | - </plugin> | ||
| 325 | - <plugin> | ||
| 326 | - <groupId>org.apache.maven.plugins</groupId> | ||
| 327 | - <artifactId>maven-compiler-plugin</artifactId> | ||
| 328 | - <version>3.8.1</version> | ||
| 329 | - <configuration> | ||
| 330 | - <source>1.8</source> | ||
| 331 | - <target>1.8</target> | ||
| 332 | - </configuration> | ||
| 333 | - </plugin> | ||
| 334 | - | ||
| 335 | - <plugin> | ||
| 336 | - <groupId>pl.project13.maven</groupId> | ||
| 337 | - <artifactId>git-commit-id-plugin</artifactId> | ||
| 338 | - <version>3.0.1</version> | ||
| 339 | - <configuration> | ||
| 340 | - <offline>true</offline> | ||
| 341 | - <failOnNoGitDirectory>false</failOnNoGitDirectory> | ||
| 342 | - <dateFormat>yyyyMMdd</dateFormat> | ||
| 343 | - </configuration> | ||
| 344 | - </plugin> | ||
| 345 | - <plugin> | ||
| 346 | - <groupId>org.apache.maven.plugins</groupId> | ||
| 347 | - <artifactId>maven-surefire-plugin</artifactId> | ||
| 348 | - <version>2.22.2</version> | ||
| 349 | - <configuration> | ||
| 350 | - <skipTests>true</skipTests> | ||
| 351 | - </configuration> | ||
| 352 | - </plugin> | ||
| 353 | - </plugins> | ||
| 354 | - <resources> | ||
| 355 | - <resource> | ||
| 356 | - <directory>src/main/resources</directory> | ||
| 357 | - </resource> | ||
| 358 | - <resource> | ||
| 359 | - <directory>src/main/java</directory> | ||
| 360 | - <includes> | ||
| 361 | - <include>**/*.xml</include> | ||
| 362 | - </includes> | ||
| 363 | - </resource> | ||
| 364 | - </resources> | ||
| 365 | - </build> | 199 | + <dependency> |
| 200 | + <groupId>com.github.xiaoymin</groupId> | ||
| 201 | + <artifactId>knife4j-springdoc-ui</artifactId> | ||
| 202 | + <version>3.0.3</version> | ||
| 203 | + </dependency> | ||
| 204 | + | ||
| 205 | + <!--参数校验 --> | ||
| 206 | + <dependency> | ||
| 207 | + <groupId>javax.validation</groupId> | ||
| 208 | + <artifactId>validation-api</artifactId> | ||
| 209 | + </dependency> | ||
| 210 | + | ||
| 211 | + <!-- 日志相关 --> | ||
| 212 | + <dependency> | ||
| 213 | + <groupId>org.springframework.boot</groupId> | ||
| 214 | + <artifactId>spring-boot-starter-aop</artifactId> | ||
| 215 | + </dependency> | ||
| 216 | + | ||
| 217 | + <!-- sip协议栈 --> | ||
| 218 | + <dependency> | ||
| 219 | + <groupId>javax.sip</groupId> | ||
| 220 | + <artifactId>jain-sip-ri</artifactId> | ||
| 221 | + <version>1.3.0-91</version> | ||
| 222 | + </dependency> | ||
| 223 | + | ||
| 224 | + <!-- 取代log4j --> | ||
| 225 | + <dependency> | ||
| 226 | + <groupId>org.slf4j</groupId> | ||
| 227 | + <artifactId>log4j-over-slf4j</artifactId> | ||
| 228 | + <version>1.7.36</version> | ||
| 229 | + </dependency> | ||
| 230 | + | ||
| 231 | + <!-- xml解析库 --> | ||
| 232 | + <dependency> | ||
| 233 | + <groupId>org.dom4j</groupId> | ||
| 234 | + <artifactId>dom4j</artifactId> | ||
| 235 | + <version>2.1.3</version> | ||
| 236 | + </dependency> | ||
| 237 | + | ||
| 238 | + <!-- json解析库fastjson2 --> | ||
| 239 | + <dependency> | ||
| 240 | + <groupId>com.alibaba.fastjson2</groupId> | ||
| 241 | + <artifactId>fastjson2</artifactId> | ||
| 242 | + <version>2.0.17</version> | ||
| 243 | + </dependency> | ||
| 244 | + <dependency> | ||
| 245 | + <groupId>com.alibaba.fastjson2</groupId> | ||
| 246 | + <artifactId>fastjson2-extension</artifactId> | ||
| 247 | + <version>2.0.17</version> | ||
| 248 | + </dependency> | ||
| 249 | + | ||
| 250 | + <!-- okhttp --> | ||
| 251 | + <dependency> | ||
| 252 | + <groupId>com.squareup.okhttp3</groupId> | ||
| 253 | + <artifactId>okhttp</artifactId> | ||
| 254 | + <version>4.10.0</version> | ||
| 255 | + </dependency> | ||
| 256 | + | ||
| 257 | + <!-- okhttp 调试日志 --> | ||
| 258 | + <dependency> | ||
| 259 | + <groupId>com.squareup.okhttp3</groupId> | ||
| 260 | + <artifactId>logging-interceptor</artifactId> | ||
| 261 | + <version>4.10.0</version> | ||
| 262 | + </dependency> | ||
| 263 | + | ||
| 264 | + <!-- okhttp-digest --> | ||
| 265 | + <dependency> | ||
| 266 | + <groupId>io.github.rburgst</groupId> | ||
| 267 | + <artifactId>okhttp-digest</artifactId> | ||
| 268 | + <version>2.7</version> | ||
| 269 | + </dependency> | ||
| 270 | + | ||
| 271 | + <!-- https://mvnrepository.com/artifact/net.sf.kxml/kxml2 --> | ||
| 272 | + <!-- <dependency>--> | ||
| 273 | + <!-- <groupId>net.sf.kxml</groupId>--> | ||
| 274 | + <!-- <artifactId>kxml2</artifactId>--> | ||
| 275 | + <!-- <version>2.3.0</version>--> | ||
| 276 | + <!-- </dependency>--> | ||
| 277 | + | ||
| 278 | + <!-- jwt实现 --> | ||
| 279 | + <dependency> | ||
| 280 | + <groupId>org.bitbucket.b_c</groupId> | ||
| 281 | + <artifactId>jose4j</artifactId> | ||
| 282 | + <version>0.9.3</version> | ||
| 283 | + </dependency> | ||
| 284 | + | ||
| 285 | + <!--反向代理--> | ||
| 286 | + <dependency> | ||
| 287 | + <groupId>org.mitre.dsmiley.httpproxy</groupId> | ||
| 288 | + <artifactId>smiley-http-proxy-servlet</artifactId> | ||
| 289 | + <version>1.12.1</version> | ||
| 290 | + </dependency> | ||
| 291 | + | ||
| 292 | + <!--excel解析库--> | ||
| 293 | + <dependency> | ||
| 294 | + <groupId>com.alibaba</groupId> | ||
| 295 | + <artifactId>easyexcel</artifactId> | ||
| 296 | + <version>3.3.2</version> | ||
| 297 | + <exclusions> | ||
| 298 | + <exclusion> | ||
| 299 | + <groupId>org.apache.commons</groupId> | ||
| 300 | + <artifactId>commons-compress</artifactId> | ||
| 301 | + </exclusion> | ||
| 302 | + </exclusions> | ||
| 303 | + </dependency> | ||
| 304 | + <dependency> | ||
| 305 | + <groupId>org.apache.commons</groupId> | ||
| 306 | + <artifactId>commons-compress</artifactId> | ||
| 307 | + <version>1.24.0</version> | ||
| 308 | + </dependency> | ||
| 309 | + | ||
| 310 | + <!-- 获取系统信息 --> | ||
| 311 | + <dependency> | ||
| 312 | + <groupId>com.github.oshi</groupId> | ||
| 313 | + <artifactId>oshi-core</artifactId> | ||
| 314 | + <version>6.2.2</version> | ||
| 315 | + </dependency> | ||
| 316 | + | ||
| 317 | + <dependency> | ||
| 318 | + <groupId>org.springframework.session</groupId> | ||
| 319 | + <artifactId>spring-session-core</artifactId> | ||
| 320 | + </dependency> | ||
| 321 | + | ||
| 322 | + <!-- 检测文件编码 --> | ||
| 323 | + <!-- https://mvnrepository.com/artifact/cpdetector/cpdetector --> | ||
| 324 | + <!--<dependency>--> | ||
| 325 | + <!-- <groupId>cpdetector</groupId>--> | ||
| 326 | + <!-- <artifactId>cpdetector</artifactId>--> | ||
| 327 | + <!-- <version>1.0.8</version>--> | ||
| 328 | + <!--</dependency>--> | ||
| 329 | + | ||
| 330 | + <!-- https://mvnrepository.com/artifact/com.google.guava/guava --> | ||
| 331 | + <dependency> | ||
| 332 | + <groupId>com.google.guava</groupId> | ||
| 333 | + <artifactId>guava</artifactId> | ||
| 334 | + <version>32.1.3-jre</version> | ||
| 335 | + </dependency> | ||
| 336 | + | ||
| 337 | + <dependency> | ||
| 338 | + <groupId>org.springframework.boot</groupId> | ||
| 339 | + <artifactId>spring-boot-starter-test</artifactId> | ||
| 340 | + <scope>test</scope> | ||
| 341 | + </dependency> | ||
| 342 | + </dependencies> | ||
| 343 | + | ||
| 344 | + <build> | ||
| 345 | + <finalName>${project.artifactId}-${project.version}-${maven.build.timestamp}</finalName> | ||
| 346 | + <plugins> | ||
| 347 | + <plugin> | ||
| 348 | + <groupId>org.springframework.boot</groupId> | ||
| 349 | + <artifactId>spring-boot-maven-plugin</artifactId> | ||
| 350 | + <version>2.7.2</version> | ||
| 351 | + <configuration> | ||
| 352 | + <includeSystemScope>true</includeSystemScope> | ||
| 353 | + </configuration> | ||
| 354 | + </plugin> | ||
| 355 | + | ||
| 356 | + <plugin> | ||
| 357 | + <groupId>org.apache.maven.plugins</groupId> | ||
| 358 | + <artifactId>maven-compiler-plugin</artifactId> | ||
| 359 | + <version>3.8.1</version> | ||
| 360 | + <configuration> | ||
| 361 | + <source>1.8</source> | ||
| 362 | + <target>1.8</target> | ||
| 363 | + </configuration> | ||
| 364 | + </plugin> | ||
| 365 | + | ||
| 366 | + <plugin> | ||
| 367 | + <groupId>pl.project13.maven</groupId> | ||
| 368 | + <artifactId>git-commit-id-plugin</artifactId> | ||
| 369 | + <version>3.0.1</version> | ||
| 370 | + <configuration> | ||
| 371 | + <offline>true</offline> | ||
| 372 | + <failOnNoGitDirectory>false</failOnNoGitDirectory> | ||
| 373 | + <dateFormat>yyyyMMdd</dateFormat> | ||
| 374 | + </configuration> | ||
| 375 | + </plugin> | ||
| 376 | + | ||
| 377 | + <plugin> | ||
| 378 | + <groupId>org.apache.maven.plugins</groupId> | ||
| 379 | + <artifactId>maven-surefire-plugin</artifactId> | ||
| 380 | + <version>2.22.2</version> | ||
| 381 | + <configuration> | ||
| 382 | + <skipTests>true</skipTests> | ||
| 383 | + </configuration> | ||
| 384 | + </plugin> | ||
| 385 | + </plugins> | ||
| 386 | + <resources> | ||
| 387 | + <resource> | ||
| 388 | + <directory>src/main/resources</directory> | ||
| 389 | + </resource> | ||
| 390 | + <resource> | ||
| 391 | + <directory>src/main/java</directory> | ||
| 392 | + <includes> | ||
| 393 | + <include>**/*.xml</include> | ||
| 394 | + </includes> | ||
| 395 | + </resource> | ||
| 396 | + </resources> | ||
| 397 | + </build> | ||
| 366 | </project> | 398 | </project> |
sql/2.6.9更新.sql deleted
100644 → 0
src/main/java/com/genersoft/iot/vmp/common/StreamInfo.java
| 1 | package com.genersoft.iot.vmp.common; | 1 | package com.genersoft.iot.vmp.common; |
| 2 | 2 | ||
| 3 | +import com.genersoft.iot.vmp.service.bean.DownloadFileInfo; | ||
| 3 | import io.swagger.v3.oas.annotations.media.Schema; | 4 | import io.swagger.v3.oas.annotations.media.Schema; |
| 4 | 5 | ||
| 5 | import java.io.Serializable; | 6 | import java.io.Serializable; |
| @@ -76,6 +77,8 @@ public class StreamInfo implements Serializable, Cloneable{ | @@ -76,6 +77,8 @@ public class StreamInfo implements Serializable, Cloneable{ | ||
| 76 | private String endTime; | 77 | private String endTime; |
| 77 | @Schema(description = "进度(录像下载使用)") | 78 | @Schema(description = "进度(录像下载使用)") |
| 78 | private double progress; | 79 | private double progress; |
| 80 | + @Schema(description = "文件下载地址(录像下载使用)") | ||
| 81 | + private DownloadFileInfo downLoadFilePath; | ||
| 79 | 82 | ||
| 80 | @Schema(description = "是否暂停(录像回放使用)") | 83 | @Schema(description = "是否暂停(录像回放使用)") |
| 81 | private boolean pause; | 84 | private boolean pause; |
| @@ -605,5 +608,11 @@ public class StreamInfo implements Serializable, Cloneable{ | @@ -605,5 +608,11 @@ public class StreamInfo implements Serializable, Cloneable{ | ||
| 605 | this.subStream = subStream; | 608 | this.subStream = subStream; |
| 606 | } | 609 | } |
| 607 | 610 | ||
| 611 | + public DownloadFileInfo getDownLoadFilePath() { | ||
| 612 | + return downLoadFilePath; | ||
| 613 | + } | ||
| 608 | 614 | ||
| 615 | + public void setDownLoadFilePath(DownloadFileInfo downLoadFilePath) { | ||
| 616 | + this.downLoadFilePath = downLoadFilePath; | ||
| 617 | + } | ||
| 609 | } | 618 | } |
src/main/java/com/genersoft/iot/vmp/common/VideoManagerConstants.java
| @@ -53,7 +53,7 @@ public class VideoManagerConstants { | @@ -53,7 +53,7 @@ public class VideoManagerConstants { | ||
| 53 | 53 | ||
| 54 | public static final String MEDIA_TRANSACTION_USED_PREFIX = "VMP_MEDIA_TRANSACTION_"; | 54 | public static final String MEDIA_TRANSACTION_USED_PREFIX = "VMP_MEDIA_TRANSACTION_"; |
| 55 | 55 | ||
| 56 | - public static final String MEDIA_STREAM_AUTHORITY = "MEDIA_STREAM_AUTHORITY_"; | 56 | + public static final String MEDIA_STREAM_AUTHORITY = "VMP_MEDIA_STREAM_AUTHORITY_"; |
| 57 | 57 | ||
| 58 | public static final String SIP_CSEQ_PREFIX = "VMP_SIP_CSEQ_"; | 58 | public static final String SIP_CSEQ_PREFIX = "VMP_SIP_CSEQ_"; |
| 59 | 59 | ||
| @@ -71,6 +71,7 @@ public class VideoManagerConstants { | @@ -71,6 +71,7 @@ public class VideoManagerConstants { | ||
| 71 | public static final String BROADCAST_WAITE_INVITE = "task_broadcast_waite_invite_"; | 71 | public static final String BROADCAST_WAITE_INVITE = "task_broadcast_waite_invite_"; |
| 72 | 72 | ||
| 73 | public static final String REGISTER_EXPIRE_TASK_KEY_PREFIX = "VMP_device_register_expire_"; | 73 | public static final String REGISTER_EXPIRE_TASK_KEY_PREFIX = "VMP_device_register_expire_"; |
| 74 | + public static final String PUSH_STREAM_LIST = "VMP_PUSH_STREAM_LIST_"; | ||
| 74 | 75 | ||
| 75 | 76 | ||
| 76 | 77 |
src/main/java/com/genersoft/iot/vmp/conf/CloudRecordTimer.java
0 → 100644
| 1 | +package com.genersoft.iot.vmp.conf; | ||
| 2 | + | ||
| 3 | + | ||
| 4 | +import com.alibaba.fastjson2.JSONObject; | ||
| 5 | +import com.genersoft.iot.vmp.media.zlm.AssistRESTfulUtils; | ||
| 6 | +import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils; | ||
| 7 | +import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; | ||
| 8 | +import com.genersoft.iot.vmp.service.IMediaServerService; | ||
| 9 | +import com.genersoft.iot.vmp.service.bean.CloudRecordItem; | ||
| 10 | +import com.genersoft.iot.vmp.storager.dao.CloudRecordServiceMapper; | ||
| 11 | +import com.genersoft.iot.vmp.vmanager.cloudRecord.CloudRecordController; | ||
| 12 | +import org.slf4j.Logger; | ||
| 13 | +import org.slf4j.LoggerFactory; | ||
| 14 | +import org.springframework.beans.factory.annotation.Autowired; | ||
| 15 | +import org.springframework.scheduling.annotation.Scheduled; | ||
| 16 | +import org.springframework.stereotype.Component; | ||
| 17 | + | ||
| 18 | +import java.io.File; | ||
| 19 | +import java.util.ArrayList; | ||
| 20 | +import java.util.Calendar; | ||
| 21 | +import java.util.Date; | ||
| 22 | +import java.util.List; | ||
| 23 | + | ||
| 24 | +/** | ||
| 25 | + * 录像文件定时删除 | ||
| 26 | + */ | ||
| 27 | +@Component | ||
| 28 | +public class CloudRecordTimer { | ||
| 29 | + | ||
| 30 | + private final static Logger logger = LoggerFactory.getLogger(CloudRecordTimer.class); | ||
| 31 | + | ||
| 32 | + @Autowired | ||
| 33 | + private IMediaServerService mediaServerService; | ||
| 34 | + | ||
| 35 | + @Autowired | ||
| 36 | + private CloudRecordServiceMapper cloudRecordServiceMapper; | ||
| 37 | + | ||
| 38 | + @Autowired | ||
| 39 | + private ZLMRESTfulUtils zlmresTfulUtils; | ||
| 40 | + | ||
| 41 | + /** | ||
| 42 | + * 定时查询待删除的录像文件 | ||
| 43 | + */ | ||
| 44 | +// @Scheduled(fixedRate = 10000) //每五秒执行一次,方便测试 | ||
| 45 | + @Scheduled(cron = "0 0 0 * * ?") //每天的0点执行 | ||
| 46 | + public void execute(){ | ||
| 47 | + logger.info("[录像文件定时清理] 开始清理过期录像文件"); | ||
| 48 | + // 获取配置了assist的流媒体节点 | ||
| 49 | + List<MediaServerItem> mediaServerItemList = mediaServerService.getAllOnline(); | ||
| 50 | + if (mediaServerItemList.isEmpty()) { | ||
| 51 | + return; | ||
| 52 | + } | ||
| 53 | + long result = 0; | ||
| 54 | + for (MediaServerItem mediaServerItem : mediaServerItemList) { | ||
| 55 | + | ||
| 56 | + Calendar lastCalendar = Calendar.getInstance(); | ||
| 57 | + if (mediaServerItem.getRecordDay() > 0) { | ||
| 58 | + lastCalendar.setTime(new Date()); | ||
| 59 | + // 获取保存的最后截至日[期,因为每个节点都有一个日期,也就是支持每个节点设置不同的保存日期, | ||
| 60 | + lastCalendar.add(Calendar.DAY_OF_MONTH, -mediaServerItem.getRecordDay()); | ||
| 61 | + Long lastDate = lastCalendar.getTimeInMillis(); | ||
| 62 | + | ||
| 63 | + // 获取到截至日期之前的录像文件列表,文件列表满足未被收藏和保持的。这两个字段目前共能一致, | ||
| 64 | + // 为我自己业务系统相关的代码,大家使用的时候直接使用收藏(collect)这一个类型即可 | ||
| 65 | + List<CloudRecordItem> cloudRecordItemList = cloudRecordServiceMapper.queryRecordListForDelete(lastDate, mediaServerItem.getId()); | ||
| 66 | + if (cloudRecordItemList.isEmpty()) { | ||
| 67 | + continue; | ||
| 68 | + } | ||
| 69 | + // TODO 后续可以删除空了的过期日期文件夹 | ||
| 70 | + for (CloudRecordItem cloudRecordItem : cloudRecordItemList) { | ||
| 71 | + String date = new File(cloudRecordItem.getFilePath()).getParentFile().getName(); | ||
| 72 | + JSONObject jsonObject = zlmresTfulUtils.deleteRecordDirectory(mediaServerItem, cloudRecordItem.getApp(), | ||
| 73 | + cloudRecordItem.getStream(), date, cloudRecordItem.getFileName()); | ||
| 74 | + if (jsonObject.getInteger("code") != 0) { | ||
| 75 | + logger.warn("[录像文件定时清理] 删除磁盘文件错误: {}:{}", cloudRecordItem.getFilePath(), jsonObject); | ||
| 76 | + } | ||
| 77 | + } | ||
| 78 | + result += cloudRecordServiceMapper.deleteList(cloudRecordItemList); | ||
| 79 | + } | ||
| 80 | + } | ||
| 81 | + logger.info("[录像文件定时清理] 共清理{}个过期录像文件", result); | ||
| 82 | + } | ||
| 83 | +} |
src/main/java/com/genersoft/iot/vmp/conf/MediaConfig.java
| @@ -81,6 +81,12 @@ public class MediaConfig{ | @@ -81,6 +81,12 @@ public class MediaConfig{ | ||
| 81 | @Value("${media.record-assist-port:0}") | 81 | @Value("${media.record-assist-port:0}") |
| 82 | private Integer recordAssistPort = 0; | 82 | private Integer recordAssistPort = 0; |
| 83 | 83 | ||
| 84 | + @Value("${media.record-day:7}") | ||
| 85 | + private Integer recordDay; | ||
| 86 | + | ||
| 87 | + @Value("${media.record-path:}") | ||
| 88 | + private String recordPath; | ||
| 89 | + | ||
| 84 | public String getId() { | 90 | public String getId() { |
| 85 | return id; | 91 | return id; |
| 86 | } | 92 | } |
| @@ -212,13 +218,32 @@ public class MediaConfig{ | @@ -212,13 +218,32 @@ public class MediaConfig{ | ||
| 212 | mediaServerItem.setSendRtpPortRange(rtpSendPortRange); | 218 | mediaServerItem.setSendRtpPortRange(rtpSendPortRange); |
| 213 | mediaServerItem.setRecordAssistPort(recordAssistPort); | 219 | mediaServerItem.setRecordAssistPort(recordAssistPort); |
| 214 | mediaServerItem.setHookAliveInterval(30.00f); | 220 | mediaServerItem.setHookAliveInterval(30.00f); |
| 215 | - | 221 | + mediaServerItem.setRecordDay(recordDay); |
| 222 | + if (recordPath != null) { | ||
| 223 | + mediaServerItem.setRecordPath(recordPath); | ||
| 224 | + } | ||
| 216 | mediaServerItem.setCreateTime(DateUtil.getNow()); | 225 | mediaServerItem.setCreateTime(DateUtil.getNow()); |
| 217 | mediaServerItem.setUpdateTime(DateUtil.getNow()); | 226 | mediaServerItem.setUpdateTime(DateUtil.getNow()); |
| 218 | 227 | ||
| 219 | return mediaServerItem; | 228 | return mediaServerItem; |
| 220 | } | 229 | } |
| 221 | 230 | ||
| 231 | + public Integer getRecordDay() { | ||
| 232 | + return recordDay; | ||
| 233 | + } | ||
| 234 | + | ||
| 235 | + public void setRecordDay(Integer recordDay) { | ||
| 236 | + this.recordDay = recordDay; | ||
| 237 | + } | ||
| 238 | + | ||
| 239 | + public String getRecordPath() { | ||
| 240 | + return recordPath; | ||
| 241 | + } | ||
| 242 | + | ||
| 243 | + public void setRecordPath(String recordPath) { | ||
| 244 | + this.recordPath = recordPath; | ||
| 245 | + } | ||
| 246 | + | ||
| 222 | public String getRtpSendPortRange() { | 247 | public String getRtpSendPortRange() { |
| 223 | return rtpSendPortRange; | 248 | return rtpSendPortRange; |
| 224 | } | 249 | } |
src/main/java/com/genersoft/iot/vmp/conf/SpringDocConfig.java
| 1 | package com.genersoft.iot.vmp.conf; | 1 | package com.genersoft.iot.vmp.conf; |
| 2 | 2 | ||
| 3 | +import com.genersoft.iot.vmp.conf.security.JwtUtils; | ||
| 4 | +import io.swagger.v3.oas.models.Components; | ||
| 3 | import io.swagger.v3.oas.models.OpenAPI; | 5 | import io.swagger.v3.oas.models.OpenAPI; |
| 4 | import io.swagger.v3.oas.models.info.Contact; | 6 | import io.swagger.v3.oas.models.info.Contact; |
| 5 | import io.swagger.v3.oas.models.info.Info; | 7 | import io.swagger.v3.oas.models.info.Info; |
| 6 | import io.swagger.v3.oas.models.info.License; | 8 | import io.swagger.v3.oas.models.info.License; |
| 9 | +import io.swagger.v3.oas.models.security.SecurityScheme; | ||
| 7 | import org.springframework.core.annotation.Order; | 10 | import org.springframework.core.annotation.Order; |
| 8 | import org.springdoc.core.GroupedOpenApi; | 11 | import org.springdoc.core.GroupedOpenApi; |
| 9 | import org.springframework.beans.factory.annotation.Value; | 12 | import org.springframework.beans.factory.annotation.Value; |
| @@ -26,10 +29,14 @@ public class SpringDocConfig { | @@ -26,10 +29,14 @@ public class SpringDocConfig { | ||
| 26 | contact.setName("pan"); | 29 | contact.setName("pan"); |
| 27 | contact.setEmail("648540858@qq.com"); | 30 | contact.setEmail("648540858@qq.com"); |
| 28 | return new OpenAPI() | 31 | return new OpenAPI() |
| 32 | + .components(new Components() | ||
| 33 | + .addSecuritySchemes(JwtUtils.HEADER, new SecurityScheme() | ||
| 34 | + .type(SecurityScheme.Type.HTTP) | ||
| 35 | + .bearerFormat("JWT"))) | ||
| 29 | .info(new Info().title("WVP-PRO 接口文档") | 36 | .info(new Info().title("WVP-PRO 接口文档") |
| 30 | .contact(contact) | 37 | .contact(contact) |
| 31 | .description("开箱即用的28181协议视频平台") | 38 | .description("开箱即用的28181协议视频平台") |
| 32 | - .version("v2.0") | 39 | + .version("v3.1.0") |
| 33 | .license(new License().name("Apache 2.0").url("http://springdoc.org"))); | 40 | .license(new License().name("Apache 2.0").url("http://springdoc.org"))); |
| 34 | } | 41 | } |
| 35 | 42 |
src/main/java/com/genersoft/iot/vmp/conf/SystemInfoTimerTask.java
src/main/java/com/genersoft/iot/vmp/conf/UserSetting.java
| @@ -23,7 +23,7 @@ public class UserSetting { | @@ -23,7 +23,7 @@ public class UserSetting { | ||
| 23 | 23 | ||
| 24 | private Integer playTimeout = 18000; | 24 | private Integer playTimeout = 18000; |
| 25 | 25 | ||
| 26 | - private int platformPlayTimeout = 60000; | 26 | + private int platformPlayTimeout = 20000; |
| 27 | 27 | ||
| 28 | private Boolean interfaceAuthentication = Boolean.TRUE; | 28 | private Boolean interfaceAuthentication = Boolean.TRUE; |
| 29 | 29 | ||
| @@ -51,13 +51,11 @@ public class UserSetting { | @@ -51,13 +51,11 @@ public class UserSetting { | ||
| 51 | 51 | ||
| 52 | private Boolean refuseChannelStatusChannelFormNotify = Boolean.FALSE; | 52 | private Boolean refuseChannelStatusChannelFormNotify = Boolean.FALSE; |
| 53 | 53 | ||
| 54 | - private Boolean deviceStatusNotify = Boolean.FALSE; | 54 | + private Boolean deviceStatusNotify = Boolean.TRUE; |
| 55 | private Boolean useCustomSsrcForParentInvite = Boolean.TRUE; | 55 | private Boolean useCustomSsrcForParentInvite = Boolean.TRUE; |
| 56 | 56 | ||
| 57 | private String serverId = "000000"; | 57 | private String serverId = "000000"; |
| 58 | 58 | ||
| 59 | - private String recordPath = null; | ||
| 60 | - | ||
| 61 | private String thirdPartyGBIdReg = "[\\s\\S]*"; | 59 | private String thirdPartyGBIdReg = "[\\s\\S]*"; |
| 62 | 60 | ||
| 63 | private String broadcastForPlatform = "UDP"; | 61 | private String broadcastForPlatform = "UDP"; |
| @@ -262,14 +260,6 @@ public class UserSetting { | @@ -262,14 +260,6 @@ public class UserSetting { | ||
| 262 | this.refuseChannelStatusChannelFormNotify = refuseChannelStatusChannelFormNotify; | 260 | this.refuseChannelStatusChannelFormNotify = refuseChannelStatusChannelFormNotify; |
| 263 | } | 261 | } |
| 264 | 262 | ||
| 265 | - public String getRecordPath() { | ||
| 266 | - return recordPath; | ||
| 267 | - } | ||
| 268 | - | ||
| 269 | - public void setRecordPath(String recordPath) { | ||
| 270 | - this.recordPath = recordPath; | ||
| 271 | - } | ||
| 272 | - | ||
| 273 | public int getMaxNotifyCountQueue() { | 263 | public int getMaxNotifyCountQueue() { |
| 274 | return maxNotifyCountQueue; | 264 | return maxNotifyCountQueue; |
| 275 | } | 265 | } |
src/main/java/com/genersoft/iot/vmp/conf/security/JwtAuthenticationFilter.java
| @@ -78,6 +78,7 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter { | @@ -78,6 +78,7 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter { | ||
| 78 | 78 | ||
| 79 | // 构建UsernamePasswordAuthenticationToken,这里密码为null,是因为提供了正确的JWT,实现自动登录 | 79 | // 构建UsernamePasswordAuthenticationToken,这里密码为null,是因为提供了正确的JWT,实现自动登录 |
| 80 | User user = new User(); | 80 | User user = new User(); |
| 81 | + user.setId(jwtUser.getUserId()); | ||
| 81 | user.setUsername(jwtUser.getUserName()); | 82 | user.setUsername(jwtUser.getUserName()); |
| 82 | user.setPassword(jwtUser.getPassword()); | 83 | user.setPassword(jwtUser.getPassword()); |
| 83 | Role role = new Role(); | 84 | Role role = new Role(); |
src/main/java/com/genersoft/iot/vmp/conf/security/JwtUtils.java
| @@ -28,7 +28,7 @@ public class JwtUtils implements InitializingBean { | @@ -28,7 +28,7 @@ public class JwtUtils implements InitializingBean { | ||
| 28 | 28 | ||
| 29 | private static final Logger logger = LoggerFactory.getLogger(JwtUtils.class); | 29 | private static final Logger logger = LoggerFactory.getLogger(JwtUtils.class); |
| 30 | 30 | ||
| 31 | - private static final String HEADER = "access-token"; | 31 | + public static final String HEADER = "access-token"; |
| 32 | 32 | ||
| 33 | private static final String AUDIENCE = "Audience"; | 33 | private static final String AUDIENCE = "Audience"; |
| 34 | 34 | ||
| @@ -144,6 +144,7 @@ public class JwtUtils implements InitializingBean { | @@ -144,6 +144,7 @@ public class JwtUtils implements InitializingBean { | ||
| 144 | jwtUser.setUserName(username); | 144 | jwtUser.setUserName(username); |
| 145 | jwtUser.setPassword(user.getPassword()); | 145 | jwtUser.setPassword(user.getPassword()); |
| 146 | jwtUser.setRoleId(user.getRole().getId()); | 146 | jwtUser.setRoleId(user.getRole().getId()); |
| 147 | + jwtUser.setUserId(user.getId()); | ||
| 147 | 148 | ||
| 148 | return jwtUser; | 149 | return jwtUser; |
| 149 | } catch (InvalidJwtException e) { | 150 | } catch (InvalidJwtException e) { |
src/main/java/com/genersoft/iot/vmp/conf/security/WebSecurityConfig.java
| 1 | package com.genersoft.iot.vmp.conf.security; | 1 | package com.genersoft.iot.vmp.conf.security; |
| 2 | 2 | ||
| 3 | import com.genersoft.iot.vmp.conf.UserSetting; | 3 | import com.genersoft.iot.vmp.conf.UserSetting; |
| 4 | -import org.springframework.core.annotation.Order; | ||
| 5 | import org.slf4j.Logger; | 4 | import org.slf4j.Logger; |
| 6 | import org.slf4j.LoggerFactory; | 5 | import org.slf4j.LoggerFactory; |
| 7 | import org.springframework.beans.factory.annotation.Autowired; | 6 | import org.springframework.beans.factory.annotation.Autowired; |
| 8 | import org.springframework.context.annotation.Bean; | 7 | import org.springframework.context.annotation.Bean; |
| 9 | import org.springframework.context.annotation.Configuration; | 8 | import org.springframework.context.annotation.Configuration; |
| 9 | +import org.springframework.core.annotation.Order; | ||
| 10 | import org.springframework.security.authentication.AuthenticationManager; | 10 | import org.springframework.security.authentication.AuthenticationManager; |
| 11 | import org.springframework.security.authentication.dao.DaoAuthenticationProvider; | 11 | import org.springframework.security.authentication.dao.DaoAuthenticationProvider; |
| 12 | import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; | 12 | import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; |
| @@ -25,9 +25,11 @@ import org.springframework.web.cors.UrlBasedCorsConfigurationSource; | @@ -25,9 +25,11 @@ import org.springframework.web.cors.UrlBasedCorsConfigurationSource; | ||
| 25 | 25 | ||
| 26 | import java.util.ArrayList; | 26 | import java.util.ArrayList; |
| 27 | import java.util.Arrays; | 27 | import java.util.Arrays; |
| 28 | +import java.util.Collections; | ||
| 28 | 29 | ||
| 29 | /** | 30 | /** |
| 30 | * 配置Spring Security | 31 | * 配置Spring Security |
| 32 | + * | ||
| 31 | * @author lin | 33 | * @author lin |
| 32 | */ | 34 | */ |
| 33 | @Configuration | 35 | @Configuration |
| @@ -67,6 +69,8 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter { | @@ -67,6 +69,8 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter { | ||
| 67 | matchers.add("/"); | 69 | matchers.add("/"); |
| 68 | matchers.add("/#/**"); | 70 | matchers.add("/#/**"); |
| 69 | matchers.add("/static/**"); | 71 | matchers.add("/static/**"); |
| 72 | + matchers.add("/swagger-ui.html"); | ||
| 73 | + matchers.add("/swagger-ui/"); | ||
| 70 | matchers.add("/index.html"); | 74 | matchers.add("/index.html"); |
| 71 | matchers.add("/doc.html"); | 75 | matchers.add("/doc.html"); |
| 72 | matchers.add("/webjars/**"); | 76 | matchers.add("/webjars/**"); |
| @@ -75,7 +79,8 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter { | @@ -75,7 +79,8 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter { | ||
| 75 | matchers.add("/js/**"); | 79 | matchers.add("/js/**"); |
| 76 | matchers.add("/api/device/query/snap/**"); | 80 | matchers.add("/api/device/query/snap/**"); |
| 77 | matchers.add("/record_proxy/*/**"); | 81 | matchers.add("/record_proxy/*/**"); |
| 78 | - matchers.addAll(userSetting.getInterfaceAuthenticationExcludes()); | 82 | + matchers.add("/api/emit"); |
| 83 | + matchers.add("/favicon.ico"); | ||
| 79 | // 可以直接访问的静态数据 | 84 | // 可以直接访问的静态数据 |
| 80 | web.ignoring().antMatchers(matchers.toArray(new String[0])); | 85 | web.ignoring().antMatchers(matchers.toArray(new String[0])); |
| 81 | } | 86 | } |
| @@ -83,6 +88,7 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter { | @@ -83,6 +88,7 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter { | ||
| 83 | 88 | ||
| 84 | /** | 89 | /** |
| 85 | * 配置认证方式 | 90 | * 配置认证方式 |
| 91 | + * | ||
| 86 | * @param auth | 92 | * @param auth |
| 87 | * @throws Exception | 93 | * @throws Exception |
| 88 | */ | 94 | */ |
| @@ -111,7 +117,7 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter { | @@ -111,7 +117,7 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter { | ||
| 111 | .authorizeRequests() | 117 | .authorizeRequests() |
| 112 | .requestMatchers(CorsUtils::isPreFlightRequest).permitAll() | 118 | .requestMatchers(CorsUtils::isPreFlightRequest).permitAll() |
| 113 | .antMatchers(userSetting.getInterfaceAuthenticationExcludes().toArray(new String[0])).permitAll() | 119 | .antMatchers(userSetting.getInterfaceAuthenticationExcludes().toArray(new String[0])).permitAll() |
| 114 | - .antMatchers("/api/user/login","/index/hook/**","/zlm_Proxy/FhTuMYqB2HeCuNOb/record/t/1/2023-03-25/16:35:07-16:35:16-9353.mp4").permitAll() | 120 | + .antMatchers("/api/user/login", "/index/hook/**", "/swagger-ui/**", "/doc.html").permitAll() |
| 115 | .anyRequest().authenticated() | 121 | .anyRequest().authenticated() |
| 116 | // 异常处理器 | 122 | // 异常处理器 |
| 117 | .and() | 123 | .and() |
| @@ -124,18 +130,24 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter { | @@ -124,18 +130,24 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter { | ||
| 124 | 130 | ||
| 125 | } | 131 | } |
| 126 | 132 | ||
| 127 | - CorsConfigurationSource configurationSource(){ | 133 | + CorsConfigurationSource configurationSource() { |
| 128 | // 配置跨域 | 134 | // 配置跨域 |
| 129 | CorsConfiguration corsConfiguration = new CorsConfiguration(); | 135 | CorsConfiguration corsConfiguration = new CorsConfiguration(); |
| 130 | corsConfiguration.setAllowedHeaders(Arrays.asList("*")); | 136 | corsConfiguration.setAllowedHeaders(Arrays.asList("*")); |
| 131 | corsConfiguration.setAllowedMethods(Arrays.asList("*")); | 137 | corsConfiguration.setAllowedMethods(Arrays.asList("*")); |
| 132 | corsConfiguration.setMaxAge(3600L); | 138 | corsConfiguration.setMaxAge(3600L); |
| 133 | - corsConfiguration.setAllowCredentials(true); | ||
| 134 | - corsConfiguration.setAllowedOrigins(userSetting.getAllowedOrigins()); | 139 | + if (userSetting.getAllowedOrigins() != null && !userSetting.getAllowedOrigins().isEmpty()) { |
| 140 | + corsConfiguration.setAllowCredentials(true); | ||
| 141 | + corsConfiguration.setAllowedOrigins(userSetting.getAllowedOrigins()); | ||
| 142 | + }else { | ||
| 143 | + corsConfiguration.setAllowCredentials(false); | ||
| 144 | + corsConfiguration.setAllowedOrigins(Collections.singletonList(CorsConfiguration.ALL)); | ||
| 145 | + } | ||
| 146 | + | ||
| 135 | corsConfiguration.setExposedHeaders(Arrays.asList(JwtUtils.getHeader())); | 147 | corsConfiguration.setExposedHeaders(Arrays.asList(JwtUtils.getHeader())); |
| 136 | 148 | ||
| 137 | UrlBasedCorsConfigurationSource url = new UrlBasedCorsConfigurationSource(); | 149 | UrlBasedCorsConfigurationSource url = new UrlBasedCorsConfigurationSource(); |
| 138 | - url.registerCorsConfiguration("/**",corsConfiguration); | 150 | + url.registerCorsConfiguration("/**", corsConfiguration); |
| 139 | return url; | 151 | return url; |
| 140 | } | 152 | } |
| 141 | 153 |
src/main/java/com/genersoft/iot/vmp/conf/security/dto/JwtUser.java
| @@ -21,6 +21,7 @@ public class JwtUser { | @@ -21,6 +21,7 @@ public class JwtUser { | ||
| 21 | EXCEPTION | 21 | EXCEPTION |
| 22 | } | 22 | } |
| 23 | 23 | ||
| 24 | + private int userId; | ||
| 24 | private String userName; | 25 | private String userName; |
| 25 | 26 | ||
| 26 | private String password; | 27 | private String password; |
| @@ -29,6 +30,14 @@ public class JwtUser { | @@ -29,6 +30,14 @@ public class JwtUser { | ||
| 29 | 30 | ||
| 30 | private TokenStatus status; | 31 | private TokenStatus status; |
| 31 | 32 | ||
| 33 | + public int getUserId() { | ||
| 34 | + return userId; | ||
| 35 | + } | ||
| 36 | + | ||
| 37 | + public void setUserId(int userId) { | ||
| 38 | + this.userId = userId; | ||
| 39 | + } | ||
| 40 | + | ||
| 32 | public String getUserName() { | 41 | public String getUserName() { |
| 33 | return userName; | 42 | return userName; |
| 34 | } | 43 | } |
src/main/java/com/genersoft/iot/vmp/gb28181/conf/StackLoggerImpl.java
| 1 | package com.genersoft.iot.vmp.gb28181.conf; | 1 | package com.genersoft.iot.vmp.gb28181.conf; |
| 2 | 2 | ||
| 3 | import gov.nist.core.StackLogger; | 3 | import gov.nist.core.StackLogger; |
| 4 | -import org.slf4j.Logger; | ||
| 5 | import org.slf4j.LoggerFactory; | 4 | import org.slf4j.LoggerFactory; |
| 5 | +import org.slf4j.spi.LocationAwareLogger; | ||
| 6 | import org.springframework.stereotype.Component; | 6 | import org.springframework.stereotype.Component; |
| 7 | 7 | ||
| 8 | import java.util.Properties; | 8 | import java.util.Properties; |
| @@ -10,100 +10,132 @@ import java.util.Properties; | @@ -10,100 +10,132 @@ import java.util.Properties; | ||
| 10 | @Component | 10 | @Component |
| 11 | public class StackLoggerImpl implements StackLogger { | 11 | public class StackLoggerImpl implements StackLogger { |
| 12 | 12 | ||
| 13 | - private final static Logger logger = LoggerFactory.getLogger(StackLoggerImpl.class); | 13 | + /** |
| 14 | + * 完全限定类名(Fully Qualified Class Name),用于定位日志位置 | ||
| 15 | + */ | ||
| 16 | + private static final String FQCN = StackLoggerImpl.class.getName(); | ||
| 17 | + | ||
| 18 | + /** | ||
| 19 | + * 获取栈中类信息(以便底层日志记录系统能够提取正确的位置信息(方法名、行号)) | ||
| 20 | + * @return LocationAwareLogger | ||
| 21 | + */ | ||
| 22 | + private static LocationAwareLogger getLocationAwareLogger() { | ||
| 23 | + return (LocationAwareLogger) LoggerFactory.getLogger(new Throwable().getStackTrace()[4].getClassName()); | ||
| 24 | + } | ||
| 25 | + | ||
| 26 | + | ||
| 27 | + /** | ||
| 28 | + * 封装打印日志的位置信息 | ||
| 29 | + * @param level 日志级别 | ||
| 30 | + * @param message 日志事件的消息 | ||
| 31 | + */ | ||
| 32 | + private static void log(int level, String message) { | ||
| 33 | + LocationAwareLogger locationAwareLogger = getLocationAwareLogger(); | ||
| 34 | + locationAwareLogger.log(null, FQCN, level, message, null, null); | ||
| 35 | + } | ||
| 36 | + | ||
| 37 | + /** | ||
| 38 | + * 封装打印日志的位置信息 | ||
| 39 | + * @param level 日志级别 | ||
| 40 | + * @param message 日志事件的消息 | ||
| 41 | + */ | ||
| 42 | + private static void log(int level, String message, Throwable throwable) { | ||
| 43 | + LocationAwareLogger locationAwareLogger = getLocationAwareLogger(); | ||
| 44 | + locationAwareLogger.log(null, FQCN, level, message, null, throwable); | ||
| 45 | + } | ||
| 46 | + | ||
| 47 | + @Override | ||
| 48 | + public void logStackTrace() { | ||
| 49 | + | ||
| 50 | + } | ||
| 51 | + | ||
| 52 | + @Override | ||
| 53 | + public void logStackTrace(int traceLevel) { | ||
| 54 | + System.out.println("traceLevel: " + traceLevel); | ||
| 55 | + } | ||
| 56 | + | ||
| 57 | + @Override | ||
| 58 | + public int getLineCount() { | ||
| 59 | + return 0; | ||
| 60 | + } | ||
| 61 | + | ||
| 62 | + @Override | ||
| 63 | + public void logException(Throwable ex) { | ||
| 64 | + | ||
| 65 | + } | ||
| 66 | + | ||
| 67 | + @Override | ||
| 68 | + public void logDebug(String message) { | ||
| 69 | + log(LocationAwareLogger.INFO_INT, message); | ||
| 70 | + } | ||
| 71 | + | ||
| 72 | + @Override | ||
| 73 | + public void logDebug(String message, Exception ex) { | ||
| 74 | + log(LocationAwareLogger.INFO_INT, message, ex); | ||
| 75 | + } | ||
| 76 | + | ||
| 77 | + @Override | ||
| 78 | + public void logTrace(String message) { | ||
| 79 | + log(LocationAwareLogger.INFO_INT, message); | ||
| 80 | + } | ||
| 81 | + | ||
| 82 | + @Override | ||
| 83 | + public void logFatalError(String message) { | ||
| 84 | + log(LocationAwareLogger.INFO_INT, message); | ||
| 85 | + } | ||
| 86 | + | ||
| 87 | + @Override | ||
| 88 | + public void logError(String message) { | ||
| 89 | + log(LocationAwareLogger.INFO_INT, message); | ||
| 90 | + } | ||
| 91 | + | ||
| 92 | + @Override | ||
| 93 | + public boolean isLoggingEnabled() { | ||
| 94 | + return true; | ||
| 95 | + } | ||
| 96 | + | ||
| 97 | + @Override | ||
| 98 | + public boolean isLoggingEnabled(int logLevel) { | ||
| 99 | + return true; | ||
| 100 | + } | ||
| 101 | + | ||
| 102 | + @Override | ||
| 103 | + public void logError(String message, Exception ex) { | ||
| 104 | + log(LocationAwareLogger.INFO_INT, message, ex); | ||
| 105 | + } | ||
| 106 | + | ||
| 107 | + @Override | ||
| 108 | + public void logWarning(String message) { | ||
| 109 | + log(LocationAwareLogger.INFO_INT, message); | ||
| 110 | + } | ||
| 111 | + | ||
| 112 | + @Override | ||
| 113 | + public void logInfo(String message) { | ||
| 114 | + log(LocationAwareLogger.INFO_INT, message); | ||
| 115 | + } | ||
| 116 | + | ||
| 117 | + @Override | ||
| 118 | + public void disableLogging() { | ||
| 119 | + | ||
| 120 | + } | ||
| 121 | + | ||
| 122 | + @Override | ||
| 123 | + public void enableLogging() { | ||
| 124 | + | ||
| 125 | + } | ||
| 126 | + | ||
| 127 | + @Override | ||
| 128 | + public void setBuildTimeStamp(String buildTimeStamp) { | ||
| 129 | + | ||
| 130 | + } | ||
| 131 | + | ||
| 132 | + @Override | ||
| 133 | + public void setStackProperties(Properties stackProperties) { | ||
| 14 | 134 | ||
| 15 | - @Override | ||
| 16 | - public void logStackTrace() { | 135 | + } |
| 17 | 136 | ||
| 18 | - } | ||
| 19 | - | ||
| 20 | - @Override | ||
| 21 | - public void logStackTrace(int traceLevel) { | ||
| 22 | - System.out.println("traceLevel: " + traceLevel); | ||
| 23 | - } | ||
| 24 | - | ||
| 25 | - @Override | ||
| 26 | - public int getLineCount() { | ||
| 27 | - return 0; | ||
| 28 | - } | ||
| 29 | - | ||
| 30 | - @Override | ||
| 31 | - public void logException(Throwable ex) { | ||
| 32 | - | ||
| 33 | - } | ||
| 34 | - | ||
| 35 | - @Override | ||
| 36 | - public void logDebug(String message) { | ||
| 37 | -// logger.debug(message); | ||
| 38 | - } | ||
| 39 | - | ||
| 40 | - @Override | ||
| 41 | - public void logDebug(String message, Exception ex) { | ||
| 42 | -// logger.debug(message); | ||
| 43 | - } | ||
| 44 | - | ||
| 45 | - @Override | ||
| 46 | - public void logTrace(String message) { | ||
| 47 | - logger.trace(message); | ||
| 48 | - } | ||
| 49 | - | ||
| 50 | - @Override | ||
| 51 | - public void logFatalError(String message) { | ||
| 52 | -// logger.error(message); | ||
| 53 | - } | ||
| 54 | - | ||
| 55 | - @Override | ||
| 56 | - public void logError(String message) { | ||
| 57 | -// logger.error(message); | ||
| 58 | - } | ||
| 59 | - | ||
| 60 | - @Override | ||
| 61 | - public boolean isLoggingEnabled() { | ||
| 62 | - return true; | ||
| 63 | - } | ||
| 64 | - | ||
| 65 | - @Override | ||
| 66 | - public boolean isLoggingEnabled(int logLevel) { | ||
| 67 | - return true; | ||
| 68 | - } | ||
| 69 | - | ||
| 70 | - @Override | ||
| 71 | - public void logError(String message, Exception ex) { | ||
| 72 | -// logger.error(message); | ||
| 73 | - } | ||
| 74 | - | ||
| 75 | - @Override | ||
| 76 | - public void logWarning(String message) { | ||
| 77 | - logger.warn(message); | ||
| 78 | - } | ||
| 79 | - | ||
| 80 | - @Override | ||
| 81 | - public void logInfo(String message) { | ||
| 82 | - logger.info(message); | ||
| 83 | - } | ||
| 84 | - | ||
| 85 | - @Override | ||
| 86 | - public void disableLogging() { | ||
| 87 | - | ||
| 88 | - } | ||
| 89 | - | ||
| 90 | - @Override | ||
| 91 | - public void enableLogging() { | ||
| 92 | - | ||
| 93 | - } | ||
| 94 | - | ||
| 95 | - @Override | ||
| 96 | - public void setBuildTimeStamp(String buildTimeStamp) { | ||
| 97 | - | ||
| 98 | - } | ||
| 99 | - | ||
| 100 | - @Override | ||
| 101 | - public void setStackProperties(Properties stackProperties) { | ||
| 102 | - | ||
| 103 | - } | ||
| 104 | - | ||
| 105 | - @Override | ||
| 106 | - public String getLoggerName() { | ||
| 107 | - return null; | ||
| 108 | - } | 137 | + @Override |
| 138 | + public String getLoggerName() { | ||
| 139 | + return null; | ||
| 140 | + } | ||
| 109 | } | 141 | } |
src/main/java/com/genersoft/iot/vmp/gb28181/event/alarm/AlarmEventListener.java
| 1 | package com.genersoft.iot.vmp.gb28181.event.alarm; | 1 | package com.genersoft.iot.vmp.gb28181.event.alarm; |
| 2 | 2 | ||
| 3 | +import org.jetbrains.annotations.NotNull; | ||
| 4 | +import org.slf4j.Logger; | ||
| 5 | +import org.slf4j.LoggerFactory; | ||
| 3 | import org.springframework.context.ApplicationListener; | 6 | import org.springframework.context.ApplicationListener; |
| 4 | import org.springframework.stereotype.Component; | 7 | import org.springframework.stereotype.Component; |
| 5 | -import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; | ||
| 6 | -import java.io.IOException; | ||
| 7 | -import java.util.Hashtable; | 8 | + |
| 9 | +import java.io.PrintWriter; | ||
| 8 | import java.util.Iterator; | 10 | import java.util.Iterator; |
| 9 | import java.util.Map; | 11 | import java.util.Map; |
| 10 | - | ||
| 11 | -import org.slf4j.Logger; | ||
| 12 | -import org.slf4j.LoggerFactory; | 12 | +import java.util.concurrent.ConcurrentHashMap; |
| 13 | 13 | ||
| 14 | /** | 14 | /** |
| 15 | - * @description: 报警事件监听 | ||
| 16 | - * @author: lawrencehj | ||
| 17 | - * @data: 2021-01-20 | 15 | + * 报警事件监听器. |
| 16 | + * | ||
| 17 | + * @author lawrencehj | ||
| 18 | + * @author <a href="mailto:xiaoQQya@126.com">xiaoQQya</a> | ||
| 19 | + * @since 2021/01/20 | ||
| 18 | */ | 20 | */ |
| 19 | - | ||
| 20 | @Component | 21 | @Component |
| 21 | public class AlarmEventListener implements ApplicationListener<AlarmEvent> { | 22 | public class AlarmEventListener implements ApplicationListener<AlarmEvent> { |
| 22 | 23 | ||
| 23 | - private final static Logger logger = LoggerFactory.getLogger(AlarmEventListener.class); | 24 | + private static final Logger logger = LoggerFactory.getLogger(AlarmEventListener.class); |
| 24 | 25 | ||
| 25 | - private static Map<String, SseEmitter> sseEmitters = new Hashtable<>(); | 26 | + private static final Map<String, PrintWriter> SSE_CACHE = new ConcurrentHashMap<>(); |
| 26 | 27 | ||
| 27 | - public void addSseEmitters(String browserId, SseEmitter sseEmitter) { | ||
| 28 | - sseEmitters.put(browserId, sseEmitter); | 28 | + public void addSseEmitter(String browserId, PrintWriter writer) { |
| 29 | + SSE_CACHE.put(browserId, writer); | ||
| 30 | + logger.info("SSE 在线数量: {}", SSE_CACHE.size()); | ||
| 31 | + } | ||
| 32 | + | ||
| 33 | + public void removeSseEmitter(String browserId, PrintWriter writer) { | ||
| 34 | + SSE_CACHE.remove(browserId, writer); | ||
| 35 | + logger.info("SSE 在线数量: {}", SSE_CACHE.size()); | ||
| 29 | } | 36 | } |
| 30 | 37 | ||
| 31 | @Override | 38 | @Override |
| 32 | - public void onApplicationEvent(AlarmEvent event) { | 39 | + public void onApplicationEvent(@NotNull AlarmEvent event) { |
| 33 | if (logger.isDebugEnabled()) { | 40 | if (logger.isDebugEnabled()) { |
| 34 | - logger.debug("设备报警事件触发,deviceId:" + event.getAlarmInfo().getDeviceId() + ", " | ||
| 35 | - + event.getAlarmInfo().getAlarmDescription()); | 41 | + logger.debug("设备报警事件触发, deviceId: {}, {}", event.getAlarmInfo().getDeviceId(), event.getAlarmInfo().getAlarmDescription()); |
| 36 | } | 42 | } |
| 37 | - String msg = "<strong>设备编码:</strong> <i>" + event.getAlarmInfo().getDeviceId() + "</i>" | ||
| 38 | - + "<br><strong>报警描述:</strong> <i>" + event.getAlarmInfo().getAlarmDescription() + "</i>" | ||
| 39 | - + "<br><strong>报警时间:</strong> <i>" + event.getAlarmInfo().getAlarmTime() + "</i>" | ||
| 40 | - + "<br><strong>报警位置:</strong> <i>" + event.getAlarmInfo().getLongitude() + "</i>" | ||
| 41 | - + ", <i>" + event.getAlarmInfo().getLatitude() + "</i>"; | ||
| 42 | - | ||
| 43 | - for (Iterator<Map.Entry<String, SseEmitter>> it = sseEmitters.entrySet().iterator(); it.hasNext();) { | ||
| 44 | - Map.Entry<String, SseEmitter> emitter = it.next(); | ||
| 45 | - logger.info("推送到SSE连接,浏览器ID: " + emitter.getKey()); | 43 | + |
| 44 | + String msg = "<strong>设备编号:</strong> <i>" + event.getAlarmInfo().getDeviceId() + "</i>" | ||
| 45 | + + "<br><strong>通道编号:</strong> <i>" + event.getAlarmInfo().getChannelId() + "</i>" | ||
| 46 | + + "<br><strong>报警描述:</strong> <i>" + event.getAlarmInfo().getAlarmDescription() + "</i>" | ||
| 47 | + + "<br><strong>报警时间:</strong> <i>" + event.getAlarmInfo().getAlarmTime() + "</i>"; | ||
| 48 | + | ||
| 49 | + for (Iterator<Map.Entry<String, PrintWriter>> it = SSE_CACHE.entrySet().iterator(); it.hasNext(); ) { | ||
| 50 | + Map.Entry<String, PrintWriter> response = it.next(); | ||
| 51 | + logger.info("推送到 SSE 连接, 浏览器 ID: {}", response.getKey()); | ||
| 46 | try { | 52 | try { |
| 47 | - emitter.getValue().send(msg); | ||
| 48 | - } catch (IOException | IllegalStateException e) { | ||
| 49 | - if (logger.isDebugEnabled()) { | ||
| 50 | - logger.debug("SSE连接已关闭"); | 53 | + PrintWriter writer = response.getValue(); |
| 54 | + | ||
| 55 | + if (writer.checkError()) { | ||
| 56 | + it.remove(); | ||
| 57 | + continue; | ||
| 51 | } | 58 | } |
| 52 | - // 移除已关闭的连接 | 59 | + |
| 60 | + String sseMsg = "event:message\n" + | ||
| 61 | + "data:" + msg + "\n" + | ||
| 62 | + "\n"; | ||
| 63 | + writer.write(sseMsg); | ||
| 64 | + writer.flush(); | ||
| 65 | + } catch (Exception e) { | ||
| 53 | it.remove(); | 66 | it.remove(); |
| 54 | } | 67 | } |
| 55 | } | 68 | } |
src/main/java/com/genersoft/iot/vmp/gb28181/event/record/RecordEndEventListener.java
| @@ -35,7 +35,7 @@ public class RecordEndEventListener implements ApplicationListener<RecordEndEven | @@ -35,7 +35,7 @@ public class RecordEndEventListener implements ApplicationListener<RecordEndEven | ||
| 35 | int sumNum = event.getRecordInfo().getSumNum(); | 35 | int sumNum = event.getRecordInfo().getSumNum(); |
| 36 | logger.info("录像查询完成事件触发,deviceId:{}, channelId: {}, 录像数量{}/{}条", event.getRecordInfo().getDeviceId(), | 36 | logger.info("录像查询完成事件触发,deviceId:{}, channelId: {}, 录像数量{}/{}条", event.getRecordInfo().getDeviceId(), |
| 37 | event.getRecordInfo().getChannelId(), count,sumNum); | 37 | event.getRecordInfo().getChannelId(), count,sumNum); |
| 38 | - if (handlerMap.size() > 0) { | 38 | + if (!handlerMap.isEmpty()) { |
| 39 | RecordEndEventHandler handler = handlerMap.get(deviceId + channelId); | 39 | RecordEndEventHandler handler = handlerMap.get(deviceId + channelId); |
| 40 | if (handler !=null){ | 40 | if (handler !=null){ |
| 41 | handler.handler(event.getRecordInfo()); | 41 | handler.handler(event.getRecordInfo()); |
| @@ -43,6 +43,9 @@ public class RecordEndEventListener implements ApplicationListener<RecordEndEven | @@ -43,6 +43,9 @@ public class RecordEndEventListener implements ApplicationListener<RecordEndEven | ||
| 43 | handlerMap.remove(deviceId + channelId); | 43 | handlerMap.remove(deviceId + channelId); |
| 44 | } | 44 | } |
| 45 | } | 45 | } |
| 46 | + }else { | ||
| 47 | + logger.info("录像查询完成事件触发, 但是订阅为空,取消发送,deviceId:{}, channelId: {}", | ||
| 48 | + event.getRecordInfo().getDeviceId(), event.getRecordInfo().getChannelId()); | ||
| 46 | } | 49 | } |
| 47 | } | 50 | } |
| 48 | 51 | ||
| @@ -53,6 +56,7 @@ public class RecordEndEventListener implements ApplicationListener<RecordEndEven | @@ -53,6 +56,7 @@ public class RecordEndEventListener implements ApplicationListener<RecordEndEven | ||
| 53 | * @param recordEndEventHandler | 56 | * @param recordEndEventHandler |
| 54 | */ | 57 | */ |
| 55 | public void addEndEventHandler(String device, String channelId, RecordEndEventHandler recordEndEventHandler) { | 58 | public void addEndEventHandler(String device, String channelId, RecordEndEventHandler recordEndEventHandler) { |
| 59 | + logger.info("录像查询事件添加监听,deviceId:{}, channelId: {}", device, channelId); | ||
| 56 | handlerMap.put(device + channelId, recordEndEventHandler); | 60 | handlerMap.put(device + channelId, recordEndEventHandler); |
| 57 | } | 61 | } |
| 58 | /** | 62 | /** |
| @@ -61,6 +65,7 @@ public class RecordEndEventListener implements ApplicationListener<RecordEndEven | @@ -61,6 +65,7 @@ public class RecordEndEventListener implements ApplicationListener<RecordEndEven | ||
| 61 | * @param channelId | 65 | * @param channelId |
| 62 | */ | 66 | */ |
| 63 | public void delEndEventHandler(String device, String channelId) { | 67 | public void delEndEventHandler(String device, String channelId) { |
| 68 | + logger.info("录像查询事件移除监听,deviceId:{}, channelId: {}", device, channelId); | ||
| 64 | handlerMap.remove(device + channelId); | 69 | handlerMap.remove(device + channelId); |
| 65 | } | 70 | } |
| 66 | 71 |
src/main/java/com/genersoft/iot/vmp/gb28181/event/subscribe/catalog/CatalogEventLister.java
| @@ -148,13 +148,13 @@ public class CatalogEventLister implements ApplicationListener<CatalogEvent> { | @@ -148,13 +148,13 @@ public class CatalogEventLister implements ApplicationListener<CatalogEvent> { | ||
| 148 | if (event.getDeviceChannels() != null) { | 148 | if (event.getDeviceChannels() != null) { |
| 149 | deviceChannelList.addAll(event.getDeviceChannels()); | 149 | deviceChannelList.addAll(event.getDeviceChannels()); |
| 150 | } | 150 | } |
| 151 | - if (event.getGbStreams() != null && event.getGbStreams().size() > 0){ | 151 | + if (event.getGbStreams() != null && !event.getGbStreams().isEmpty()){ |
| 152 | for (GbStream gbStream : event.getGbStreams()) { | 152 | for (GbStream gbStream : event.getGbStreams()) { |
| 153 | deviceChannelList.add( | 153 | deviceChannelList.add( |
| 154 | gbStreamService.getDeviceChannelListByStreamWithStatus(gbStream, gbStream.getCatalogId(), parentPlatform)); | 154 | gbStreamService.getDeviceChannelListByStreamWithStatus(gbStream, gbStream.getCatalogId(), parentPlatform)); |
| 155 | } | 155 | } |
| 156 | } | 156 | } |
| 157 | - if (deviceChannelList.size() > 0) { | 157 | + if (!deviceChannelList.isEmpty()) { |
| 158 | logger.info("[Catalog事件: {}]平台:{},影响通道{}个", event.getType(), event.getPlatformId(), deviceChannelList.size()); | 158 | logger.info("[Catalog事件: {}]平台:{},影响通道{}个", event.getType(), event.getPlatformId(), deviceChannelList.size()); |
| 159 | try { | 159 | try { |
| 160 | sipCommanderFroPlatform.sendNotifyForCatalogAddOrUpdate(event.getType(), parentPlatform, deviceChannelList, subscribe, null); | 160 | sipCommanderFroPlatform.sendNotifyForCatalogAddOrUpdate(event.getType(), parentPlatform, deviceChannelList, subscribe, null); |
| @@ -163,10 +163,10 @@ public class CatalogEventLister implements ApplicationListener<CatalogEvent> { | @@ -163,10 +163,10 @@ public class CatalogEventLister implements ApplicationListener<CatalogEvent> { | ||
| 163 | logger.error("[命令发送失败] 国标级联 Catalog通知: {}", e.getMessage()); | 163 | logger.error("[命令发送失败] 国标级联 Catalog通知: {}", e.getMessage()); |
| 164 | } | 164 | } |
| 165 | } | 165 | } |
| 166 | - }else if (parentPlatformMap.keySet().size() > 0) { | 166 | + }else if (!parentPlatformMap.keySet().isEmpty()) { |
| 167 | for (String gbId : parentPlatformMap.keySet()) { | 167 | for (String gbId : parentPlatformMap.keySet()) { |
| 168 | List<ParentPlatform> parentPlatforms = parentPlatformMap.get(gbId); | 168 | List<ParentPlatform> parentPlatforms = parentPlatformMap.get(gbId); |
| 169 | - if (parentPlatforms != null && parentPlatforms.size() > 0) { | 169 | + if (parentPlatforms != null && !parentPlatforms.isEmpty()) { |
| 170 | for (ParentPlatform platform : parentPlatforms) { | 170 | for (ParentPlatform platform : parentPlatforms) { |
| 171 | SubscribeInfo subscribeInfo = subscribeHolder.getCatalogSubscribe(platform.getServerGBId()); | 171 | SubscribeInfo subscribeInfo = subscribeHolder.getCatalogSubscribe(platform.getServerGBId()); |
| 172 | if (subscribeInfo == null) { | 172 | if (subscribeInfo == null) { |
src/main/java/com/genersoft/iot/vmp/gb28181/session/SSRCFactory.java
| @@ -38,7 +38,8 @@ public class SSRCFactory { | @@ -38,7 +38,8 @@ public class SSRCFactory { | ||
| 38 | 38 | ||
| 39 | 39 | ||
| 40 | public void initMediaServerSSRC(String mediaServerId, Set<String> usedSet) { | 40 | public void initMediaServerSSRC(String mediaServerId, Set<String> usedSet) { |
| 41 | - String ssrcPrefix = sipConfig.getDomain().substring(3, 8); | 41 | + String sipDomain = sipConfig.getDomain(); |
| 42 | + String ssrcPrefix = sipDomain.length() >= 8 ? sipDomain.substring(3, 8) : sipDomain; | ||
| 42 | String redisKey = SSRC_INFO_KEY + userSetting.getServerId() + "_" + mediaServerId; | 43 | String redisKey = SSRC_INFO_KEY + userSetting.getServerId() + "_" + mediaServerId; |
| 43 | List<String> ssrcList = new ArrayList<>(); | 44 | List<String> ssrcList = new ArrayList<>(); |
| 44 | for (int i = 1; i < MAX_STREAM_COUNT; i++) { | 45 | for (int i = 1; i < MAX_STREAM_COUNT; i++) { |
src/main/java/com/genersoft/iot/vmp/gb28181/session/VideoStreamSessionManager.java
| @@ -75,6 +75,33 @@ public class VideoStreamSessionManager { | @@ -75,6 +75,33 @@ public class VideoStreamSessionManager { | ||
| 75 | return (SsrcTransaction)redisTemplate.opsForValue().get(scanResult.get(0)); | 75 | return (SsrcTransaction)redisTemplate.opsForValue().get(scanResult.get(0)); |
| 76 | } | 76 | } |
| 77 | 77 | ||
| 78 | + public SsrcTransaction getSsrcTransactionByCallId(String callId){ | ||
| 79 | + | ||
| 80 | + if (ObjectUtils.isEmpty(callId)) { | ||
| 81 | + return null; | ||
| 82 | + } | ||
| 83 | + String key = VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX + userSetting.getServerId() + "_*_*_" + callId+ "_*"; | ||
| 84 | + List<Object> scanResult = RedisUtil.scan(redisTemplate, key); | ||
| 85 | + if (!scanResult.isEmpty()) { | ||
| 86 | + return (SsrcTransaction)redisTemplate.opsForValue().get(scanResult.get(0)); | ||
| 87 | + }else { | ||
| 88 | + key = VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX + userSetting.getServerId() + "_*_*_play_*"; | ||
| 89 | + scanResult = RedisUtil.scan(redisTemplate, key); | ||
| 90 | + if (scanResult.isEmpty()) { | ||
| 91 | + return null; | ||
| 92 | + } | ||
| 93 | + for (Object keyObj : scanResult) { | ||
| 94 | + SsrcTransaction ssrcTransaction = (SsrcTransaction)redisTemplate.opsForValue().get(keyObj); | ||
| 95 | + if (ssrcTransaction.getSipTransactionInfo() != null && | ||
| 96 | + ssrcTransaction.getSipTransactionInfo().getCallId().equals(callId)) { | ||
| 97 | + return ssrcTransaction; | ||
| 98 | + } | ||
| 99 | + } | ||
| 100 | + return null; | ||
| 101 | + } | ||
| 102 | + | ||
| 103 | + } | ||
| 104 | + | ||
| 78 | public List<SsrcTransaction> getSsrcTransactionForAll(String deviceId, String channelId, String callId, String stream){ | 105 | public List<SsrcTransaction> getSsrcTransactionForAll(String deviceId, String channelId, String callId, String stream){ |
| 79 | if (ObjectUtils.isEmpty(deviceId)) { | 106 | if (ObjectUtils.isEmpty(deviceId)) { |
| 80 | deviceId ="*"; | 107 | deviceId ="*"; |
| @@ -117,8 +144,19 @@ public class VideoStreamSessionManager { | @@ -117,8 +144,19 @@ public class VideoStreamSessionManager { | ||
| 117 | } | 144 | } |
| 118 | 145 | ||
| 119 | public void remove(String deviceId, String channelId, String stream) { | 146 | public void remove(String deviceId, String channelId, String stream) { |
| 120 | - SsrcTransaction ssrcTransaction = getSsrcTransaction(deviceId, channelId, null, stream); | ||
| 121 | - if (ssrcTransaction == null) { | 147 | + List<SsrcTransaction> ssrcTransactionList = getSsrcTransactionForAll(deviceId, channelId, null, stream); |
| 148 | + if (ssrcTransactionList == null || ssrcTransactionList.isEmpty()) { | ||
| 149 | + return; | ||
| 150 | + } | ||
| 151 | + for (SsrcTransaction ssrcTransaction : ssrcTransactionList) { | ||
| 152 | + redisTemplate.delete(VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX + userSetting.getServerId() + "_" | ||
| 153 | + + deviceId + "_" + channelId + "_" + ssrcTransaction.getCallId() + "_" + ssrcTransaction.getStream()); | ||
| 154 | + } | ||
| 155 | + } | ||
| 156 | + | ||
| 157 | + public void removeByCallId(String deviceId, String channelId, String callId) { | ||
| 158 | + SsrcTransaction ssrcTransaction = getSsrcTransaction(deviceId, channelId, callId, null); | ||
| 159 | + if (ssrcTransaction == null ) { | ||
| 122 | return; | 160 | return; |
| 123 | } | 161 | } |
| 124 | redisTemplate.delete(VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX + userSetting.getServerId() + "_" | 162 | redisTemplate.delete(VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX + userSetting.getServerId() + "_" |
src/main/java/com/genersoft/iot/vmp/gb28181/task/SipRunner.java
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPSender.java
| @@ -66,17 +66,17 @@ public class SIPSender { | @@ -66,17 +66,17 @@ public class SIPSender { | ||
| 66 | // 添加错误订阅 | 66 | // 添加错误订阅 |
| 67 | if (errorEvent != null) { | 67 | if (errorEvent != null) { |
| 68 | sipSubscribe.addErrorSubscribe(callIdHeader.getCallId(), (eventResult -> { | 68 | sipSubscribe.addErrorSubscribe(callIdHeader.getCallId(), (eventResult -> { |
| 69 | - errorEvent.response(eventResult); | ||
| 70 | sipSubscribe.removeErrorSubscribe(eventResult.callId); | 69 | sipSubscribe.removeErrorSubscribe(eventResult.callId); |
| 71 | sipSubscribe.removeOkSubscribe(eventResult.callId); | 70 | sipSubscribe.removeOkSubscribe(eventResult.callId); |
| 71 | + errorEvent.response(eventResult); | ||
| 72 | })); | 72 | })); |
| 73 | } | 73 | } |
| 74 | // 添加订阅 | 74 | // 添加订阅 |
| 75 | if (okEvent != null) { | 75 | if (okEvent != null) { |
| 76 | sipSubscribe.addOkSubscribe(callIdHeader.getCallId(), eventResult -> { | 76 | sipSubscribe.addOkSubscribe(callIdHeader.getCallId(), eventResult -> { |
| 77 | - okEvent.response(eventResult); | ||
| 78 | sipSubscribe.removeOkSubscribe(eventResult.callId); | 77 | sipSubscribe.removeOkSubscribe(eventResult.callId); |
| 79 | sipSubscribe.removeErrorSubscribe(eventResult.callId); | 78 | sipSubscribe.removeErrorSubscribe(eventResult.callId); |
| 79 | + okEvent.response(eventResult); | ||
| 80 | }); | 80 | }); |
| 81 | } | 81 | } |
| 82 | if ("TCP".equals(transport)) { | 82 | if ("TCP".equals(transport)) { |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderProvider.java
| @@ -164,6 +164,7 @@ public class SIPRequestHeaderProvider { | @@ -164,6 +164,7 @@ public class SIPRequestHeaderProvider { | ||
| 164 | Request request = null; | 164 | Request request = null; |
| 165 | //请求行 | 165 | //请求行 |
| 166 | SipURI requestLine = SipFactory.getInstance().createAddressFactory().createSipURI(channelId, device.getHostAddress()); | 166 | SipURI requestLine = SipFactory.getInstance().createAddressFactory().createSipURI(channelId, device.getHostAddress()); |
| 167 | +// SipURI requestLine = SipFactory.getInstance().createAddressFactory().createSipURI(device.getDeviceId(), device.getHostAddress()); | ||
| 167 | // via | 168 | // via |
| 168 | ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>(); | 169 | ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>(); |
| 169 | ViaHeader viaHeader = SipFactory.getInstance().createHeaderFactory().createViaHeader(sipLayer.getLocalIp(device.getLocalIp()), sipConfig.getPort(), device.getTransport(), SipUtils.getNewViaTag()); | 170 | ViaHeader viaHeader = SipFactory.getInstance().createHeaderFactory().createViaHeader(sipLayer.getLocalIp(device.getLocalIp()), sipConfig.getPort(), device.getTransport(), SipUtils.getNewViaTag()); |
| @@ -174,6 +175,7 @@ public class SIPRequestHeaderProvider { | @@ -174,6 +175,7 @@ public class SIPRequestHeaderProvider { | ||
| 174 | FromHeader fromHeader = SipFactory.getInstance().createHeaderFactory().createFromHeader(fromAddress, transactionInfo.getFromTag()); | 175 | FromHeader fromHeader = SipFactory.getInstance().createHeaderFactory().createFromHeader(fromAddress, transactionInfo.getFromTag()); |
| 175 | //to | 176 | //to |
| 176 | SipURI toSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(channelId,device.getHostAddress()); | 177 | SipURI toSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(channelId,device.getHostAddress()); |
| 178 | +// SipURI toSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(device.getDeviceId(),device.getHostAddress()); | ||
| 177 | Address toAddress = SipFactory.getInstance().createAddressFactory().createAddress(toSipURI); | 179 | Address toAddress = SipFactory.getInstance().createAddressFactory().createAddress(toSipURI); |
| 178 | ToHeader toHeader = SipFactory.getInstance().createHeaderFactory().createToHeader(toAddress, transactionInfo.getToTag()); | 180 | ToHeader toHeader = SipFactory.getInstance().createHeaderFactory().createToHeader(toAddress, transactionInfo.getToTag()); |
| 179 | 181 |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java
| @@ -40,6 +40,7 @@ import javax.sip.SipFactory; | @@ -40,6 +40,7 @@ import javax.sip.SipFactory; | ||
| 40 | import javax.sip.header.CallIdHeader; | 40 | import javax.sip.header.CallIdHeader; |
| 41 | import javax.sip.message.Request; | 41 | import javax.sip.message.Request; |
| 42 | import java.text.ParseException; | 42 | import java.text.ParseException; |
| 43 | +import java.util.List; | ||
| 43 | 44 | ||
| 44 | /** | 45 | /** |
| 45 | * @description:设备能力接口,用于定义设备的控制、查询能力 | 46 | * @description:设备能力接口,用于定义设备的控制、查询能力 |
| @@ -374,7 +375,8 @@ public class SIPCommander implements ISIPCommander { | @@ -374,7 +375,8 @@ public class SIPCommander implements ISIPCommander { | ||
| 374 | }), e -> { | 375 | }), e -> { |
| 375 | ResponseEvent responseEvent = (ResponseEvent) e.event; | 376 | ResponseEvent responseEvent = (ResponseEvent) e.event; |
| 376 | SIPResponse response = (SIPResponse) responseEvent.getResponse(); | 377 | SIPResponse response = (SIPResponse) responseEvent.getResponse(); |
| 377 | - streamSession.put(device.getDeviceId(), channelId, "play", stream, ssrcInfo.getSsrc(), mediaServerItem.getId(), response, | 378 | + String callId = response.getCallIdHeader().getCallId(); |
| 379 | + streamSession.put(device.getDeviceId(), channelId, callId, stream, ssrcInfo.getSsrc(), mediaServerItem.getId(), response, | ||
| 378 | InviteSessionType.PLAY); | 380 | InviteSessionType.PLAY); |
| 379 | okEvent.response(e); | 381 | okEvent.response(e); |
| 380 | }); | 382 | }); |
| @@ -676,22 +678,26 @@ public class SIPCommander implements ISIPCommander { | @@ -676,22 +678,26 @@ public class SIPCommander implements ISIPCommander { | ||
| 676 | */ | 678 | */ |
| 677 | @Override | 679 | @Override |
| 678 | public void streamByeCmd(Device device, String channelId, String stream, String callId, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException, SsrcTransactionNotFoundException { | 680 | public void streamByeCmd(Device device, String channelId, String stream, String callId, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException, SsrcTransactionNotFoundException { |
| 679 | - SsrcTransaction ssrcTransaction; | ||
| 680 | - if (callId != null) { | ||
| 681 | - ssrcTransaction = streamSession.getSsrcTransaction(null, null, callId, null); | ||
| 682 | - }else { | ||
| 683 | - ssrcTransaction = streamSession.getSsrcTransaction(device.getDeviceId(), channelId, null, stream); | 681 | + if (device == null) { |
| 682 | + logger.warn("[发送BYE] device为null"); | ||
| 683 | + return; | ||
| 684 | } | 684 | } |
| 685 | - if (ssrcTransaction == null) { | 685 | + List<SsrcTransaction> ssrcTransactionList = streamSession.getSsrcTransactionForAll(device.getDeviceId(), channelId, callId, stream); |
| 686 | + if (ssrcTransactionList == null || ssrcTransactionList.isEmpty()) { | ||
| 687 | + logger.info("[发送BYE] 未找到事务信息,设备: device: {}, channel: {}", device.getDeviceId(), channelId); | ||
| 686 | throw new SsrcTransactionNotFoundException(device.getDeviceId(), channelId, callId, stream); | 688 | throw new SsrcTransactionNotFoundException(device.getDeviceId(), channelId, callId, stream); |
| 687 | } | 689 | } |
| 688 | 690 | ||
| 689 | - mediaServerService.releaseSsrc(ssrcTransaction.getMediaServerId(), ssrcTransaction.getSsrc()); | ||
| 690 | - mediaServerService.closeRTPServer(ssrcTransaction.getMediaServerId(), ssrcTransaction.getStream()); | ||
| 691 | - streamSession.remove(ssrcTransaction.getDeviceId(), ssrcTransaction.getChannelId(), ssrcTransaction.getStream()); | 691 | + for (SsrcTransaction ssrcTransaction : ssrcTransactionList) { |
| 692 | + logger.info("[发送BYE] 设备: device: {}, channel: {}, callId: {}", device.getDeviceId(), channelId, ssrcTransaction.getCallId()); | ||
| 693 | + mediaServerService.releaseSsrc(ssrcTransaction.getMediaServerId(), ssrcTransaction.getSsrc()); | ||
| 692 | 694 | ||
| 693 | - Request byteRequest = headerProvider.createByteRequest(device, channelId, ssrcTransaction.getSipTransactionInfo()); | ||
| 694 | - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), byteRequest, null, okEvent); | 695 | + mediaServerService.closeRTPServer(ssrcTransaction.getMediaServerId(), ssrcTransaction.getStream()); |
| 696 | + streamSession.removeByCallId(ssrcTransaction.getDeviceId(), ssrcTransaction.getChannelId(), ssrcTransaction.getCallId()); | ||
| 697 | + Request byteRequest = headerProvider.createByteRequest(device, channelId, ssrcTransaction.getSipTransactionInfo()); | ||
| 698 | + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), byteRequest, null, okEvent); | ||
| 699 | + | ||
| 700 | + } | ||
| 695 | } | 701 | } |
| 696 | 702 | ||
| 697 | @Override | 703 | @Override |
| @@ -1000,7 +1006,7 @@ public class SIPCommander implements ISIPCommander { | @@ -1000,7 +1006,7 @@ public class SIPCommander implements ISIPCommander { | ||
| 1000 | catalogXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n"); | 1006 | catalogXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n"); |
| 1001 | catalogXml.append("</Query>\r\n"); | 1007 | catalogXml.append("</Query>\r\n"); |
| 1002 | 1008 | ||
| 1003 | - | 1009 | + |
| 1004 | 1010 | ||
| 1005 | Request request = headerProvider.createMessageRequest(device, catalogXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); | 1011 | Request request = headerProvider.createMessageRequest(device, catalogXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); |
| 1006 | 1012 |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java
| @@ -579,7 +579,7 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { | @@ -579,7 +579,7 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { | ||
| 579 | 579 | ||
| 580 | @Override | 580 | @Override |
| 581 | public void sendNotifyForCatalogAddOrUpdate(String type, ParentPlatform parentPlatform, List<DeviceChannel> deviceChannels, SubscribeInfo subscribeInfo, Integer index) throws InvalidArgumentException, ParseException, NoSuchFieldException, SipException, IllegalAccessException { | 581 | public void sendNotifyForCatalogAddOrUpdate(String type, ParentPlatform parentPlatform, List<DeviceChannel> deviceChannels, SubscribeInfo subscribeInfo, Integer index) throws InvalidArgumentException, ParseException, NoSuchFieldException, SipException, IllegalAccessException { |
| 582 | - if (parentPlatform == null || deviceChannels == null || deviceChannels.size() == 0 || subscribeInfo == null) { | 582 | + if (parentPlatform == null || deviceChannels == null || deviceChannels.isEmpty() || subscribeInfo == null) { |
| 583 | return; | 583 | return; |
| 584 | } | 584 | } |
| 585 | if (index == null) { | 585 | if (index == null) { |
| @@ -597,6 +597,7 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { | @@ -597,6 +597,7 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { | ||
| 597 | Integer finalIndex = index; | 597 | Integer finalIndex = index; |
| 598 | String catalogXmlContent = getCatalogXmlContentForCatalogAddOrUpdate(parentPlatform, channels, | 598 | String catalogXmlContent = getCatalogXmlContentForCatalogAddOrUpdate(parentPlatform, channels, |
| 599 | deviceChannels.size(), type, subscribeInfo); | 599 | deviceChannels.size(), type, subscribeInfo); |
| 600 | + logger.info("[发送NOTIFY通知]类型: {},发送数量: {}", type, channels.size()); | ||
| 600 | sendNotify(parentPlatform, catalogXmlContent, subscribeInfo, eventResult -> { | 601 | sendNotify(parentPlatform, catalogXmlContent, subscribeInfo, eventResult -> { |
| 601 | logger.error("发送NOTIFY通知消息失败。错误:{} {}", eventResult.statusCode, eventResult.msg); | 602 | logger.error("发送NOTIFY通知消息失败。错误:{} {}", eventResult.statusCode, eventResult.msg); |
| 602 | }, (eventResult -> { | 603 | }, (eventResult -> { |
| @@ -620,7 +621,7 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { | @@ -620,7 +621,7 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { | ||
| 620 | 621 | ||
| 621 | SIPRequest notifyRequest = headerProviderPlatformProvider.createNotifyRequest(parentPlatform, catalogXmlContent, subscribeInfo); | 622 | SIPRequest notifyRequest = headerProviderPlatformProvider.createNotifyRequest(parentPlatform, catalogXmlContent, subscribeInfo); |
| 622 | 623 | ||
| 623 | - sipSender.transmitRequest(parentPlatform.getDeviceIp(), notifyRequest); | 624 | + sipSender.transmitRequest(parentPlatform.getDeviceIp(), notifyRequest, errorEvent, okEvent); |
| 624 | } | 625 | } |
| 625 | 626 | ||
| 626 | private String getCatalogXmlContentForCatalogAddOrUpdate(ParentPlatform parentPlatform, List<DeviceChannel> channels, int sumNum, String type, SubscribeInfo subscribeInfo) { | 627 | private String getCatalogXmlContentForCatalogAddOrUpdate(ParentPlatform parentPlatform, List<DeviceChannel> channels, int sumNum, String type, SubscribeInfo subscribeInfo) { |
| @@ -632,9 +633,9 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { | @@ -632,9 +633,9 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { | ||
| 632 | .append("<CmdType>Catalog</CmdType>\r\n") | 633 | .append("<CmdType>Catalog</CmdType>\r\n") |
| 633 | .append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n") | 634 | .append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n") |
| 634 | .append("<DeviceID>" + parentPlatform.getDeviceGBId() + "</DeviceID>\r\n") | 635 | .append("<DeviceID>" + parentPlatform.getDeviceGBId() + "</DeviceID>\r\n") |
| 635 | - .append("<SumNum>1</SumNum>\r\n") | 636 | + .append("<SumNum>"+ sumNum +"</SumNum>\r\n") |
| 636 | .append("<DeviceList Num=\"" + channels.size() + "\">\r\n"); | 637 | .append("<DeviceList Num=\"" + channels.size() + "\">\r\n"); |
| 637 | - if (channels.size() > 0) { | 638 | + if (!channels.isEmpty()) { |
| 638 | for (DeviceChannel channel : channels) { | 639 | for (DeviceChannel channel : channels) { |
| 639 | if (parentPlatform.getServerGBId().equals(channel.getParentId())) { | 640 | if (parentPlatform.getServerGBId().equals(channel.getParentId())) { |
| 640 | channel.setParentId(parentPlatform.getDeviceGBId()); | 641 | channel.setParentId(parentPlatform.getDeviceGBId()); |
| @@ -701,6 +702,7 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { | @@ -701,6 +702,7 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { | ||
| 701 | }else { | 702 | }else { |
| 702 | channels = deviceChannels.subList(index, deviceChannels.size()); | 703 | channels = deviceChannels.subList(index, deviceChannels.size()); |
| 703 | } | 704 | } |
| 705 | + logger.info("[发送NOTIFY通知]类型: {},发送数量: {}", type, channels.size()); | ||
| 704 | Integer finalIndex = index; | 706 | Integer finalIndex = index; |
| 705 | String catalogXmlContent = getCatalogXmlContentForCatalogOther(parentPlatform, channels, type); | 707 | String catalogXmlContent = getCatalogXmlContentForCatalogOther(parentPlatform, channels, type); |
| 706 | sendNotify(parentPlatform, catalogXmlContent, subscribeInfo, eventResult -> { | 708 | sendNotify(parentPlatform, catalogXmlContent, subscribeInfo, eventResult -> { |
| @@ -747,13 +749,14 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { | @@ -747,13 +749,14 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { | ||
| 747 | if ( parentPlatform ==null) { | 749 | if ( parentPlatform ==null) { |
| 748 | return ; | 750 | return ; |
| 749 | } | 751 | } |
| 752 | + logger.info("[国标级联] 发送录像数据通道: {}", recordInfo.getChannelId()); | ||
| 750 | String characterSet = parentPlatform.getCharacterSet(); | 753 | String characterSet = parentPlatform.getCharacterSet(); |
| 751 | StringBuffer recordXml = new StringBuffer(600); | 754 | StringBuffer recordXml = new StringBuffer(600); |
| 752 | recordXml.append("<?xml version=\"1.0\" encoding=\"" + characterSet + "\"?>\r\n") | 755 | recordXml.append("<?xml version=\"1.0\" encoding=\"" + characterSet + "\"?>\r\n") |
| 753 | .append("<Response>\r\n") | 756 | .append("<Response>\r\n") |
| 754 | .append("<CmdType>RecordInfo</CmdType>\r\n") | 757 | .append("<CmdType>RecordInfo</CmdType>\r\n") |
| 755 | .append("<SN>" +recordInfo.getSn() + "</SN>\r\n") | 758 | .append("<SN>" +recordInfo.getSn() + "</SN>\r\n") |
| 756 | - .append("<DeviceID>" + recordInfo.getChannelId() + "</DeviceID>\r\n") | 759 | + .append("<DeviceID>" + deviceChannel.getChannelId() + "</DeviceID>\r\n") |
| 757 | .append("<SumNum>" + recordInfo.getSumNum() + "</SumNum>\r\n"); | 760 | .append("<SumNum>" + recordInfo.getSumNum() + "</SumNum>\r\n"); |
| 758 | if (recordInfo.getRecordList() == null ) { | 761 | if (recordInfo.getRecordList() == null ) { |
| 759 | recordXml.append("<RecordList Num=\"0\">\r\n"); | 762 | recordXml.append("<RecordList Num=\"0\">\r\n"); |
| @@ -763,7 +766,7 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { | @@ -763,7 +766,7 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { | ||
| 763 | for (RecordItem recordItem : recordInfo.getRecordList()) { | 766 | for (RecordItem recordItem : recordInfo.getRecordList()) { |
| 764 | recordXml.append("<Item>\r\n"); | 767 | recordXml.append("<Item>\r\n"); |
| 765 | if (deviceChannel != null) { | 768 | if (deviceChannel != null) { |
| 766 | - recordXml.append("<DeviceID>" + recordItem.getDeviceId() + "</DeviceID>\r\n") | 769 | + recordXml.append("<DeviceID>" + deviceChannel.getChannelId() + "</DeviceID>\r\n") |
| 767 | .append("<Name>" + recordItem.getName() + "</Name>\r\n") | 770 | .append("<Name>" + recordItem.getName() + "</Name>\r\n") |
| 768 | .append("<StartTime>" + DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(recordItem.getStartTime()) + "</StartTime>\r\n") | 771 | .append("<StartTime>" + DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(recordItem.getStartTime()) + "</StartTime>\r\n") |
| 769 | .append("<EndTime>" + DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(recordItem.getEndTime()) + "</EndTime>\r\n") | 772 | .append("<EndTime>" + DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(recordItem.getEndTime()) + "</EndTime>\r\n") |
| @@ -783,12 +786,14 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { | @@ -783,12 +786,14 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { | ||
| 783 | 786 | ||
| 784 | recordXml.append("</RecordList>\r\n") | 787 | recordXml.append("</RecordList>\r\n") |
| 785 | .append("</Response>\r\n"); | 788 | .append("</Response>\r\n"); |
| 786 | - | 789 | + logger.info("[国标级联] 发送录像数据通道:{}, 内容: {}", recordInfo.getChannelId(), recordXml); |
| 787 | // callid | 790 | // callid |
| 788 | CallIdHeader callIdHeader = sipSender.getNewCallIdHeader(parentPlatform.getDeviceIp(),parentPlatform.getTransport()); | 791 | CallIdHeader callIdHeader = sipSender.getNewCallIdHeader(parentPlatform.getDeviceIp(),parentPlatform.getTransport()); |
| 789 | 792 | ||
| 790 | Request request = headerProviderPlatformProvider.createMessageRequest(parentPlatform, recordXml.toString(), fromTag, SipUtils.getNewViaTag(), callIdHeader); | 793 | Request request = headerProviderPlatformProvider.createMessageRequest(parentPlatform, recordXml.toString(), fromTag, SipUtils.getNewViaTag(), callIdHeader); |
| 791 | - sipSender.transmitRequest(parentPlatform.getDeviceIp(), request); | 794 | + sipSender.transmitRequest(parentPlatform.getDeviceIp(), request, null, eventResult -> { |
| 795 | + logger.info("[国标级联] 发送录像数据通道:{}, 发送成功", recordInfo.getChannelId()); | ||
| 796 | + }); | ||
| 792 | 797 | ||
| 793 | } | 798 | } |
| 794 | 799 |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/ByeRequestProcessor.java
| @@ -128,6 +128,9 @@ public class ByeRequestProcessor extends SIPRequestProcessorParent implements In | @@ -128,6 +128,9 @@ public class ByeRequestProcessor extends SIPRequestProcessorParent implements In | ||
| 128 | redisCatchStorage.deleteSendRTPServer(sendRtpItem.getPlatformId(), sendRtpItem.getChannelId(), | 128 | redisCatchStorage.deleteSendRTPServer(sendRtpItem.getPlatformId(), sendRtpItem.getChannelId(), |
| 129 | callIdHeader.getCallId(), null); | 129 | callIdHeader.getCallId(), null); |
| 130 | zlmServerFactory.stopSendRtpStream(mediaInfo, param); | 130 | zlmServerFactory.stopSendRtpStream(mediaInfo, param); |
| 131 | + if (userSetting.getUseCustomSsrcForParentInvite()) { | ||
| 132 | + mediaServerService.releaseSsrc(mediaInfo.getId(), sendRtpItem.getSsrc()); | ||
| 133 | + } | ||
| 131 | if (sendRtpItem.getPlayType().equals(InviteStreamType.PUSH)) { | 134 | if (sendRtpItem.getPlayType().equals(InviteStreamType.PUSH)) { |
| 132 | ParentPlatform platform = platformService.queryPlatformByServerGBId(sendRtpItem.getPlatformId()); | 135 | ParentPlatform platform = platformService.queryPlatformByServerGBId(sendRtpItem.getPlatformId()); |
| 133 | if (platform != null) { | 136 | if (platform != null) { |
| @@ -167,14 +170,12 @@ public class ByeRequestProcessor extends SIPRequestProcessorParent implements In | @@ -167,14 +170,12 @@ public class ByeRequestProcessor extends SIPRequestProcessorParent implements In | ||
| 167 | } | 170 | } |
| 168 | } | 171 | } |
| 169 | 172 | ||
| 170 | - // 发流端发送的停止 | ||
| 171 | - SsrcTransaction ssrcTransaction = streamSession.getSsrcTransaction(null, null, callIdHeader.getCallId(), null); | ||
| 172 | - if (ssrcTransaction == null ) { | ||
| 173 | - logger.info("[收到bye] 但是无法获取推流信息和发流信息,忽略此请求"); | ||
| 174 | - logger.info(request.toString()); | ||
| 175 | - return; | ||
| 176 | - } | ||
| 177 | - | 173 | + // 可能是设备发送的停止 |
| 174 | + SsrcTransaction ssrcTransaction = streamSession.getSsrcTransactionByCallId(callIdHeader.getCallId()); | ||
| 175 | + if (ssrcTransaction == null) { | ||
| 176 | + return; | ||
| 177 | + } | ||
| 178 | + logger.info("[收到bye] 来自设备:{}, 通道已停止推流: {}", ssrcTransaction.getDeviceId(), ssrcTransaction.getChannelId()); | ||
| 178 | 179 | ||
| 179 | ParentPlatform platform = platformService.queryPlatformByServerGBId(ssrcTransaction.getDeviceId()); | 180 | ParentPlatform platform = platformService.queryPlatformByServerGBId(ssrcTransaction.getDeviceId()); |
| 180 | if (platform != null ) { | 181 | if (platform != null ) { |
| @@ -216,7 +217,7 @@ public class ByeRequestProcessor extends SIPRequestProcessorParent implements In | @@ -216,7 +217,7 @@ public class ByeRequestProcessor extends SIPRequestProcessorParent implements In | ||
| 216 | if (mediaServerItem != null) { | 217 | if (mediaServerItem != null) { |
| 217 | mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcTransaction.getSsrc()); | 218 | mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcTransaction.getSsrc()); |
| 218 | } | 219 | } |
| 219 | - streamSession.remove(device.getDeviceId(), channel.getChannelId(), ssrcTransaction.getStream()); | 220 | + streamSession.removeByCallId(device.getDeviceId(), channel.getChannelId(), ssrcTransaction.getCallId()); |
| 220 | if (ssrcTransaction.getType() == InviteSessionType.BROADCAST) { | 221 | if (ssrcTransaction.getType() == InviteSessionType.BROADCAST) { |
| 221 | // 查找来源的对讲设备,发送停止 | 222 | // 查找来源的对讲设备,发送停止 |
| 222 | Device sourceDevice = storager.queryVideoDeviceByPlatformIdAndChannelId(ssrcTransaction.getDeviceId(), ssrcTransaction.getChannelId()); | 223 | Device sourceDevice = storager.queryVideoDeviceByPlatformIdAndChannelId(ssrcTransaction.getDeviceId(), ssrcTransaction.getChannelId()); |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java
| @@ -152,7 +152,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements | @@ -152,7 +152,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements | ||
| 152 | String requesterId = SipUtils.getUserIdFromFromHeader(request); | 152 | String requesterId = SipUtils.getUserIdFromFromHeader(request); |
| 153 | CallIdHeader callIdHeader = (CallIdHeader) request.getHeader(CallIdHeader.NAME); | 153 | CallIdHeader callIdHeader = (CallIdHeader) request.getHeader(CallIdHeader.NAME); |
| 154 | if (requesterId == null || channelId == null) { | 154 | if (requesterId == null || channelId == null) { |
| 155 | - logger.info("无法从FromHeader的Address中获取到平台id,返回400"); | 155 | + logger.info("无法从请求中获取到平台id,返回400"); |
| 156 | // 参数不全, 发400,请求错误 | 156 | // 参数不全, 发400,请求错误 |
| 157 | try { | 157 | try { |
| 158 | responseAck(request, Response.BAD_REQUEST); | 158 | responseAck(request, Response.BAD_REQUEST); |
| @@ -162,6 +162,8 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements | @@ -162,6 +162,8 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements | ||
| 162 | return; | 162 | return; |
| 163 | } | 163 | } |
| 164 | 164 | ||
| 165 | + logger.info("[INVITE] requesterId: {}, callId: {}, 来自:{}:{}", | ||
| 166 | + requesterId, callIdHeader.getCallId(), request.getRemoteAddress(), request.getRemotePort()); | ||
| 165 | 167 | ||
| 166 | // 查询请求是否来自上级平台\设备 | 168 | // 查询请求是否来自上级平台\设备 |
| 167 | ParentPlatform platform = storager.queryParentPlatByServerGBId(requesterId); | 169 | ParentPlatform platform = storager.queryParentPlatByServerGBId(requesterId); |
| @@ -409,7 +411,16 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements | @@ -409,7 +411,16 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements | ||
| 409 | // 非严格模式端口不统一, 增加兼容性,修改为一个不为0的端口 | 411 | // 非严格模式端口不统一, 增加兼容性,修改为一个不为0的端口 |
| 410 | localPort = new Random().nextInt(65535) + 1; | 412 | localPort = new Random().nextInt(65535) + 1; |
| 411 | } | 413 | } |
| 412 | - content.append("m=video " + localPort + " RTP/AVP 96\r\n"); | 414 | + if (sendRtpItem.isTcp()) { |
| 415 | + content.append("m=video " + localPort + " TCP/RTP/AVP 96\r\n"); | ||
| 416 | + if (!sendRtpItem.isTcpActive()) { | ||
| 417 | + content.append("a=setup:active\r\n"); | ||
| 418 | + } else { | ||
| 419 | + content.append("a=setup:passive\r\n"); | ||
| 420 | + } | ||
| 421 | + }else { | ||
| 422 | + content.append("m=video " + localPort + " RTP/AVP 96\r\n"); | ||
| 423 | + } | ||
| 413 | content.append("a=sendonly\r\n"); | 424 | content.append("a=sendonly\r\n"); |
| 414 | content.append("a=rtpmap:96 PS/90000\r\n"); | 425 | content.append("a=rtpmap:96 PS/90000\r\n"); |
| 415 | content.append("y=" + sendRtpItem.getSsrc() + "\r\n"); | 426 | content.append("y=" + sendRtpItem.getSsrc() + "\r\n"); |
| @@ -524,7 +535,10 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements | @@ -524,7 +535,10 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements | ||
| 524 | } | 535 | } |
| 525 | }); | 536 | }); |
| 526 | } else { | 537 | } else { |
| 527 | - | 538 | + sendRtpItem.setPlayType(InviteStreamType.PLAY); |
| 539 | + String streamId = String.format("%s_%s", device.getDeviceId(), channelId); | ||
| 540 | + sendRtpItem.setStreamId(streamId); | ||
| 541 | + redisCatchStorage.updateSendRTPSever(sendRtpItem); | ||
| 528 | SSRCInfo ssrcInfo = playService.play(mediaServerItem, device.getDeviceId(), channelId, ssrc, ((code, msg, data) -> { | 542 | SSRCInfo ssrcInfo = playService.play(mediaServerItem, device.getDeviceId(), channelId, ssrc, ((code, msg, data) -> { |
| 529 | if (code == InviteErrorCode.SUCCESS.getCode()) { | 543 | if (code == InviteErrorCode.SUCCESS.getCode()) { |
| 530 | hookEvent.run(code, msg, data); | 544 | hookEvent.run(code, msg, data); |
| @@ -536,9 +550,6 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements | @@ -536,9 +550,6 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements | ||
| 536 | errorEvent.run(code, msg, data); | 550 | errorEvent.run(code, msg, data); |
| 537 | } | 551 | } |
| 538 | })); | 552 | })); |
| 539 | - sendRtpItem.setPlayType(InviteStreamType.PLAY); | ||
| 540 | - String streamId = String.format("%s_%s", device.getDeviceId(), channelId); | ||
| 541 | - sendRtpItem.setStream(streamId); | ||
| 542 | sendRtpItem.setSsrc(ssrcInfo.getSsrc()); | 553 | sendRtpItem.setSsrc(ssrcInfo.getSsrc()); |
| 543 | redisCatchStorage.updateSendRTPSever(sendRtpItem); | 554 | redisCatchStorage.updateSendRTPSever(sendRtpItem); |
| 544 | 555 | ||
| @@ -721,8 +732,6 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements | @@ -721,8 +732,6 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements | ||
| 721 | zlmHttpHookSubscribe.removeSubscribe(hookSubscribe); | 732 | zlmHttpHookSubscribe.removeSubscribe(hookSubscribe); |
| 722 | dynamicTask.stop(callIdHeader.getCallId()); | 733 | dynamicTask.stop(callIdHeader.getCallId()); |
| 723 | } | 734 | } |
| 724 | - | ||
| 725 | - | ||
| 726 | } else if ("push".equals(gbStream.getStreamType())) { | 735 | } else if ("push".equals(gbStream.getStreamType())) { |
| 727 | if (!platform.isStartOfflinePush()) { | 736 | if (!platform.isStartOfflinePush()) { |
| 728 | // 平台设置中关闭了拉起离线的推流则直接回复 | 737 | // 平台设置中关闭了拉起离线的推流则直接回复 |
| @@ -745,13 +754,10 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements | @@ -745,13 +754,10 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements | ||
| 745 | dynamicTask.startDelay(callIdHeader.getCallId(), () -> { | 754 | dynamicTask.startDelay(callIdHeader.getCallId(), () -> { |
| 746 | logger.info("[ app={}, stream={} ] 等待设备开始推流超时", gbStream.getApp(), gbStream.getStream()); | 755 | logger.info("[ app={}, stream={} ] 等待设备开始推流超时", gbStream.getApp(), gbStream.getStream()); |
| 747 | try { | 756 | try { |
| 757 | + redisPushStreamResponseListener.removeEvent(gbStream.getApp(), gbStream.getStream()); | ||
| 748 | mediaListManager.removedChannelOnlineEventLister(gbStream.getApp(), gbStream.getStream()); | 758 | mediaListManager.removedChannelOnlineEventLister(gbStream.getApp(), gbStream.getStream()); |
| 749 | responseAck(request, Response.REQUEST_TIMEOUT); // 超时 | 759 | responseAck(request, Response.REQUEST_TIMEOUT); // 超时 |
| 750 | - } catch (SipException e) { | ||
| 751 | - logger.error("未处理的异常 ", e); | ||
| 752 | - } catch (InvalidArgumentException e) { | ||
| 753 | - logger.error("未处理的异常 ", e); | ||
| 754 | - } catch (ParseException e) { | 760 | + } catch (SipException | InvalidArgumentException | ParseException e) { |
| 755 | logger.error("未处理的异常 ", e); | 761 | logger.error("未处理的异常 ", e); |
| 756 | } | 762 | } |
| 757 | }, userSetting.getPlatformPlayTimeout()); | 763 | }, userSetting.getPlatformPlayTimeout()); |
| @@ -762,6 +768,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements | @@ -762,6 +768,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements | ||
| 762 | // 添加在本机上线的通知 | 768 | // 添加在本机上线的通知 |
| 763 | mediaListManager.addChannelOnlineEventLister(gbStream.getApp(), gbStream.getStream(), (app, stream, serverId) -> { | 769 | mediaListManager.addChannelOnlineEventLister(gbStream.getApp(), gbStream.getStream(), (app, stream, serverId) -> { |
| 764 | dynamicTask.stop(callIdHeader.getCallId()); | 770 | dynamicTask.stop(callIdHeader.getCallId()); |
| 771 | + redisPushStreamResponseListener.removeEvent(gbStream.getApp(), gbStream.getStream()); | ||
| 765 | if (serverId.equals(userSetting.getServerId())) { | 772 | if (serverId.equals(userSetting.getServerId())) { |
| 766 | SendRtpItem sendRtpItem = zlmServerFactory.createSendRtpItem(mediaServerItem, addressStr, finalPort, ssrc, requesterId, | 773 | SendRtpItem sendRtpItem = zlmServerFactory.createSendRtpItem(mediaServerItem, addressStr, finalPort, ssrc, requesterId, |
| 767 | app, stream, channelId, mediaTransmissionTCP, platform.isRtcp()); | 774 | app, stream, channelId, mediaTransmissionTCP, platform.isRtcp()); |
| @@ -826,7 +833,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements | @@ -826,7 +833,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements | ||
| 826 | // 发送redis消息 | 833 | // 发送redis消息 |
| 827 | redisGbPlayMsgListener.sendMsg(streamPushItem.getServerId(), streamPushItem.getMediaServerId(), | 834 | redisGbPlayMsgListener.sendMsg(streamPushItem.getServerId(), streamPushItem.getMediaServerId(), |
| 828 | streamPushItem.getApp(), streamPushItem.getStream(), addressStr, port, ssrc, requesterId, | 835 | streamPushItem.getApp(), streamPushItem.getStream(), addressStr, port, ssrc, requesterId, |
| 829 | - channelId, mediaTransmissionTCP, platform.isRtcp(), null, responseSendItemMsg -> { | 836 | + channelId, mediaTransmissionTCP, platform.isRtcp(),platform.getName(), responseSendItemMsg -> { |
| 830 | SendRtpItem sendRtpItem = responseSendItemMsg.getSendRtpItem(); | 837 | SendRtpItem sendRtpItem = responseSendItemMsg.getSendRtpItem(); |
| 831 | if (sendRtpItem == null || responseSendItemMsg.getMediaServerItem() == null) { | 838 | if (sendRtpItem == null || responseSendItemMsg.getMediaServerItem() == null) { |
| 832 | logger.warn("服务器端口资源不足"); | 839 | logger.warn("服务器端口资源不足"); |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/NotifyRequestForCatalogProcessor.java
| @@ -13,6 +13,7 @@ import com.genersoft.iot.vmp.gb28181.utils.SipUtils; | @@ -13,6 +13,7 @@ import com.genersoft.iot.vmp.gb28181.utils.SipUtils; | ||
| 13 | import com.genersoft.iot.vmp.gb28181.utils.XmlUtil; | 13 | import com.genersoft.iot.vmp.gb28181.utils.XmlUtil; |
| 14 | import com.genersoft.iot.vmp.service.IDeviceChannelService; | 14 | import com.genersoft.iot.vmp.service.IDeviceChannelService; |
| 15 | import com.genersoft.iot.vmp.storager.IRedisCatchStorage; | 15 | import com.genersoft.iot.vmp.storager.IRedisCatchStorage; |
| 16 | +import com.genersoft.iot.vmp.utils.DateUtil; | ||
| 16 | import org.dom4j.DocumentException; | 17 | import org.dom4j.DocumentException; |
| 17 | import org.dom4j.Element; | 18 | import org.dom4j.Element; |
| 18 | import org.slf4j.Logger; | 19 | import org.slf4j.Logger; |
| @@ -185,6 +186,7 @@ public class NotifyRequestForCatalogProcessor extends SIPRequestProcessorParent | @@ -185,6 +186,7 @@ public class NotifyRequestForCatalogProcessor extends SIPRequestProcessorParent | ||
| 185 | // 判断此通道是否存在 | 186 | // 判断此通道是否存在 |
| 186 | DeviceChannel deviceChannel = deviceChannelService.getOne(deviceId, channel.getChannelId()); | 187 | DeviceChannel deviceChannel = deviceChannelService.getOne(deviceId, channel.getChannelId()); |
| 187 | if (deviceChannel != null) { | 188 | if (deviceChannel != null) { |
| 189 | + logger.info("[增加通道] 已存在,不发送通知只更新,设备: {}, 通道 {}", device.getDeviceId(), channel.getChannelId()); | ||
| 188 | channel.setId(deviceChannel.getId()); | 190 | channel.setId(deviceChannel.getId()); |
| 189 | updateChannelMap.put(channel.getChannelId(), channel); | 191 | updateChannelMap.put(channel.getChannelId(), channel); |
| 190 | if (updateChannelMap.keySet().size() > 300) { | 192 | if (updateChannelMap.keySet().size() > 300) { |
| @@ -222,6 +224,7 @@ public class NotifyRequestForCatalogProcessor extends SIPRequestProcessorParent | @@ -222,6 +224,7 @@ public class NotifyRequestForCatalogProcessor extends SIPRequestProcessorParent | ||
| 222 | DeviceChannel deviceChannelForUpdate = deviceChannelService.getOne(deviceId, channel.getChannelId()); | 224 | DeviceChannel deviceChannelForUpdate = deviceChannelService.getOne(deviceId, channel.getChannelId()); |
| 223 | if (deviceChannelForUpdate != null) { | 225 | if (deviceChannelForUpdate != null) { |
| 224 | channel.setId(deviceChannelForUpdate.getId()); | 226 | channel.setId(deviceChannelForUpdate.getId()); |
| 227 | + channel.setUpdateTime(DateUtil.getNow()); | ||
| 225 | updateChannelMap.put(channel.getChannelId(), channel); | 228 | updateChannelMap.put(channel.getChannelId(), channel); |
| 226 | if (updateChannelMap.keySet().size() > 300) { | 229 | if (updateChannelMap.keySet().size() > 300) { |
| 227 | executeSaveForUpdate(); | 230 | executeSaveForUpdate(); |
| @@ -244,11 +247,11 @@ public class NotifyRequestForCatalogProcessor extends SIPRequestProcessorParent | @@ -244,11 +247,11 @@ public class NotifyRequestForCatalogProcessor extends SIPRequestProcessorParent | ||
| 244 | // 转发变化信息 | 247 | // 转发变化信息 |
| 245 | eventPublisher.catalogEventPublish(null, channel, event); | 248 | eventPublisher.catalogEventPublish(null, channel, event); |
| 246 | 249 | ||
| 247 | - if (updateChannelMap.keySet().size() > 0 | ||
| 248 | - || addChannelMap.keySet().size() > 0 | ||
| 249 | - || updateChannelOnlineList.size() > 0 | ||
| 250 | - || updateChannelOfflineList.size() > 0 | ||
| 251 | - || deleteChannelList.size() > 0) { | 250 | + if (!updateChannelMap.keySet().isEmpty() |
| 251 | + || !addChannelMap.keySet().isEmpty() | ||
| 252 | + || !updateChannelOnlineList.isEmpty() | ||
| 253 | + || !updateChannelOfflineList.isEmpty() | ||
| 254 | + || !deleteChannelList.isEmpty()) { | ||
| 252 | 255 | ||
| 253 | if (!dynamicTask.contains(talkKey)) { | 256 | if (!dynamicTask.contains(talkKey)) { |
| 254 | dynamicTask.startDelay(talkKey, this::executeSave, 1000); | 257 | dynamicTask.startDelay(talkKey, this::executeSave, 1000); |
| @@ -262,16 +265,36 @@ public class NotifyRequestForCatalogProcessor extends SIPRequestProcessorParent | @@ -262,16 +265,36 @@ public class NotifyRequestForCatalogProcessor extends SIPRequestProcessorParent | ||
| 262 | } | 265 | } |
| 263 | 266 | ||
| 264 | private void executeSave(){ | 267 | private void executeSave(){ |
| 265 | - executeSaveForAdd(); | ||
| 266 | - executeSaveForUpdate(); | ||
| 267 | - executeSaveForDelete(); | ||
| 268 | - executeSaveForOnline(); | ||
| 269 | - executeSaveForOffline(); | 268 | + try { |
| 269 | + executeSaveForAdd(); | ||
| 270 | + } catch (Exception e) { | ||
| 271 | + logger.error("[存储收到的增加通道] 异常: ", e ); | ||
| 272 | + } | ||
| 273 | + try { | ||
| 274 | + executeSaveForUpdate(); | ||
| 275 | + } catch (Exception e) { | ||
| 276 | + logger.error("[存储收到的更新通道] 异常: ", e ); | ||
| 277 | + } | ||
| 278 | + try { | ||
| 279 | + executeSaveForDelete(); | ||
| 280 | + } catch (Exception e) { | ||
| 281 | + logger.error("[存储收到的删除通道] 异常: ", e ); | ||
| 282 | + } | ||
| 283 | + try { | ||
| 284 | + executeSaveForOnline(); | ||
| 285 | + } catch (Exception e) { | ||
| 286 | + logger.error("[存储收到的通道上线] 异常: ", e ); | ||
| 287 | + } | ||
| 288 | + try { | ||
| 289 | + executeSaveForOffline(); | ||
| 290 | + } catch (Exception e) { | ||
| 291 | + logger.error("[存储收到的通道离线] 异常: ", e ); | ||
| 292 | + } | ||
| 270 | dynamicTask.stop(talkKey); | 293 | dynamicTask.stop(talkKey); |
| 271 | } | 294 | } |
| 272 | 295 | ||
| 273 | private void executeSaveForUpdate(){ | 296 | private void executeSaveForUpdate(){ |
| 274 | - if (updateChannelMap.values().size() > 0) { | 297 | + if (!updateChannelMap.values().isEmpty()) { |
| 275 | ArrayList<DeviceChannel> deviceChannels = new ArrayList<>(updateChannelMap.values()); | 298 | ArrayList<DeviceChannel> deviceChannels = new ArrayList<>(updateChannelMap.values()); |
| 276 | updateChannelMap.clear(); | 299 | updateChannelMap.clear(); |
| 277 | deviceChannelService.batchUpdateChannel(deviceChannels); | 300 | deviceChannelService.batchUpdateChannel(deviceChannels); |
| @@ -280,7 +303,7 @@ public class NotifyRequestForCatalogProcessor extends SIPRequestProcessorParent | @@ -280,7 +303,7 @@ public class NotifyRequestForCatalogProcessor extends SIPRequestProcessorParent | ||
| 280 | } | 303 | } |
| 281 | 304 | ||
| 282 | private void executeSaveForAdd(){ | 305 | private void executeSaveForAdd(){ |
| 283 | - if (addChannelMap.values().size() > 0) { | 306 | + if (!addChannelMap.values().isEmpty()) { |
| 284 | ArrayList<DeviceChannel> deviceChannels = new ArrayList<>(addChannelMap.values()); | 307 | ArrayList<DeviceChannel> deviceChannels = new ArrayList<>(addChannelMap.values()); |
| 285 | addChannelMap.clear(); | 308 | addChannelMap.clear(); |
| 286 | deviceChannelService.batchAddChannel(deviceChannels); | 309 | deviceChannelService.batchAddChannel(deviceChannels); |
| @@ -288,21 +311,21 @@ public class NotifyRequestForCatalogProcessor extends SIPRequestProcessorParent | @@ -288,21 +311,21 @@ public class NotifyRequestForCatalogProcessor extends SIPRequestProcessorParent | ||
| 288 | } | 311 | } |
| 289 | 312 | ||
| 290 | private void executeSaveForDelete(){ | 313 | private void executeSaveForDelete(){ |
| 291 | - if (deleteChannelList.size() > 0) { | 314 | + if (!deleteChannelList.isEmpty()) { |
| 292 | deviceChannelService.deleteChannels(deleteChannelList); | 315 | deviceChannelService.deleteChannels(deleteChannelList); |
| 293 | deleteChannelList.clear(); | 316 | deleteChannelList.clear(); |
| 294 | } | 317 | } |
| 295 | } | 318 | } |
| 296 | 319 | ||
| 297 | private void executeSaveForOnline(){ | 320 | private void executeSaveForOnline(){ |
| 298 | - if (updateChannelOnlineList.size() > 0) { | 321 | + if (!updateChannelOnlineList.isEmpty()) { |
| 299 | deviceChannelService.channelsOnline(updateChannelOnlineList); | 322 | deviceChannelService.channelsOnline(updateChannelOnlineList); |
| 300 | updateChannelOnlineList.clear(); | 323 | updateChannelOnlineList.clear(); |
| 301 | } | 324 | } |
| 302 | } | 325 | } |
| 303 | 326 | ||
| 304 | private void executeSaveForOffline(){ | 327 | private void executeSaveForOffline(){ |
| 305 | - if (updateChannelOfflineList.size() > 0) { | 328 | + if (!updateChannelOfflineList.isEmpty()) { |
| 306 | deviceChannelService.channelsOffline(updateChannelOfflineList); | 329 | deviceChannelService.channelsOffline(updateChannelOfflineList); |
| 307 | updateChannelOfflineList.clear(); | 330 | updateChannelOfflineList.clear(); |
| 308 | } | 331 | } |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/RegisterRequestProcessor.java
| @@ -106,23 +106,27 @@ public class RegisterRequestProcessor extends SIPRequestProcessorParent implemen | @@ -106,23 +106,27 @@ public class RegisterRequestProcessor extends SIPRequestProcessorParent implemen | ||
| 106 | String title = registerFlag ? "[注册请求]": "[注销请求]"; | 106 | String title = registerFlag ? "[注册请求]": "[注销请求]"; |
| 107 | logger.info(title + "设备:{}, 开始处理: {}", deviceId, requestAddress); | 107 | logger.info(title + "设备:{}, 开始处理: {}", deviceId, requestAddress); |
| 108 | if (device != null && | 108 | if (device != null && |
| 109 | - device.getSipTransactionInfo() != null && | ||
| 110 | - request.getCallIdHeader().getCallId().equals(device.getSipTransactionInfo().getCallId())) { | 109 | + device.getSipTransactionInfo() != null && |
| 110 | + request.getCallIdHeader().getCallId().equals(device.getSipTransactionInfo().getCallId())) { | ||
| 111 | logger.info(title + "设备:{}, 注册续订: {}",device.getDeviceId(), device.getDeviceId()); | 111 | logger.info(title + "设备:{}, 注册续订: {}",device.getDeviceId(), device.getDeviceId()); |
| 112 | - device.setExpires(request.getExpires().getExpires()); | ||
| 113 | - device.setIp(remoteAddressInfo.getIp()); | ||
| 114 | - device.setPort(remoteAddressInfo.getPort()); | ||
| 115 | - device.setHostAddress(remoteAddressInfo.getIp().concat(":").concat(String.valueOf(remoteAddressInfo.getPort()))); | ||
| 116 | - device.setLocalIp(request.getLocalAddress().getHostAddress()); | ||
| 117 | - Response registerOkResponse = getRegisterOkResponse(request); | ||
| 118 | - // 判断TCP还是UDP | ||
| 119 | - ViaHeader reqViaHeader = (ViaHeader) request.getHeader(ViaHeader.NAME); | ||
| 120 | - String transport = reqViaHeader.getTransport(); | ||
| 121 | - device.setTransport("TCP".equalsIgnoreCase(transport) ? "TCP" : "UDP"); | ||
| 122 | - sipSender.transmitRequest(request.getLocalAddress().getHostAddress(), registerOkResponse); | ||
| 123 | - device.setRegisterTime(DateUtil.getNow()); | ||
| 124 | - SipTransactionInfo sipTransactionInfo = new SipTransactionInfo((SIPResponse)registerOkResponse); | ||
| 125 | - deviceService.online(device, sipTransactionInfo); | 112 | + if (registerFlag) { |
| 113 | + device.setExpires(request.getExpires().getExpires()); | ||
| 114 | + device.setIp(remoteAddressInfo.getIp()); | ||
| 115 | + device.setPort(remoteAddressInfo.getPort()); | ||
| 116 | + device.setHostAddress(remoteAddressInfo.getIp().concat(":").concat(String.valueOf(remoteAddressInfo.getPort()))); | ||
| 117 | + device.setLocalIp(request.getLocalAddress().getHostAddress()); | ||
| 118 | + Response registerOkResponse = getRegisterOkResponse(request); | ||
| 119 | + // 判断TCP还是UDP | ||
| 120 | + ViaHeader reqViaHeader = (ViaHeader) request.getHeader(ViaHeader.NAME); | ||
| 121 | + String transport = reqViaHeader.getTransport(); | ||
| 122 | + device.setTransport("TCP".equalsIgnoreCase(transport) ? "TCP" : "UDP"); | ||
| 123 | + sipSender.transmitRequest(request.getLocalAddress().getHostAddress(), registerOkResponse); | ||
| 124 | + device.setRegisterTime(DateUtil.getNow()); | ||
| 125 | + SipTransactionInfo sipTransactionInfo = new SipTransactionInfo((SIPResponse)registerOkResponse); | ||
| 126 | + deviceService.online(device, sipTransactionInfo); | ||
| 127 | + }else { | ||
| 128 | + deviceService.offline(deviceId, "主动注销"); | ||
| 129 | + } | ||
| 126 | return; | 130 | return; |
| 127 | } | 131 | } |
| 128 | String password = (device != null && !ObjectUtils.isEmpty(device.getPassword()))? device.getPassword() : sipConfig.getPassword(); | 132 | String password = (device != null && !ObjectUtils.isEmpty(device.getPassword()))? device.getPassword() : sipConfig.getPassword(); |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/KeepaliveNotifyMessageHandler.java
| @@ -61,7 +61,7 @@ public class KeepaliveNotifyMessageHandler extends SIPRequestProcessorParent imp | @@ -61,7 +61,7 @@ public class KeepaliveNotifyMessageHandler extends SIPRequestProcessorParent imp | ||
| 61 | return; | 61 | return; |
| 62 | } | 62 | } |
| 63 | SIPRequest request = (SIPRequest) evt.getRequest(); | 63 | SIPRequest request = (SIPRequest) evt.getRequest(); |
| 64 | - logger.info("[收到心跳], device: {}, callId: {}", device.getDeviceId(), request.getCallIdHeader().getCallId()); | 64 | + logger.info("[收到心跳] device: {}, callId: {}", device.getDeviceId(), request.getCallIdHeader().getCallId()); |
| 65 | 65 | ||
| 66 | // 回复200 OK | 66 | // 回复200 OK |
| 67 | try { | 67 | try { |
| @@ -76,10 +76,15 @@ public class KeepaliveNotifyMessageHandler extends SIPRequestProcessorParent imp | @@ -76,10 +76,15 @@ public class KeepaliveNotifyMessageHandler extends SIPRequestProcessorParent imp | ||
| 76 | 76 | ||
| 77 | RemoteAddressInfo remoteAddressInfo = SipUtils.getRemoteAddressFromRequest(request, userSetting.getSipUseSourceIpAsRemoteAddress()); | 77 | RemoteAddressInfo remoteAddressInfo = SipUtils.getRemoteAddressFromRequest(request, userSetting.getSipUseSourceIpAsRemoteAddress()); |
| 78 | if (!device.getIp().equalsIgnoreCase(remoteAddressInfo.getIp()) || device.getPort() != remoteAddressInfo.getPort()) { | 78 | if (!device.getIp().equalsIgnoreCase(remoteAddressInfo.getIp()) || device.getPort() != remoteAddressInfo.getPort()) { |
| 79 | - logger.info("[心跳] 设备{}地址变化, 远程地址为: {}:{}", device.getDeviceId(), remoteAddressInfo.getIp(), remoteAddressInfo.getPort()); | 79 | + logger.info("[收到心跳] 设备{}地址变化, 远程地址为: {}:{}", device.getDeviceId(), remoteAddressInfo.getIp(), remoteAddressInfo.getPort()); |
| 80 | device.setPort(remoteAddressInfo.getPort()); | 80 | device.setPort(remoteAddressInfo.getPort()); |
| 81 | device.setHostAddress(remoteAddressInfo.getIp().concat(":").concat(String.valueOf(remoteAddressInfo.getPort()))); | 81 | device.setHostAddress(remoteAddressInfo.getIp().concat(":").concat(String.valueOf(remoteAddressInfo.getPort()))); |
| 82 | device.setIp(remoteAddressInfo.getIp()); | 82 | device.setIp(remoteAddressInfo.getIp()); |
| 83 | + // 设备地址变化会引起目录订阅任务失效,需要重新添加 | ||
| 84 | + if (device.getSubscribeCycleForCatalog() > 0) { | ||
| 85 | + deviceService.removeCatalogSubscribe(device); | ||
| 86 | + deviceService.addCatalogSubscribe(device); | ||
| 87 | + } | ||
| 83 | } | 88 | } |
| 84 | if (device.getKeepaliveTime() == null) { | 89 | if (device.getKeepaliveTime() == null) { |
| 85 | device.setKeepaliveIntervalTime(60); | 90 | device.setKeepaliveIntervalTime(60); |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/RecordInfoQueryMessageHandler.java
| @@ -102,6 +102,7 @@ public class RecordInfoQueryMessageHandler extends SIPRequestProcessorParent imp | @@ -102,6 +102,7 @@ public class RecordInfoQueryMessageHandler extends SIPRequestProcessorParent imp | ||
| 102 | // 接收录像数据 | 102 | // 接收录像数据 |
| 103 | recordEndEventListener.addEndEventHandler(deviceChannel.getDeviceId(), channelId, (recordInfo)->{ | 103 | recordEndEventListener.addEndEventHandler(deviceChannel.getDeviceId(), channelId, (recordInfo)->{ |
| 104 | try { | 104 | try { |
| 105 | + logger.info("[国标级联] 录像查询收到数据, 通道: {},准备转发===", channelId); | ||
| 105 | cmderFroPlatform.recordInfo(deviceChannel, parentPlatform, request.getFromTag(), recordInfo); | 106 | cmderFroPlatform.recordInfo(deviceChannel, parentPlatform, request.getFromTag(), recordInfo); |
| 106 | } catch (SipException | InvalidArgumentException | ParseException e) { | 107 | } catch (SipException | InvalidArgumentException | ParseException e) { |
| 107 | logger.error("[命令发送失败] 国标级联 回复录像数据: {}", e.getMessage()); | 108 | logger.error("[命令发送失败] 国标级联 回复录像数据: {}", e.getMessage()); |
src/main/java/com/genersoft/iot/vmp/gb28181/utils/XmlUtil.java
| @@ -8,6 +8,7 @@ import com.genersoft.iot.vmp.gb28181.bean.Device; | @@ -8,6 +8,7 @@ import com.genersoft.iot.vmp.gb28181.bean.Device; | ||
| 8 | import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; | 8 | import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; |
| 9 | import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent; | 9 | import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent; |
| 10 | import com.genersoft.iot.vmp.utils.DateUtil; | 10 | import com.genersoft.iot.vmp.utils.DateUtil; |
| 11 | +import org.apache.commons.lang3.StringUtils; | ||
| 11 | import org.apache.commons.lang3.math.NumberUtils; | 12 | import org.apache.commons.lang3.math.NumberUtils; |
| 12 | import org.dom4j.Attribute; | 13 | import org.dom4j.Attribute; |
| 13 | import org.dom4j.Document; | 14 | import org.dom4j.Document; |
| @@ -214,8 +215,11 @@ public class XmlUtil { | @@ -214,8 +215,11 @@ public class XmlUtil { | ||
| 214 | return deviceChannel; | 215 | return deviceChannel; |
| 215 | } | 216 | } |
| 216 | Element nameElement = itemDevice.element("Name"); | 217 | Element nameElement = itemDevice.element("Name"); |
| 217 | - if (nameElement != null) { | 218 | + // 当通道名称为空时,设置通道名称为通道编码,避免级联时因通道名称为空导致上级接收通道失败 |
| 219 | + if (nameElement != null && StringUtils.isNotBlank(nameElement.getText())) { | ||
| 218 | deviceChannel.setName(nameElement.getText()); | 220 | deviceChannel.setName(nameElement.getText()); |
| 221 | + } else { | ||
| 222 | + deviceChannel.setName(channelId); | ||
| 219 | } | 223 | } |
| 220 | if(channelId.length() <= 8) { | 224 | if(channelId.length() <= 8) { |
| 221 | deviceChannel.setHasAudio(false); | 225 | deviceChannel.setHasAudio(false); |
src/main/java/com/genersoft/iot/vmp/media/zlm/AssistRESTfulUtils.java
| @@ -2,40 +2,69 @@ package com.genersoft.iot.vmp.media.zlm; | @@ -2,40 +2,69 @@ package com.genersoft.iot.vmp.media.zlm; | ||
| 2 | 2 | ||
| 3 | import com.alibaba.fastjson2.JSON; | 3 | import com.alibaba.fastjson2.JSON; |
| 4 | import com.alibaba.fastjson2.JSONObject; | 4 | import com.alibaba.fastjson2.JSONObject; |
| 5 | +import com.genersoft.iot.vmp.conf.exception.ControllerException; | ||
| 5 | import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; | 6 | import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; |
| 7 | +import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; | ||
| 6 | import okhttp3.*; | 8 | import okhttp3.*; |
| 7 | import okhttp3.logging.HttpLoggingInterceptor; | 9 | import okhttp3.logging.HttpLoggingInterceptor; |
| 8 | import org.jetbrains.annotations.NotNull; | 10 | import org.jetbrains.annotations.NotNull; |
| 9 | import org.slf4j.Logger; | 11 | import org.slf4j.Logger; |
| 10 | import org.slf4j.LoggerFactory; | 12 | import org.slf4j.LoggerFactory; |
| 11 | import org.springframework.stereotype.Component; | 13 | import org.springframework.stereotype.Component; |
| 14 | +import org.springframework.util.ObjectUtils; | ||
| 12 | 15 | ||
| 13 | import java.io.IOException; | 16 | import java.io.IOException; |
| 14 | import java.net.ConnectException; | 17 | import java.net.ConnectException; |
| 18 | +import java.net.MalformedURLException; | ||
| 19 | +import java.net.SocketTimeoutException; | ||
| 20 | +import java.net.URL; | ||
| 15 | import java.util.HashMap; | 21 | import java.util.HashMap; |
| 22 | +import java.util.List; | ||
| 16 | import java.util.Map; | 23 | import java.util.Map; |
| 17 | import java.util.Objects; | 24 | import java.util.Objects; |
| 25 | +import java.util.concurrent.TimeUnit; | ||
| 18 | 26 | ||
| 19 | @Component | 27 | @Component |
| 20 | public class AssistRESTfulUtils { | 28 | public class AssistRESTfulUtils { |
| 21 | 29 | ||
| 22 | private final static Logger logger = LoggerFactory.getLogger(AssistRESTfulUtils.class); | 30 | private final static Logger logger = LoggerFactory.getLogger(AssistRESTfulUtils.class); |
| 23 | 31 | ||
| 32 | + | ||
| 33 | + private OkHttpClient client; | ||
| 34 | + | ||
| 35 | + | ||
| 24 | public interface RequestCallback{ | 36 | public interface RequestCallback{ |
| 25 | void run(JSONObject response); | 37 | void run(JSONObject response); |
| 26 | } | 38 | } |
| 27 | 39 | ||
| 28 | private OkHttpClient getClient(){ | 40 | private OkHttpClient getClient(){ |
| 29 | - OkHttpClient.Builder httpClientBuilder = new OkHttpClient.Builder(); | ||
| 30 | - if (logger.isDebugEnabled()) { | ||
| 31 | - HttpLoggingInterceptor logging = new HttpLoggingInterceptor(message -> { | ||
| 32 | - logger.debug("http请求参数:" + message); | ||
| 33 | - }); | ||
| 34 | - logging.setLevel(HttpLoggingInterceptor.Level.BASIC); | ||
| 35 | - // OkHttp進行添加攔截器loggingInterceptor | ||
| 36 | - httpClientBuilder.addInterceptor(logging); | 41 | + return getClient(null); |
| 42 | + } | ||
| 43 | + | ||
| 44 | + private OkHttpClient getClient(Integer readTimeOut){ | ||
| 45 | + if (client == null) { | ||
| 46 | + if (readTimeOut == null) { | ||
| 47 | + readTimeOut = 10; | ||
| 48 | + } | ||
| 49 | + OkHttpClient.Builder httpClientBuilder = new OkHttpClient.Builder(); | ||
| 50 | + // 设置连接超时时间 | ||
| 51 | + httpClientBuilder.connectTimeout(8, TimeUnit.SECONDS); | ||
| 52 | + // 设置读取超时时间 | ||
| 53 | + httpClientBuilder.readTimeout(readTimeOut,TimeUnit.SECONDS); | ||
| 54 | + // 设置连接池 | ||
| 55 | + httpClientBuilder.connectionPool(new ConnectionPool(16, 5, TimeUnit.MINUTES)); | ||
| 56 | + if (logger.isDebugEnabled()) { | ||
| 57 | + HttpLoggingInterceptor logging = new HttpLoggingInterceptor(message -> { | ||
| 58 | + logger.debug("http请求参数:" + message); | ||
| 59 | + }); | ||
| 60 | + logging.setLevel(HttpLoggingInterceptor.Level.BASIC); | ||
| 61 | + // OkHttp進行添加攔截器loggingInterceptor | ||
| 62 | + httpClientBuilder.addInterceptor(logging); | ||
| 63 | + } | ||
| 64 | + client = httpClientBuilder.build(); | ||
| 37 | } | 65 | } |
| 38 | - return httpClientBuilder.build(); | 66 | + return client; |
| 67 | + | ||
| 39 | } | 68 | } |
| 40 | 69 | ||
| 41 | 70 | ||
| @@ -49,11 +78,11 @@ public class AssistRESTfulUtils { | @@ -49,11 +78,11 @@ public class AssistRESTfulUtils { | ||
| 49 | logger.warn("未启用Assist服务"); | 78 | logger.warn("未启用Assist服务"); |
| 50 | return null; | 79 | return null; |
| 51 | } | 80 | } |
| 52 | - StringBuffer stringBuffer = new StringBuffer(); | ||
| 53 | - stringBuffer.append(String.format("http://%s:%s/%s", mediaServerItem.getIp(), mediaServerItem.getRecordAssistPort(), api)); | 81 | + StringBuilder stringBuffer = new StringBuilder(); |
| 82 | + stringBuffer.append(api); | ||
| 54 | JSONObject responseJSON = null; | 83 | JSONObject responseJSON = null; |
| 55 | 84 | ||
| 56 | - if (param != null && param.keySet().size() > 0) { | 85 | + if (param != null && !param.keySet().isEmpty()) { |
| 57 | stringBuffer.append("?"); | 86 | stringBuffer.append("?"); |
| 58 | int index = 1; | 87 | int index = 1; |
| 59 | for (String key : param.keySet()){ | 88 | for (String key : param.keySet()){ |
| @@ -68,6 +97,7 @@ public class AssistRESTfulUtils { | @@ -68,6 +97,7 @@ public class AssistRESTfulUtils { | ||
| 68 | } | 97 | } |
| 69 | 98 | ||
| 70 | String url = stringBuffer.toString(); | 99 | String url = stringBuffer.toString(); |
| 100 | + logger.info("[访问assist]: {}", url); | ||
| 71 | Request request = new Request.Builder() | 101 | Request request = new Request.Builder() |
| 72 | .get() | 102 | .get() |
| 73 | .url(url) | 103 | .url(url) |
| @@ -123,13 +153,93 @@ public class AssistRESTfulUtils { | @@ -123,13 +153,93 @@ public class AssistRESTfulUtils { | ||
| 123 | return responseJSON; | 153 | return responseJSON; |
| 124 | } | 154 | } |
| 125 | 155 | ||
| 156 | + public JSONObject sendPost(MediaServerItem mediaServerItem, String url, | ||
| 157 | + JSONObject param, ZLMRESTfulUtils.RequestCallback callback, | ||
| 158 | + Integer readTimeOut) { | ||
| 159 | + OkHttpClient client = getClient(readTimeOut); | ||
| 126 | 160 | ||
| 127 | - public JSONObject fileDuration(MediaServerItem mediaServerItem, String app, String stream, RequestCallback callback){ | ||
| 128 | - Map<String, Object> param = new HashMap<>(); | ||
| 129 | - param.put("app",app); | ||
| 130 | - param.put("stream",stream); | ||
| 131 | - param.put("recordIng",true); | ||
| 132 | - return sendGet(mediaServerItem, "api/record/file/duration",param, callback); | 161 | + if (mediaServerItem == null) { |
| 162 | + return null; | ||
| 163 | + } | ||
| 164 | + logger.info("[访问assist]: {}, 参数: {}", url, param); | ||
| 165 | + JSONObject responseJSON = new JSONObject(); | ||
| 166 | + //-2自定义流媒体 调用错误码 | ||
| 167 | + responseJSON.put("code",-2); | ||
| 168 | + responseJSON.put("msg","ASSIST调用失败"); | ||
| 169 | + | ||
| 170 | + RequestBody requestBodyJson = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), param.toString()); | ||
| 171 | + | ||
| 172 | + Request request = new Request.Builder() | ||
| 173 | + .post(requestBodyJson) | ||
| 174 | + .url(url) | ||
| 175 | + .addHeader("Content-Type", "application/json") | ||
| 176 | + .build(); | ||
| 177 | + if (callback == null) { | ||
| 178 | + try { | ||
| 179 | + Response response = client.newCall(request).execute(); | ||
| 180 | + if (response.isSuccessful()) { | ||
| 181 | + ResponseBody responseBody = response.body(); | ||
| 182 | + if (responseBody != null) { | ||
| 183 | + String responseStr = responseBody.string(); | ||
| 184 | + responseJSON = JSON.parseObject(responseStr); | ||
| 185 | + } | ||
| 186 | + }else { | ||
| 187 | + response.close(); | ||
| 188 | + Objects.requireNonNull(response.body()).close(); | ||
| 189 | + } | ||
| 190 | + }catch (IOException e) { | ||
| 191 | + logger.error(String.format("[ %s ]ASSIST请求失败: %s", url, e.getMessage())); | ||
| 192 | + | ||
| 193 | + if(e instanceof SocketTimeoutException){ | ||
| 194 | + //读取超时超时异常 | ||
| 195 | + logger.error(String.format("读取ASSIST数据失败: %s, %s", url, e.getMessage())); | ||
| 196 | + } | ||
| 197 | + if(e instanceof ConnectException){ | ||
| 198 | + //判断连接异常,我这里是报Failed to connect to 10.7.5.144 | ||
| 199 | + logger.error(String.format("连接ASSIST失败: %s, %s", url, e.getMessage())); | ||
| 200 | + } | ||
| 201 | + | ||
| 202 | + }catch (Exception e){ | ||
| 203 | + logger.error(String.format("访问ASSIST失败: %s, %s", url, e.getMessage())); | ||
| 204 | + } | ||
| 205 | + }else { | ||
| 206 | + client.newCall(request).enqueue(new Callback(){ | ||
| 207 | + | ||
| 208 | + @Override | ||
| 209 | + public void onResponse(@NotNull Call call, @NotNull Response response){ | ||
| 210 | + if (response.isSuccessful()) { | ||
| 211 | + try { | ||
| 212 | + String responseStr = Objects.requireNonNull(response.body()).string(); | ||
| 213 | + callback.run(JSON.parseObject(responseStr)); | ||
| 214 | + } catch (IOException e) { | ||
| 215 | + logger.error(String.format("[ %s ]请求失败: %s", url, e.getMessage())); | ||
| 216 | + } | ||
| 217 | + | ||
| 218 | + }else { | ||
| 219 | + response.close(); | ||
| 220 | + Objects.requireNonNull(response.body()).close(); | ||
| 221 | + } | ||
| 222 | + } | ||
| 223 | + | ||
| 224 | + @Override | ||
| 225 | + public void onFailure(@NotNull Call call, @NotNull IOException e) { | ||
| 226 | + logger.error(String.format("连接ZLM失败: %s, %s", call.request().toString(), e.getMessage())); | ||
| 227 | + | ||
| 228 | + if(e instanceof SocketTimeoutException){ | ||
| 229 | + //读取超时超时异常 | ||
| 230 | + logger.error(String.format("读取ZLM数据失败: %s, %s", call.request().toString(), e.getMessage())); | ||
| 231 | + } | ||
| 232 | + if(e instanceof ConnectException){ | ||
| 233 | + //判断连接异常,我这里是报Failed to connect to 10.7.5.144 | ||
| 234 | + logger.error(String.format("连接ZLM失败: %s, %s", call.request().toString(), e.getMessage())); | ||
| 235 | + } | ||
| 236 | + } | ||
| 237 | + }); | ||
| 238 | + } | ||
| 239 | + | ||
| 240 | + | ||
| 241 | + | ||
| 242 | + return responseJSON; | ||
| 133 | } | 243 | } |
| 134 | 244 | ||
| 135 | public JSONObject getInfo(MediaServerItem mediaServerItem, RequestCallback callback){ | 245 | public JSONObject getInfo(MediaServerItem mediaServerItem, RequestCallback callback){ |
| @@ -137,33 +247,43 @@ public class AssistRESTfulUtils { | @@ -137,33 +247,43 @@ public class AssistRESTfulUtils { | ||
| 137 | return sendGet(mediaServerItem, "api/record/info",param, callback); | 247 | return sendGet(mediaServerItem, "api/record/info",param, callback); |
| 138 | } | 248 | } |
| 139 | 249 | ||
| 140 | - public JSONObject addStreamCallInfo(MediaServerItem mediaServerItem, String app, String stream, String callId, RequestCallback callback){ | ||
| 141 | - Map<String, Object> param = new HashMap<>(); | ||
| 142 | - param.put("app",app); | ||
| 143 | - param.put("stream",stream); | ||
| 144 | - param.put("callId",callId); | ||
| 145 | - return sendGet(mediaServerItem, "api/record/addStreamCallInfo",param, callback); | ||
| 146 | - } | 250 | + public JSONObject addTask(MediaServerItem mediaServerItem, String app, String stream, String startTime, |
| 251 | + String endTime, String callId, List<String> filePathList, String remoteHost) { | ||
| 147 | 252 | ||
| 148 | - public JSONObject getDateList(MediaServerItem mediaServerItem, String app, String stream, int year, int month) { | ||
| 149 | - Map<String, Object> param = new HashMap<>(); | ||
| 150 | - param.put("app", app); | ||
| 151 | - param.put("stream", stream); | ||
| 152 | - param.put("year", year); | ||
| 153 | - param.put("month", month); | ||
| 154 | - return sendGet(mediaServerItem, "api/record/date/list", param, null); | 253 | + JSONObject videoTaskInfoJSON = new JSONObject(); |
| 254 | + videoTaskInfoJSON.put("app", app); | ||
| 255 | + videoTaskInfoJSON.put("stream", stream); | ||
| 256 | + videoTaskInfoJSON.put("startTime", startTime); | ||
| 257 | + videoTaskInfoJSON.put("endTime", endTime); | ||
| 258 | + videoTaskInfoJSON.put("callId", callId); | ||
| 259 | + videoTaskInfoJSON.put("filePathList", filePathList); | ||
| 260 | + if (!ObjectUtils.isEmpty(remoteHost)) { | ||
| 261 | + videoTaskInfoJSON.put("remoteHost", remoteHost); | ||
| 262 | + } | ||
| 263 | + String urlStr = String.format("%s/api/record/file/download/task/add", remoteHost);; | ||
| 264 | + return sendPost(mediaServerItem, urlStr, videoTaskInfoJSON, null, 30); | ||
| 155 | } | 265 | } |
| 156 | 266 | ||
| 157 | - public JSONObject getFileList(MediaServerItem mediaServerItem, int page, int count, String app, String stream, | ||
| 158 | - String startTime, String endTime) { | 267 | + public JSONObject queryTaskList(MediaServerItem mediaServerItem, String app, String stream, String callId, |
| 268 | + String taskId, Boolean isEnd, String scheme) { | ||
| 159 | Map<String, Object> param = new HashMap<>(); | 269 | Map<String, Object> param = new HashMap<>(); |
| 160 | - param.put("app", app); | ||
| 161 | - param.put("stream", stream); | ||
| 162 | - param.put("page", page); | ||
| 163 | - param.put("count", count); | ||
| 164 | - param.put("startTime", startTime); | ||
| 165 | - param.put("endTime", endTime); | ||
| 166 | - return sendGet(mediaServerItem, "api/record/file/listWithDate", param, null); | 270 | + if (!ObjectUtils.isEmpty(app)) { |
| 271 | + param.put("app", app); | ||
| 272 | + } | ||
| 273 | + if (!ObjectUtils.isEmpty(stream)) { | ||
| 274 | + param.put("stream", stream); | ||
| 275 | + } | ||
| 276 | + if (!ObjectUtils.isEmpty(callId)) { | ||
| 277 | + param.put("callId", callId); | ||
| 278 | + } | ||
| 279 | + if (!ObjectUtils.isEmpty(taskId)) { | ||
| 280 | + param.put("taskId", taskId); | ||
| 281 | + } | ||
| 282 | + if (!ObjectUtils.isEmpty(isEnd)) { | ||
| 283 | + param.put("isEnd", isEnd); | ||
| 284 | + } | ||
| 285 | + String urlStr = String.format("%s://%s:%s/api/record/file/download/task/list", | ||
| 286 | + scheme, mediaServerItem.getIp(), mediaServerItem.getRecordAssistPort());; | ||
| 287 | + return sendGet(mediaServerItem, urlStr, param, null); | ||
| 167 | } | 288 | } |
| 168 | - | ||
| 169 | } | 289 | } |
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java
| @@ -118,6 +118,9 @@ public class ZLMHttpHookListener { | @@ -118,6 +118,9 @@ public class ZLMHttpHookListener { | ||
| 118 | private IUserService userService; | 118 | private IUserService userService; |
| 119 | 119 | ||
| 120 | @Autowired | 120 | @Autowired |
| 121 | + private ICloudRecordService cloudRecordService; | ||
| 122 | + | ||
| 123 | + @Autowired | ||
| 121 | private VideoStreamSessionManager sessionManager; | 124 | private VideoStreamSessionManager sessionManager; |
| 122 | 125 | ||
| 123 | @Autowired | 126 | @Autowired |
| @@ -238,12 +241,6 @@ public class ZLMHttpHookListener { | @@ -238,12 +241,6 @@ public class ZLMHttpHookListener { | ||
| 238 | streamAuthorityInfo.setSign(sign); | 241 | streamAuthorityInfo.setSign(sign); |
| 239 | // 鉴权通过 | 242 | // 鉴权通过 |
| 240 | redisCatchStorage.updateStreamAuthorityInfo(param.getApp(), param.getStream(), streamAuthorityInfo); | 243 | redisCatchStorage.updateStreamAuthorityInfo(param.getApp(), param.getStream(), streamAuthorityInfo); |
| 241 | - // 通知assist新的callId | ||
| 242 | - if (mediaInfo != null && mediaInfo.getRecordAssistPort() > 0) { | ||
| 243 | - taskExecutor.execute(() -> { | ||
| 244 | - assistRESTfulUtils.addStreamCallInfo(mediaInfo, param.getApp(), param.getStream(), callId, null); | ||
| 245 | - }); | ||
| 246 | - } | ||
| 247 | } | 244 | } |
| 248 | } else { | 245 | } else { |
| 249 | zlmMediaListManager.sendStreamEvent(param.getApp(), param.getStream(), param.getMediaServerId()); | 246 | zlmMediaListManager.sendStreamEvent(param.getApp(), param.getStream(), param.getMediaServerId()); |
| @@ -269,51 +266,57 @@ public class ZLMHttpHookListener { | @@ -269,51 +266,57 @@ public class ZLMHttpHookListener { | ||
| 269 | } else { | 266 | } else { |
| 270 | result.setEnable_mp4(userSetting.isRecordPushLive()); | 267 | result.setEnable_mp4(userSetting.isRecordPushLive()); |
| 271 | } | 268 | } |
| 272 | - // 替换流地址 | ||
| 273 | - if ("rtp".equals(param.getApp()) && !mediaInfo.isRtpEnable()) { | ||
| 274 | - String ssrc = String.format("%010d", Long.parseLong(param.getStream(), 16));; | ||
| 275 | - InviteInfo inviteInfo = inviteStreamService.getInviteInfoBySSRC(ssrc); | ||
| 276 | - if (inviteInfo != null) { | ||
| 277 | - result.setStream_replace(inviteInfo.getStream()); | ||
| 278 | - logger.info("[ZLM HOOK]推流鉴权 stream: {} 替换为 {}", param.getStream(), inviteInfo.getStream()); | ||
| 279 | - } | ||
| 280 | - } | ||
| 281 | - List<SsrcTransaction> ssrcTransactionForAll = sessionManager.getSsrcTransactionForAll(null, null, null, param.getStream()); | ||
| 282 | - if (ssrcTransactionForAll != null && ssrcTransactionForAll.size() == 1) { | ||
| 283 | - String deviceId = ssrcTransactionForAll.get(0).getDeviceId(); | ||
| 284 | - String channelId = ssrcTransactionForAll.get(0).getChannelId(); | ||
| 285 | - DeviceChannel deviceChannel = storager.queryChannel(deviceId, channelId); | ||
| 286 | - if (deviceChannel != null) { | 269 | + // 国标流 |
| 270 | + if ("rtp".equals(param.getApp()) ) { | ||
| 287 | 271 | ||
| 288 | - result.setEnable_audio(deviceChannel.isHasAudio()); | ||
| 289 | - } | ||
| 290 | - // 如果是录像下载就设置视频间隔十秒 | ||
| 291 | - if (ssrcTransactionForAll.get(0).getType() == InviteSessionType.DOWNLOAD) { | ||
| 292 | - result.setMp4_max_second(10); | ||
| 293 | - result.setEnable_mp4(true); | ||
| 294 | - } | ||
| 295 | - // 如果是talk对讲,则默认获取声音 | ||
| 296 | - if (ssrcTransactionForAll.get(0).getType() == InviteSessionType.TALK) { | ||
| 297 | - result.setEnable_audio(true); | 272 | + InviteInfo inviteInfo = inviteStreamService.getInviteInfoByStream(null, param.getStream()); |
| 273 | + | ||
| 274 | + // 单端口模式下修改流 ID | ||
| 275 | + if (!mediaInfo.isRtpEnable() && inviteInfo == null) { | ||
| 276 | + String ssrc = String.format("%010d", Long.parseLong(param.getStream(), 16)); | ||
| 277 | + inviteInfo = inviteStreamService.getInviteInfoBySSRC(ssrc); | ||
| 278 | + if (inviteInfo != null) { | ||
| 279 | + result.setStream_replace(inviteInfo.getStream()); | ||
| 280 | + logger.info("[ZLM HOOK]推流鉴权 stream: {} 替换为 {}", param.getStream(), inviteInfo.getStream()); | ||
| 281 | + } | ||
| 298 | } | 282 | } |
| 299 | 283 | ||
| 300 | - } | ||
| 301 | - if (mediaInfo.getRecordAssistPort() > 0 && userSetting.getRecordPath() == null) { | ||
| 302 | - logger.info("推流时发现尚未设置录像路径,从assist服务中读取"); | ||
| 303 | - JSONObject info = assistRESTfulUtils.getInfo(mediaInfo, null); | ||
| 304 | - if (info != null && info.getInteger("code") != null && info.getInteger("code") == 0) { | ||
| 305 | - JSONObject dataJson = info.getJSONObject("data"); | ||
| 306 | - if (dataJson != null) { | ||
| 307 | - String recordPath = dataJson.getString("record"); | ||
| 308 | - userSetting.setRecordPath(recordPath); | ||
| 309 | - result.setMp4_save_path(recordPath); | ||
| 310 | - // 修改zlm中的录像路径 | ||
| 311 | - if (mediaInfo.isAutoConfig()) { | ||
| 312 | - taskExecutor.execute(() -> { | ||
| 313 | - mediaServerService.setZLMConfig(mediaInfo, false); | ||
| 314 | - }); | 284 | + // 设置音频信息及录制信息 |
| 285 | + List<SsrcTransaction> ssrcTransactionForAll = sessionManager.getSsrcTransactionForAll(null, null, null, param.getStream()); | ||
| 286 | + if (ssrcTransactionForAll != null && ssrcTransactionForAll.size() == 1) { | ||
| 287 | + | ||
| 288 | + // 为录制国标模拟一个鉴权信息, 方便后续写入录像文件时使用 | ||
| 289 | + StreamAuthorityInfo streamAuthorityInfo = StreamAuthorityInfo.getInstanceByHook(param); | ||
| 290 | + streamAuthorityInfo.setApp(param.getApp()); | ||
| 291 | + streamAuthorityInfo.setStream(ssrcTransactionForAll.get(0).getStream()); | ||
| 292 | + streamAuthorityInfo.setCallId(ssrcTransactionForAll.get(0).getSipTransactionInfo().getCallId()); | ||
| 293 | + | ||
| 294 | + redisCatchStorage.updateStreamAuthorityInfo(param.getApp(), ssrcTransactionForAll.get(0).getStream(), streamAuthorityInfo); | ||
| 295 | + | ||
| 296 | + String deviceId = ssrcTransactionForAll.get(0).getDeviceId(); | ||
| 297 | + String channelId = ssrcTransactionForAll.get(0).getChannelId(); | ||
| 298 | + DeviceChannel deviceChannel = storager.queryChannel(deviceId, channelId); | ||
| 299 | + if (deviceChannel != null) { | ||
| 300 | + result.setEnable_audio(deviceChannel.isHasAudio()); | ||
| 301 | + } | ||
| 302 | + // 如果是录像下载就设置视频间隔十秒 | ||
| 303 | + if (ssrcTransactionForAll.get(0).getType() == InviteSessionType.DOWNLOAD) { | ||
| 304 | + // 获取录像的总时长,然后设置为这个视频的时长 | ||
| 305 | + InviteInfo inviteInfoForDownload = inviteStreamService.getInviteInfo(InviteSessionType.DOWNLOAD, deviceId, channelId, param.getStream()); | ||
| 306 | + if (inviteInfoForDownload != null && inviteInfoForDownload.getStreamInfo() != null) { | ||
| 307 | + String startTime = inviteInfoForDownload.getStreamInfo().getStartTime(); | ||
| 308 | + String endTime = inviteInfoForDownload.getStreamInfo().getEndTime(); | ||
| 309 | + long difference = DateUtil.getDifference(startTime, endTime) / 1000; | ||
| 310 | + result.setMp4_max_second((int) difference); | ||
| 311 | + result.setEnable_mp4(true); | ||
| 312 | + // 设置为2保证得到的mp4的时长是正常的 | ||
| 313 | + result.setModify_stamp(2); | ||
| 315 | } | 314 | } |
| 316 | } | 315 | } |
| 316 | + // 如果是talk对讲,则默认获取声音 | ||
| 317 | + if (ssrcTransactionForAll.get(0).getType() == InviteSessionType.TALK) { | ||
| 318 | + result.setEnable_audio(true); | ||
| 319 | + } | ||
| 317 | } | 320 | } |
| 318 | } | 321 | } |
| 319 | if (param.getApp().equalsIgnoreCase("rtp")) { | 322 | if (param.getApp().equalsIgnoreCase("rtp")) { |
| @@ -361,13 +364,11 @@ public class ZLMHttpHookListener { | @@ -361,13 +364,11 @@ public class ZLMHttpHookListener { | ||
| 361 | 364 | ||
| 362 | List<OnStreamChangedHookParam.MediaTrack> tracks = param.getTracks(); | 365 | List<OnStreamChangedHookParam.MediaTrack> tracks = param.getTracks(); |
| 363 | // TODO 重构此处逻辑 | 366 | // TODO 重构此处逻辑 |
| 364 | - boolean isPush = false; | ||
| 365 | if (param.isRegist()) { | 367 | if (param.isRegist()) { |
| 366 | - // 处理流注册的鉴权信息 | 368 | + // 处理流注册的鉴权信息, 流注销这里不再删除鉴权信息,下次来了新的鉴权信息会对就的进行覆盖 |
| 367 | if (param.getOriginType() == OriginType.RTMP_PUSH.ordinal() | 369 | if (param.getOriginType() == OriginType.RTMP_PUSH.ordinal() |
| 368 | || param.getOriginType() == OriginType.RTSP_PUSH.ordinal() | 370 | || param.getOriginType() == OriginType.RTSP_PUSH.ordinal() |
| 369 | || param.getOriginType() == OriginType.RTC_PUSH.ordinal()) { | 371 | || param.getOriginType() == OriginType.RTC_PUSH.ordinal()) { |
| 370 | - isPush = true; | ||
| 371 | StreamAuthorityInfo streamAuthorityInfo = redisCatchStorage.getStreamAuthorityInfo(param.getApp(), param.getStream()); | 372 | StreamAuthorityInfo streamAuthorityInfo = redisCatchStorage.getStreamAuthorityInfo(param.getApp(), param.getStream()); |
| 372 | if (streamAuthorityInfo == null) { | 373 | if (streamAuthorityInfo == null) { |
| 373 | streamAuthorityInfo = StreamAuthorityInfo.getInstanceByHook(param); | 374 | streamAuthorityInfo = StreamAuthorityInfo.getInstanceByHook(param); |
| @@ -377,8 +378,6 @@ public class ZLMHttpHookListener { | @@ -377,8 +378,6 @@ public class ZLMHttpHookListener { | ||
| 377 | } | 378 | } |
| 378 | redisCatchStorage.updateStreamAuthorityInfo(param.getApp(), param.getStream(), streamAuthorityInfo); | 379 | redisCatchStorage.updateStreamAuthorityInfo(param.getApp(), param.getStream(), streamAuthorityInfo); |
| 379 | } | 380 | } |
| 380 | - } else { | ||
| 381 | - redisCatchStorage.removeStreamAuthorityInfo(param.getApp(), param.getStream()); | ||
| 382 | } | 381 | } |
| 383 | 382 | ||
| 384 | if ("rtsp".equals(param.getSchema())) { | 383 | if ("rtsp".equals(param.getSchema())) { |
| @@ -460,35 +459,40 @@ public class ZLMHttpHookListener { | @@ -460,35 +459,40 @@ public class ZLMHttpHookListener { | ||
| 460 | } else { | 459 | } else { |
| 461 | if (!"rtp".equals(param.getApp())) { | 460 | if (!"rtp".equals(param.getApp())) { |
| 462 | String type = OriginType.values()[param.getOriginType()].getType(); | 461 | String type = OriginType.values()[param.getOriginType()].getType(); |
| 463 | - MediaServerItem mediaServerItem = mediaServerService.getOne(param.getMediaServerId()); | ||
| 464 | - | ||
| 465 | - if (mediaServerItem != null) { | ||
| 466 | - if (param.isRegist()) { | ||
| 467 | - StreamAuthorityInfo streamAuthorityInfo = redisCatchStorage.getStreamAuthorityInfo(param.getApp(), param.getStream()); | ||
| 468 | - String callId = null; | ||
| 469 | - if (streamAuthorityInfo != null) { | ||
| 470 | - callId = streamAuthorityInfo.getCallId(); | ||
| 471 | - } | ||
| 472 | - StreamInfo streamInfoByAppAndStream = mediaService.getStreamInfoByAppAndStream(mediaServerItem, | ||
| 473 | - param.getApp(), param.getStream(), param.getTracks(), callId); | ||
| 474 | - param.setStreamInfo(new StreamContent(streamInfoByAppAndStream)); | ||
| 475 | - redisCatchStorage.addStream(mediaServerItem, type, param.getApp(), param.getStream(), param); | ||
| 476 | - if (param.getOriginType() == OriginType.RTSP_PUSH.ordinal() | ||
| 477 | - || param.getOriginType() == OriginType.RTMP_PUSH.ordinal() | ||
| 478 | - || param.getOriginType() == OriginType.RTC_PUSH.ordinal()) { | ||
| 479 | - param.setSeverId(userSetting.getServerId()); | ||
| 480 | - zlmMediaListManager.addPush(param); | ||
| 481 | - } | ||
| 482 | - } else { | ||
| 483 | - // 兼容流注销时类型从redis记录获取 | ||
| 484 | - OnStreamChangedHookParam onStreamChangedHookParam = redisCatchStorage.getStreamInfo( | ||
| 485 | - param.getApp(), param.getStream(), param.getMediaServerId()); | ||
| 486 | - if (onStreamChangedHookParam != null) { | ||
| 487 | - type = OriginType.values()[onStreamChangedHookParam.getOriginType()].getType(); | ||
| 488 | - redisCatchStorage.removeStream(mediaServerItem.getId(), type, param.getApp(), param.getStream()); | 462 | + if (param.isRegist()) { |
| 463 | + StreamAuthorityInfo streamAuthorityInfo = redisCatchStorage.getStreamAuthorityInfo( | ||
| 464 | + param.getApp(), param.getStream()); | ||
| 465 | + String callId = null; | ||
| 466 | + if (streamAuthorityInfo != null) { | ||
| 467 | + callId = streamAuthorityInfo.getCallId(); | ||
| 468 | + } | ||
| 469 | + StreamInfo streamInfoByAppAndStream = mediaService.getStreamInfoByAppAndStream(mediaInfo, | ||
| 470 | + param.getApp(), param.getStream(), tracks, callId); | ||
| 471 | + param.setStreamInfo(new StreamContent(streamInfoByAppAndStream)); | ||
| 472 | + redisCatchStorage.addStream(mediaInfo, type, param.getApp(), param.getStream(), param); | ||
| 473 | + if (param.getOriginType() == OriginType.RTSP_PUSH.ordinal() | ||
| 474 | + || param.getOriginType() == OriginType.RTMP_PUSH.ordinal() | ||
| 475 | + || param.getOriginType() == OriginType.RTC_PUSH.ordinal()) { | ||
| 476 | + param.setSeverId(userSetting.getServerId()); | ||
| 477 | + zlmMediaListManager.addPush(param); | ||
| 478 | + | ||
| 479 | + // 冗余数据,自己系统中自用 | ||
| 480 | + redisCatchStorage.addPushListItem(param.getApp(), param.getStream(), param); | ||
| 481 | + } | ||
| 482 | + } else { | ||
| 483 | + // 兼容流注销时类型从redis记录获取 | ||
| 484 | + OnStreamChangedHookParam onStreamChangedHookParam = redisCatchStorage.getStreamInfo( | ||
| 485 | + param.getApp(), param.getStream(), param.getMediaServerId()); | ||
| 486 | + if (onStreamChangedHookParam != null) { | ||
| 487 | + type = OriginType.values()[onStreamChangedHookParam.getOriginType()].getType(); | ||
| 488 | + redisCatchStorage.removeStream(mediaInfo.getId(), type, param.getApp(), param.getStream()); | ||
| 489 | + if ("PUSH".equalsIgnoreCase(type)) { | ||
| 490 | + // 冗余数据,自己系统中自用 | ||
| 491 | + redisCatchStorage.removePushListItem(param.getApp(), param.getStream(), param.getMediaServerId()); | ||
| 489 | } | 492 | } |
| 490 | - GbStream gbStream = storager.getGbStream(param.getApp(), param.getStream()); | ||
| 491 | - if (gbStream != null) { | 493 | + } |
| 494 | + GbStream gbStream = storager.getGbStream(param.getApp(), param.getStream()); | ||
| 495 | + if (gbStream != null) { | ||
| 492 | // eventPublisher.catalogEventPublishForStream(null, gbStream, CatalogEvent.OFF); | 496 | // eventPublisher.catalogEventPublishForStream(null, gbStream, CatalogEvent.OFF); |
| 493 | } | 497 | } |
| 494 | zlmMediaListManager.removeMedia(param.getApp(), param.getStream()); | 498 | zlmMediaListManager.removeMedia(param.getApp(), param.getStream()); |
| @@ -513,7 +517,7 @@ public class ZLMHttpHookListener { | @@ -513,7 +517,7 @@ public class ZLMHttpHookListener { | ||
| 513 | } | 517 | } |
| 514 | if (!param.isRegist()) { | 518 | if (!param.isRegist()) { |
| 515 | List<SendRtpItem> sendRtpItems = redisCatchStorage.querySendRTPServerByStream(param.getStream()); | 519 | List<SendRtpItem> sendRtpItems = redisCatchStorage.querySendRTPServerByStream(param.getStream()); |
| 516 | - if (sendRtpItems.size() > 0) { | 520 | + if (!sendRtpItems.isEmpty()) { |
| 517 | for (SendRtpItem sendRtpItem : sendRtpItems) { | 521 | for (SendRtpItem sendRtpItem : sendRtpItems) { |
| 518 | if (sendRtpItem != null && sendRtpItem.getApp().equals(param.getApp())) { | 522 | if (sendRtpItem != null && sendRtpItem.getApp().equals(param.getApp())) { |
| 519 | String platformId = sendRtpItem.getPlatformId(); | 523 | String platformId = sendRtpItem.getPlatformId(); |
| @@ -608,11 +612,15 @@ public class ZLMHttpHookListener { | @@ -608,11 +612,15 @@ public class ZLMHttpHookListener { | ||
| 608 | if (info != null) { | 612 | if (info != null) { |
| 609 | cmder.streamByeCmd(device, inviteInfo.getChannelId(), | 613 | cmder.streamByeCmd(device, inviteInfo.getChannelId(), |
| 610 | inviteInfo.getStream(), null); | 614 | inviteInfo.getStream(), null); |
| 615 | + }else { | ||
| 616 | + logger.info("[无人观看] 未找到设备的点播信息: {}, 流:{}", inviteInfo.getDeviceId(), param.getStream()); | ||
| 611 | } | 617 | } |
| 612 | } catch (InvalidArgumentException | ParseException | SipException | | 618 | } catch (InvalidArgumentException | ParseException | SipException | |
| 613 | SsrcTransactionNotFoundException e) { | 619 | SsrcTransactionNotFoundException e) { |
| 614 | logger.error("[无人观看]点播, 发送BYE失败 {}", e.getMessage()); | 620 | logger.error("[无人观看]点播, 发送BYE失败 {}", e.getMessage()); |
| 615 | } | 621 | } |
| 622 | + }else { | ||
| 623 | + logger.info("[无人观看] 未找到设备: {},流:{}", inviteInfo.getDeviceId(), param.getStream()); | ||
| 616 | } | 624 | } |
| 617 | 625 | ||
| 618 | inviteStreamService.removeInviteInfo(inviteInfo.getType(), inviteInfo.getDeviceId(), | 626 | inviteStreamService.removeInviteInfo(inviteInfo.getType(), inviteInfo.getDeviceId(), |
| @@ -684,7 +692,7 @@ public class ZLMHttpHookListener { | @@ -684,7 +692,7 @@ public class ZLMHttpHookListener { | ||
| 684 | String deviceId = s[0]; | 692 | String deviceId = s[0]; |
| 685 | String channelId = s[1]; | 693 | String channelId = s[1]; |
| 686 | Device device = redisCatchStorage.getDevice(deviceId); | 694 | Device device = redisCatchStorage.getDevice(deviceId); |
| 687 | - if (device == null) { | 695 | + if (device == null || !device.isOnLine()) { |
| 688 | defaultResult.setResult(new HookResult(ErrorCode.ERROR404.getCode(), ErrorCode.ERROR404.getMsg())); | 696 | defaultResult.setResult(new HookResult(ErrorCode.ERROR404.getCode(), ErrorCode.ERROR404.getMsg())); |
| 689 | return defaultResult; | 697 | return defaultResult; |
| 690 | } | 698 | } |
| @@ -848,11 +856,33 @@ public class ZLMHttpHookListener { | @@ -848,11 +856,33 @@ public class ZLMHttpHookListener { | ||
| 848 | taskExecutor.execute(() -> { | 856 | taskExecutor.execute(() -> { |
| 849 | JSONObject json = (JSONObject) JSON.toJSON(param); | 857 | JSONObject json = (JSONObject) JSON.toJSON(param); |
| 850 | List<ZlmHttpHookSubscribe.Event> subscribes = this.subscribe.getSubscribes(HookType.on_rtp_server_timeout); | 858 | List<ZlmHttpHookSubscribe.Event> subscribes = this.subscribe.getSubscribes(HookType.on_rtp_server_timeout); |
| 851 | - if (subscribes != null && subscribes.size() > 0) { | 859 | + if (subscribes != null && !subscribes.isEmpty()) { |
| 860 | + for (ZlmHttpHookSubscribe.Event subscribe : subscribes) { | ||
| 861 | + subscribe.response(null, param); | ||
| 862 | + } | ||
| 863 | + } | ||
| 864 | + }); | ||
| 865 | + | ||
| 866 | + return HookResult.SUCCESS(); | ||
| 867 | + } | ||
| 868 | + | ||
| 869 | + /** | ||
| 870 | + * 录像完成事件 | ||
| 871 | + */ | ||
| 872 | + @ResponseBody | ||
| 873 | + @PostMapping(value = "/on_record_mp4", produces = "application/json;charset=UTF-8") | ||
| 874 | + public HookResult onRecordMp4(HttpServletRequest request, @RequestBody OnRecordMp4HookParam param) { | ||
| 875 | + logger.info("[ZLM HOOK] 录像完成事件:{}->{}", param.getMediaServerId(), param.getFile_path()); | ||
| 876 | + | ||
| 877 | + taskExecutor.execute(() -> { | ||
| 878 | + List<ZlmHttpHookSubscribe.Event> subscribes = this.subscribe.getSubscribes(HookType.on_record_mp4); | ||
| 879 | + if (subscribes != null && !subscribes.isEmpty()) { | ||
| 852 | for (ZlmHttpHookSubscribe.Event subscribe : subscribes) { | 880 | for (ZlmHttpHookSubscribe.Event subscribe : subscribes) { |
| 853 | subscribe.response(null, param); | 881 | subscribe.response(null, param); |
| 854 | } | 882 | } |
| 855 | } | 883 | } |
| 884 | + cloudRecordService.addRecord(param); | ||
| 885 | + | ||
| 856 | }); | 886 | }); |
| 857 | 887 | ||
| 858 | return HookResult.SUCCESS(); | 888 | return HookResult.SUCCESS(); |
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRESTfulUtils.java
| @@ -25,8 +25,6 @@ public class ZLMRESTfulUtils { | @@ -25,8 +25,6 @@ public class ZLMRESTfulUtils { | ||
| 25 | 25 | ||
| 26 | private OkHttpClient client; | 26 | private OkHttpClient client; |
| 27 | 27 | ||
| 28 | - | ||
| 29 | - | ||
| 30 | public interface RequestCallback{ | 28 | public interface RequestCallback{ |
| 31 | void run(JSONObject response); | 29 | void run(JSONObject response); |
| 32 | } | 30 | } |
| @@ -405,4 +403,14 @@ public class ZLMRESTfulUtils { | @@ -405,4 +403,14 @@ public class ZLMRESTfulUtils { | ||
| 405 | param.put("stream_id", streamId); | 403 | param.put("stream_id", streamId); |
| 406 | return sendPost(mediaServerItem, "updateRtpServerSSRC",param, null); | 404 | return sendPost(mediaServerItem, "updateRtpServerSSRC",param, null); |
| 407 | } | 405 | } |
| 406 | + | ||
| 407 | + public JSONObject deleteRecordDirectory(MediaServerItem mediaServerItem, String app, String stream, String date, String fileName) { | ||
| 408 | + Map<String, Object> param = new HashMap<>(1); | ||
| 409 | + param.put("vhost", "__defaultVhost__"); | ||
| 410 | + param.put("app", app); | ||
| 411 | + param.put("stream", stream); | ||
| 412 | + param.put("period", date); | ||
| 413 | + param.put("name", fileName); | ||
| 414 | + return sendPost(mediaServerItem, "deleteRecordDirectory",param, null); | ||
| 415 | + } | ||
| 408 | } | 416 | } |
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/HookSubscribeFactory.java
| @@ -57,4 +57,15 @@ public class HookSubscribeFactory { | @@ -57,4 +57,15 @@ public class HookSubscribeFactory { | ||
| 57 | return hookSubscribe; | 57 | return hookSubscribe; |
| 58 | } | 58 | } |
| 59 | 59 | ||
| 60 | + public static HookSubscribeForRecordMp4 on_record_mp4(String mediaServerId, String app, String stream) { | ||
| 61 | + HookSubscribeForRecordMp4 hookSubscribe = new HookSubscribeForRecordMp4(); | ||
| 62 | + JSONObject subscribeKey = new com.alibaba.fastjson2.JSONObject(); | ||
| 63 | + subscribeKey.put("app", app); | ||
| 64 | + subscribeKey.put("stream", stream); | ||
| 65 | + subscribeKey.put("mediaServerId", mediaServerId); | ||
| 66 | + hookSubscribe.setContent(subscribeKey); | ||
| 67 | + | ||
| 68 | + return hookSubscribe; | ||
| 69 | + } | ||
| 70 | + | ||
| 60 | } | 71 | } |
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/HookSubscribeForRecordMp4.java
0 → 100755
| 1 | +package com.genersoft.iot.vmp.media.zlm.dto; | ||
| 2 | + | ||
| 3 | +import com.alibaba.fastjson2.JSONObject; | ||
| 4 | +import com.alibaba.fastjson2.annotation.JSONField; | ||
| 5 | + | ||
| 6 | +import java.time.Instant; | ||
| 7 | + | ||
| 8 | +/** | ||
| 9 | + * hook订阅-录像完成 | ||
| 10 | + * @author lin | ||
| 11 | + */ | ||
| 12 | +public class HookSubscribeForRecordMp4 implements IHookSubscribe{ | ||
| 13 | + | ||
| 14 | + private HookType hookType = HookType.on_record_mp4; | ||
| 15 | + | ||
| 16 | + private JSONObject content; | ||
| 17 | + | ||
| 18 | + @JSONField(format="yyyy-MM-dd HH:mm:ss") | ||
| 19 | + private Instant expires; | ||
| 20 | + | ||
| 21 | + @Override | ||
| 22 | + public HookType getHookType() { | ||
| 23 | + return hookType; | ||
| 24 | + } | ||
| 25 | + | ||
| 26 | + @Override | ||
| 27 | + public JSONObject getContent() { | ||
| 28 | + return content; | ||
| 29 | + } | ||
| 30 | + | ||
| 31 | + public void setContent(JSONObject content) { | ||
| 32 | + this.content = content; | ||
| 33 | + } | ||
| 34 | + | ||
| 35 | + @Override | ||
| 36 | + public Instant getExpires() { | ||
| 37 | + return expires; | ||
| 38 | + } | ||
| 39 | + | ||
| 40 | + @Override | ||
| 41 | + public void setExpires(Instant expires) { | ||
| 42 | + this.expires = expires; | ||
| 43 | + } | ||
| 44 | +} |
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/MediaServerItem.java
| @@ -80,9 +80,11 @@ public class MediaServerItem{ | @@ -80,9 +80,11 @@ public class MediaServerItem{ | ||
| 80 | @Schema(description = "是否是默认ZLM") | 80 | @Schema(description = "是否是默认ZLM") |
| 81 | private boolean defaultServer; | 81 | private boolean defaultServer; |
| 82 | 82 | ||
| 83 | - @Schema(description = "当前使用到的端口") | ||
| 84 | - private int currentPort; | 83 | + @Schema(description = "录像存储时长") |
| 84 | + private int recordDay; | ||
| 85 | 85 | ||
| 86 | + @Schema(description = "录像存储路径") | ||
| 87 | + private String recordPath; | ||
| 86 | 88 | ||
| 87 | public MediaServerItem() { | 89 | public MediaServerItem() { |
| 88 | } | 90 | } |
| @@ -269,14 +271,6 @@ public class MediaServerItem{ | @@ -269,14 +271,6 @@ public class MediaServerItem{ | ||
| 269 | this.updateTime = updateTime; | 271 | this.updateTime = updateTime; |
| 270 | } | 272 | } |
| 271 | 273 | ||
| 272 | - public int getCurrentPort() { | ||
| 273 | - return currentPort; | ||
| 274 | - } | ||
| 275 | - | ||
| 276 | - public void setCurrentPort(int currentPort) { | ||
| 277 | - this.currentPort = currentPort; | ||
| 278 | - } | ||
| 279 | - | ||
| 280 | public boolean isStatus() { | 274 | public boolean isStatus() { |
| 281 | return status; | 275 | return status; |
| 282 | } | 276 | } |
| @@ -308,4 +302,20 @@ public class MediaServerItem{ | @@ -308,4 +302,20 @@ public class MediaServerItem{ | ||
| 308 | public void setSendRtpPortRange(String sendRtpPortRange) { | 302 | public void setSendRtpPortRange(String sendRtpPortRange) { |
| 309 | this.sendRtpPortRange = sendRtpPortRange; | 303 | this.sendRtpPortRange = sendRtpPortRange; |
| 310 | } | 304 | } |
| 305 | + | ||
| 306 | + public int getRecordDay() { | ||
| 307 | + return recordDay; | ||
| 308 | + } | ||
| 309 | + | ||
| 310 | + public void setRecordDay(int recordDay) { | ||
| 311 | + this.recordDay = recordDay; | ||
| 312 | + } | ||
| 313 | + | ||
| 314 | + public String getRecordPath() { | ||
| 315 | + return recordPath; | ||
| 316 | + } | ||
| 317 | + | ||
| 318 | + public void setRecordPath(String recordPath) { | ||
| 319 | + this.recordPath = recordPath; | ||
| 320 | + } | ||
| 311 | } | 321 | } |
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/HookResultForOnPublish.java
| @@ -7,6 +7,7 @@ public class HookResultForOnPublish extends HookResult{ | @@ -7,6 +7,7 @@ public class HookResultForOnPublish extends HookResult{ | ||
| 7 | private int mp4_max_second; | 7 | private int mp4_max_second; |
| 8 | private String mp4_save_path; | 8 | private String mp4_save_path; |
| 9 | private String stream_replace; | 9 | private String stream_replace; |
| 10 | + private Integer modify_stamp; | ||
| 10 | 11 | ||
| 11 | public HookResultForOnPublish() { | 12 | public HookResultForOnPublish() { |
| 12 | } | 13 | } |
| @@ -60,14 +61,23 @@ public class HookResultForOnPublish extends HookResult{ | @@ -60,14 +61,23 @@ public class HookResultForOnPublish extends HookResult{ | ||
| 60 | this.stream_replace = stream_replace; | 61 | this.stream_replace = stream_replace; |
| 61 | } | 62 | } |
| 62 | 63 | ||
| 64 | + public Integer getModify_stamp() { | ||
| 65 | + return modify_stamp; | ||
| 66 | + } | ||
| 67 | + | ||
| 68 | + public void setModify_stamp(Integer modify_stamp) { | ||
| 69 | + this.modify_stamp = modify_stamp; | ||
| 70 | + } | ||
| 71 | + | ||
| 63 | @Override | 72 | @Override |
| 64 | public String toString() { | 73 | public String toString() { |
| 65 | return "HookResultForOnPublish{" + | 74 | return "HookResultForOnPublish{" + |
| 66 | "enable_audio=" + enable_audio + | 75 | "enable_audio=" + enable_audio + |
| 67 | ", enable_mp4=" + enable_mp4 + | 76 | ", enable_mp4=" + enable_mp4 + |
| 68 | ", mp4_max_second=" + mp4_max_second + | 77 | ", mp4_max_second=" + mp4_max_second + |
| 69 | - ", stream_replace=" + stream_replace + | ||
| 70 | ", mp4_save_path='" + mp4_save_path + '\'' + | 78 | ", mp4_save_path='" + mp4_save_path + '\'' + |
| 79 | + ", stream_replace='" + stream_replace + '\'' + | ||
| 80 | + ", modify_stamp='" + modify_stamp + '\'' + | ||
| 71 | '}'; | 81 | '}'; |
| 72 | } | 82 | } |
| 73 | } | 83 | } |
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnRecordMp4HookParam.java
0 → 100755
| 1 | +package com.genersoft.iot.vmp.media.zlm.dto.hook; | ||
| 2 | + | ||
| 3 | +/** | ||
| 4 | + * zlm hook事件中的on_rtp_server_timeout事件的参数 | ||
| 5 | + * @author lin | ||
| 6 | + */ | ||
| 7 | +public class OnRecordMp4HookParam extends HookParam{ | ||
| 8 | + private String app; | ||
| 9 | + private String stream; | ||
| 10 | + private String file_name; | ||
| 11 | + private String file_path; | ||
| 12 | + private long file_size; | ||
| 13 | + private String folder; | ||
| 14 | + private String url; | ||
| 15 | + private String vhost; | ||
| 16 | + private long start_time; | ||
| 17 | + private double time_len; | ||
| 18 | + | ||
| 19 | + public String getApp() { | ||
| 20 | + return app; | ||
| 21 | + } | ||
| 22 | + | ||
| 23 | + public void setApp(String app) { | ||
| 24 | + this.app = app; | ||
| 25 | + } | ||
| 26 | + | ||
| 27 | + public String getStream() { | ||
| 28 | + return stream; | ||
| 29 | + } | ||
| 30 | + | ||
| 31 | + public void setStream(String stream) { | ||
| 32 | + this.stream = stream; | ||
| 33 | + } | ||
| 34 | + | ||
| 35 | + public String getFile_name() { | ||
| 36 | + return file_name; | ||
| 37 | + } | ||
| 38 | + | ||
| 39 | + public void setFile_name(String file_name) { | ||
| 40 | + this.file_name = file_name; | ||
| 41 | + } | ||
| 42 | + | ||
| 43 | + public String getFile_path() { | ||
| 44 | + return file_path; | ||
| 45 | + } | ||
| 46 | + | ||
| 47 | + public void setFile_path(String file_path) { | ||
| 48 | + this.file_path = file_path; | ||
| 49 | + } | ||
| 50 | + | ||
| 51 | + public long getFile_size() { | ||
| 52 | + return file_size; | ||
| 53 | + } | ||
| 54 | + | ||
| 55 | + public void setFile_size(long file_size) { | ||
| 56 | + this.file_size = file_size; | ||
| 57 | + } | ||
| 58 | + | ||
| 59 | + public String getFolder() { | ||
| 60 | + return folder; | ||
| 61 | + } | ||
| 62 | + | ||
| 63 | + public void setFolder(String folder) { | ||
| 64 | + this.folder = folder; | ||
| 65 | + } | ||
| 66 | + | ||
| 67 | + public String getUrl() { | ||
| 68 | + return url; | ||
| 69 | + } | ||
| 70 | + | ||
| 71 | + public void setUrl(String url) { | ||
| 72 | + this.url = url; | ||
| 73 | + } | ||
| 74 | + | ||
| 75 | + public String getVhost() { | ||
| 76 | + return vhost; | ||
| 77 | + } | ||
| 78 | + | ||
| 79 | + public void setVhost(String vhost) { | ||
| 80 | + this.vhost = vhost; | ||
| 81 | + } | ||
| 82 | + | ||
| 83 | + public long getStart_time() { | ||
| 84 | + return start_time; | ||
| 85 | + } | ||
| 86 | + | ||
| 87 | + public void setStart_time(long start_time) { | ||
| 88 | + this.start_time = start_time; | ||
| 89 | + } | ||
| 90 | + | ||
| 91 | + public double getTime_len() { | ||
| 92 | + return time_len; | ||
| 93 | + } | ||
| 94 | + | ||
| 95 | + public void setTime_len(double time_len) { | ||
| 96 | + this.time_len = time_len; | ||
| 97 | + } | ||
| 98 | + | ||
| 99 | + @Override | ||
| 100 | + public String toString() { | ||
| 101 | + return "OnRecordMp4HookParam{" + | ||
| 102 | + "app='" + app + '\'' + | ||
| 103 | + ", stream='" + stream + '\'' + | ||
| 104 | + ", file_name='" + file_name + '\'' + | ||
| 105 | + ", file_path='" + file_path + '\'' + | ||
| 106 | + ", file_size='" + file_size + '\'' + | ||
| 107 | + ", folder='" + folder + '\'' + | ||
| 108 | + ", url='" + url + '\'' + | ||
| 109 | + ", vhost='" + vhost + '\'' + | ||
| 110 | + ", start_time=" + start_time + | ||
| 111 | + ", time_len=" + time_len + | ||
| 112 | + '}'; | ||
| 113 | + } | ||
| 114 | +} |
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnStreamChangedHookParam.java
| @@ -120,17 +120,17 @@ public class OnStreamChangedHookParam extends HookParam{ | @@ -120,17 +120,17 @@ public class OnStreamChangedHookParam extends HookParam{ | ||
| 120 | /** | 120 | /** |
| 121 | * H264 = 0, H265 = 1, AAC = 2, G711A = 3, G711U = 4 | 121 | * H264 = 0, H265 = 1, AAC = 2, G711A = 3, G711U = 4 |
| 122 | */ | 122 | */ |
| 123 | - private int codecId; | 123 | + private int codec_id; |
| 124 | 124 | ||
| 125 | /** | 125 | /** |
| 126 | * 编码类型名称 CodecAAC CodecH264 | 126 | * 编码类型名称 CodecAAC CodecH264 |
| 127 | */ | 127 | */ |
| 128 | - private String codecIdName; | 128 | + private String codec_id_name; |
| 129 | 129 | ||
| 130 | /** | 130 | /** |
| 131 | * Video = 0, Audio = 1 | 131 | * Video = 0, Audio = 1 |
| 132 | */ | 132 | */ |
| 133 | - private int codecType; | 133 | + private int codec_type; |
| 134 | 134 | ||
| 135 | /** | 135 | /** |
| 136 | * 轨道是否准备就绪 | 136 | * 轨道是否准备就绪 |
| @@ -140,17 +140,17 @@ public class OnStreamChangedHookParam extends HookParam{ | @@ -140,17 +140,17 @@ public class OnStreamChangedHookParam extends HookParam{ | ||
| 140 | /** | 140 | /** |
| 141 | * 音频采样位数 | 141 | * 音频采样位数 |
| 142 | */ | 142 | */ |
| 143 | - private int sampleBit; | 143 | + private int sample_bit; |
| 144 | 144 | ||
| 145 | /** | 145 | /** |
| 146 | * 音频采样率 | 146 | * 音频采样率 |
| 147 | */ | 147 | */ |
| 148 | - private int sampleRate; | 148 | + private int sample_rate; |
| 149 | 149 | ||
| 150 | /** | 150 | /** |
| 151 | * 视频fps | 151 | * 视频fps |
| 152 | */ | 152 | */ |
| 153 | - private int fps; | 153 | + private float fps; |
| 154 | 154 | ||
| 155 | /** | 155 | /** |
| 156 | * 视频高 | 156 | * 视频高 |
| @@ -162,6 +162,31 @@ public class OnStreamChangedHookParam extends HookParam{ | @@ -162,6 +162,31 @@ public class OnStreamChangedHookParam extends HookParam{ | ||
| 162 | */ | 162 | */ |
| 163 | private int width; | 163 | private int width; |
| 164 | 164 | ||
| 165 | + /** | ||
| 166 | + * 帧数 | ||
| 167 | + */ | ||
| 168 | + private int frames; | ||
| 169 | + | ||
| 170 | + /** | ||
| 171 | + * 关键帧数 | ||
| 172 | + */ | ||
| 173 | + private int key_frames; | ||
| 174 | + | ||
| 175 | + /** | ||
| 176 | + * GOP大小 | ||
| 177 | + */ | ||
| 178 | + private int gop_size; | ||
| 179 | + | ||
| 180 | + /** | ||
| 181 | + * GOP间隔时长(ms) | ||
| 182 | + */ | ||
| 183 | + private int gop_interval_ms; | ||
| 184 | + | ||
| 185 | + /** | ||
| 186 | + * 丢帧率 | ||
| 187 | + */ | ||
| 188 | + private float loss; | ||
| 189 | + | ||
| 165 | public int getChannels() { | 190 | public int getChannels() { |
| 166 | return channels; | 191 | return channels; |
| 167 | } | 192 | } |
| @@ -170,28 +195,28 @@ public class OnStreamChangedHookParam extends HookParam{ | @@ -170,28 +195,28 @@ public class OnStreamChangedHookParam extends HookParam{ | ||
| 170 | this.channels = channels; | 195 | this.channels = channels; |
| 171 | } | 196 | } |
| 172 | 197 | ||
| 173 | - public int getCodecId() { | ||
| 174 | - return codecId; | 198 | + public int getCodec_id() { |
| 199 | + return codec_id; | ||
| 175 | } | 200 | } |
| 176 | 201 | ||
| 177 | - public void setCodecId(int codecId) { | ||
| 178 | - this.codecId = codecId; | 202 | + public void setCodec_id(int codec_id) { |
| 203 | + this.codec_id = codec_id; | ||
| 179 | } | 204 | } |
| 180 | 205 | ||
| 181 | - public String getCodecIdName() { | ||
| 182 | - return codecIdName; | 206 | + public String getCodec_id_name() { |
| 207 | + return codec_id_name; | ||
| 183 | } | 208 | } |
| 184 | 209 | ||
| 185 | - public void setCodecIdName(String codecIdName) { | ||
| 186 | - this.codecIdName = codecIdName; | 210 | + public void setCodec_id_name(String codec_id_name) { |
| 211 | + this.codec_id_name = codec_id_name; | ||
| 187 | } | 212 | } |
| 188 | 213 | ||
| 189 | - public int getCodecType() { | ||
| 190 | - return codecType; | 214 | + public int getCodec_type() { |
| 215 | + return codec_type; | ||
| 191 | } | 216 | } |
| 192 | 217 | ||
| 193 | - public void setCodecType(int codecType) { | ||
| 194 | - this.codecType = codecType; | 218 | + public void setCodec_type(int codec_type) { |
| 219 | + this.codec_type = codec_type; | ||
| 195 | } | 220 | } |
| 196 | 221 | ||
| 197 | public boolean isReady() { | 222 | public boolean isReady() { |
| @@ -202,27 +227,27 @@ public class OnStreamChangedHookParam extends HookParam{ | @@ -202,27 +227,27 @@ public class OnStreamChangedHookParam extends HookParam{ | ||
| 202 | this.ready = ready; | 227 | this.ready = ready; |
| 203 | } | 228 | } |
| 204 | 229 | ||
| 205 | - public int getSampleBit() { | ||
| 206 | - return sampleBit; | 230 | + public int getSample_bit() { |
| 231 | + return sample_bit; | ||
| 207 | } | 232 | } |
| 208 | 233 | ||
| 209 | - public void setSampleBit(int sampleBit) { | ||
| 210 | - this.sampleBit = sampleBit; | 234 | + public void setSample_bit(int sample_bit) { |
| 235 | + this.sample_bit = sample_bit; | ||
| 211 | } | 236 | } |
| 212 | 237 | ||
| 213 | - public int getSampleRate() { | ||
| 214 | - return sampleRate; | 238 | + public int getSample_rate() { |
| 239 | + return sample_rate; | ||
| 215 | } | 240 | } |
| 216 | 241 | ||
| 217 | - public void setSampleRate(int sampleRate) { | ||
| 218 | - this.sampleRate = sampleRate; | 242 | + public void setSample_rate(int sample_rate) { |
| 243 | + this.sample_rate = sample_rate; | ||
| 219 | } | 244 | } |
| 220 | 245 | ||
| 221 | - public int getFps() { | 246 | + public float getFps() { |
| 222 | return fps; | 247 | return fps; |
| 223 | } | 248 | } |
| 224 | 249 | ||
| 225 | - public void setFps(int fps) { | 250 | + public void setFps(float fps) { |
| 226 | this.fps = fps; | 251 | this.fps = fps; |
| 227 | } | 252 | } |
| 228 | 253 | ||
| @@ -241,6 +266,46 @@ public class OnStreamChangedHookParam extends HookParam{ | @@ -241,6 +266,46 @@ public class OnStreamChangedHookParam extends HookParam{ | ||
| 241 | public void setWidth(int width) { | 266 | public void setWidth(int width) { |
| 242 | this.width = width; | 267 | this.width = width; |
| 243 | } | 268 | } |
| 269 | + | ||
| 270 | + public int getFrames() { | ||
| 271 | + return frames; | ||
| 272 | + } | ||
| 273 | + | ||
| 274 | + public void setFrames(int frames) { | ||
| 275 | + this.frames = frames; | ||
| 276 | + } | ||
| 277 | + | ||
| 278 | + public int getKey_frames() { | ||
| 279 | + return key_frames; | ||
| 280 | + } | ||
| 281 | + | ||
| 282 | + public void setKey_frames(int key_frames) { | ||
| 283 | + this.key_frames = key_frames; | ||
| 284 | + } | ||
| 285 | + | ||
| 286 | + public int getGop_size() { | ||
| 287 | + return gop_size; | ||
| 288 | + } | ||
| 289 | + | ||
| 290 | + public void setGop_size(int gop_size) { | ||
| 291 | + this.gop_size = gop_size; | ||
| 292 | + } | ||
| 293 | + | ||
| 294 | + public int getGop_interval_ms() { | ||
| 295 | + return gop_interval_ms; | ||
| 296 | + } | ||
| 297 | + | ||
| 298 | + public void setGop_interval_ms(int gop_interval_ms) { | ||
| 299 | + this.gop_interval_ms = gop_interval_ms; | ||
| 300 | + } | ||
| 301 | + | ||
| 302 | + public float getLoss() { | ||
| 303 | + return loss; | ||
| 304 | + } | ||
| 305 | + | ||
| 306 | + public void setLoss(float loss) { | ||
| 307 | + this.loss = loss; | ||
| 308 | + } | ||
| 244 | } | 309 | } |
| 245 | 310 | ||
| 246 | public static class OriginSock{ | 311 | public static class OriginSock{ |
src/main/java/com/genersoft/iot/vmp/service/ICloudRecordService.java
0 → 100755
| 1 | +package com.genersoft.iot.vmp.service; | ||
| 2 | + | ||
| 3 | +import com.alibaba.fastjson2.JSONArray; | ||
| 4 | +import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; | ||
| 5 | +import com.genersoft.iot.vmp.media.zlm.dto.hook.OnRecordMp4HookParam; | ||
| 6 | +import com.genersoft.iot.vmp.service.bean.CloudRecordItem; | ||
| 7 | +import com.genersoft.iot.vmp.service.bean.DownloadFileInfo; | ||
| 8 | +import com.github.pagehelper.PageInfo; | ||
| 9 | + | ||
| 10 | +import java.util.List; | ||
| 11 | + | ||
| 12 | +/** | ||
| 13 | + * 云端录像管理 | ||
| 14 | + * @author lin | ||
| 15 | + */ | ||
| 16 | +public interface ICloudRecordService { | ||
| 17 | + | ||
| 18 | + /** | ||
| 19 | + * 分页回去云端录像列表 | ||
| 20 | + */ | ||
| 21 | + PageInfo<CloudRecordItem> getList(int page, int count, String query, String app, String stream, String startTime, String endTime, List<MediaServerItem> mediaServerItems); | ||
| 22 | + | ||
| 23 | + /** | ||
| 24 | + * 根据hook消息增加一条记录 | ||
| 25 | + */ | ||
| 26 | + void addRecord(OnRecordMp4HookParam param); | ||
| 27 | + | ||
| 28 | + /** | ||
| 29 | + * 获取所有的日期 | ||
| 30 | + */ | ||
| 31 | + List<String> getDateList(String app, String stream, int year, int month, List<MediaServerItem> mediaServerItems); | ||
| 32 | + | ||
| 33 | + /** | ||
| 34 | + * 添加合并任务 | ||
| 35 | + */ | ||
| 36 | + String addTask(String app, String stream, MediaServerItem mediaServerItem, String startTime, | ||
| 37 | + String endTime, String callId, String remoteHost, boolean filterMediaServer); | ||
| 38 | + | ||
| 39 | + | ||
| 40 | + /** | ||
| 41 | + * 查询合并任务列表 | ||
| 42 | + */ | ||
| 43 | + JSONArray queryTask(String app, String stream, String callId, String taskId, String mediaServerId, Boolean isEnd, String scheme); | ||
| 44 | + | ||
| 45 | + /** | ||
| 46 | + * 收藏视频,收藏的视频过期不会删除 | ||
| 47 | + */ | ||
| 48 | + int changeCollect(boolean result, String app, String stream, String mediaServerId, String startTime, String endTime, String callId); | ||
| 49 | + | ||
| 50 | + /** | ||
| 51 | + * 添加指定录像收藏 | ||
| 52 | + */ | ||
| 53 | + int changeCollectById(Integer recordId, boolean result); | ||
| 54 | + | ||
| 55 | + /** | ||
| 56 | + * 获取播放地址 | ||
| 57 | + */ | ||
| 58 | + DownloadFileInfo getPlayUrlPath(Integer recordId); | ||
| 59 | +} |
src/main/java/com/genersoft/iot/vmp/service/IMediaServerService.java
| @@ -89,21 +89,12 @@ public interface IMediaServerService { | @@ -89,21 +89,12 @@ public interface IMediaServerService { | ||
| 89 | 89 | ||
| 90 | void updateMediaServerKeepalive(String mediaServerId, ServerKeepaliveData data); | 90 | void updateMediaServerKeepalive(String mediaServerId, ServerKeepaliveData data); |
| 91 | 91 | ||
| 92 | - boolean checkRtpServer(MediaServerItem mediaServerItem, String rtp, String stream); | ||
| 93 | - | ||
| 94 | /** | 92 | /** |
| 95 | * 获取负载信息 | 93 | * 获取负载信息 |
| 96 | * @return | 94 | * @return |
| 97 | */ | 95 | */ |
| 98 | MediaServerLoad getLoad(MediaServerItem mediaServerItem); | 96 | MediaServerLoad getLoad(MediaServerItem mediaServerItem); |
| 99 | 97 | ||
| 100 | - /** | ||
| 101 | - * 按时间查找录像文件 | ||
| 102 | - */ | ||
| 103 | - List<RecordFile> getRecords(String app, String stream, String startTime, String endTime, List<MediaServerItem> mediaServerItems); | 98 | + List<MediaServerItem> getAllWithAssistPort(); |
| 104 | 99 | ||
| 105 | - /** | ||
| 106 | - * 查找存在录像文件的时间 | ||
| 107 | - */ | ||
| 108 | - List<String> getRecordDates(String app, String stream, int year, int month, List<MediaServerItem> mediaServerItems); | ||
| 109 | } | 100 | } |
src/main/java/com/genersoft/iot/vmp/service/IPlayService.java
| @@ -33,11 +33,6 @@ public interface IPlayService { | @@ -33,11 +33,6 @@ public interface IPlayService { | ||
| 33 | 33 | ||
| 34 | MediaServerItem getNewMediaServerItem(Device device); | 34 | MediaServerItem getNewMediaServerItem(Device device); |
| 35 | 35 | ||
| 36 | - /** | ||
| 37 | - * 获取包含assist服务的节点 | ||
| 38 | - */ | ||
| 39 | - MediaServerItem getNewMediaServerItemHasAssist(Device device); | ||
| 40 | - | ||
| 41 | void playBack(String deviceId, String channelId, String startTime, String endTime, ErrorCallback<Object> callback); | 36 | void playBack(String deviceId, String channelId, String startTime, String endTime, ErrorCallback<Object> callback); |
| 42 | void playBack(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, String deviceId, String channelId, String startTime, String endTime, ErrorCallback<Object> callback); | 37 | void playBack(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, String deviceId, String channelId, String startTime, String endTime, ErrorCallback<Object> callback); |
| 43 | void zlmServerOffline(String mediaServerId); | 38 | void zlmServerOffline(String mediaServerId); |
| @@ -72,5 +67,4 @@ public interface IPlayService { | @@ -72,5 +67,4 @@ public interface IPlayService { | ||
| 72 | 67 | ||
| 73 | void getSnap(String deviceId, String channelId, String fileName, ErrorCallback errorCallback); | 68 | void getSnap(String deviceId, String channelId, String fileName, ErrorCallback errorCallback); |
| 74 | 69 | ||
| 75 | - | ||
| 76 | } | 70 | } |
src/main/java/com/genersoft/iot/vmp/service/IStreamPushService.java
src/main/java/com/genersoft/iot/vmp/service/bean/CloudRecordItem.java
0 → 100644
| 1 | +package com.genersoft.iot.vmp.service.bean; | ||
| 2 | + | ||
| 3 | +import com.genersoft.iot.vmp.media.zlm.dto.hook.OnRecordMp4HookParam; | ||
| 4 | + | ||
| 5 | +/** | ||
| 6 | + * 云端录像数据 | ||
| 7 | + */ | ||
| 8 | +public class CloudRecordItem { | ||
| 9 | + /** | ||
| 10 | + * 主键 | ||
| 11 | + */ | ||
| 12 | + private int id; | ||
| 13 | + | ||
| 14 | + /** | ||
| 15 | + * 应用名 | ||
| 16 | + */ | ||
| 17 | + private String app; | ||
| 18 | + | ||
| 19 | + /** | ||
| 20 | + * 流 | ||
| 21 | + */ | ||
| 22 | + private String stream; | ||
| 23 | + | ||
| 24 | + /** | ||
| 25 | + * 健全ID | ||
| 26 | + */ | ||
| 27 | + private String callId; | ||
| 28 | + | ||
| 29 | + /** | ||
| 30 | + * 开始时间 | ||
| 31 | + */ | ||
| 32 | + private long startTime; | ||
| 33 | + | ||
| 34 | + /** | ||
| 35 | + * 结束时间 | ||
| 36 | + */ | ||
| 37 | + private long endTime; | ||
| 38 | + | ||
| 39 | + /** | ||
| 40 | + * ZLM Id | ||
| 41 | + */ | ||
| 42 | + private String mediaServerId; | ||
| 43 | + | ||
| 44 | + /** | ||
| 45 | + * 文件名称 | ||
| 46 | + */ | ||
| 47 | + private String fileName; | ||
| 48 | + | ||
| 49 | + /** | ||
| 50 | + * 文件路径 | ||
| 51 | + */ | ||
| 52 | + private String filePath; | ||
| 53 | + | ||
| 54 | + /** | ||
| 55 | + * 文件夹 | ||
| 56 | + */ | ||
| 57 | + private String folder; | ||
| 58 | + | ||
| 59 | + /** | ||
| 60 | + * 收藏,收藏的文件不移除 | ||
| 61 | + */ | ||
| 62 | + private Boolean collect; | ||
| 63 | + | ||
| 64 | + /** | ||
| 65 | + * 保留,收藏的文件不移除 | ||
| 66 | + */ | ||
| 67 | + private Boolean reserve; | ||
| 68 | + | ||
| 69 | + /** | ||
| 70 | + * 文件大小 | ||
| 71 | + */ | ||
| 72 | + private long fileSize; | ||
| 73 | + | ||
| 74 | + /** | ||
| 75 | + * 文件时长 | ||
| 76 | + */ | ||
| 77 | + private long timeLen; | ||
| 78 | + | ||
| 79 | + public static CloudRecordItem getInstance(OnRecordMp4HookParam param) { | ||
| 80 | + CloudRecordItem cloudRecordItem = new CloudRecordItem(); | ||
| 81 | + cloudRecordItem.setApp(param.getApp()); | ||
| 82 | + cloudRecordItem.setStream(param.getStream()); | ||
| 83 | + cloudRecordItem.setStartTime(param.getStart_time()*1000); | ||
| 84 | + cloudRecordItem.setFileName(param.getFile_name()); | ||
| 85 | + cloudRecordItem.setFolder(param.getFolder()); | ||
| 86 | + cloudRecordItem.setFileSize(param.getFile_size()); | ||
| 87 | + cloudRecordItem.setFilePath(param.getFile_path()); | ||
| 88 | + cloudRecordItem.setMediaServerId(param.getMediaServerId()); | ||
| 89 | + cloudRecordItem.setTimeLen((long) param.getTime_len() * 1000); | ||
| 90 | + cloudRecordItem.setEndTime((param.getStart_time() + (long)param.getTime_len()) * 1000); | ||
| 91 | + return cloudRecordItem; | ||
| 92 | + } | ||
| 93 | + | ||
| 94 | + public int getId() { | ||
| 95 | + return id; | ||
| 96 | + } | ||
| 97 | + | ||
| 98 | + public void setId(int id) { | ||
| 99 | + this.id = id; | ||
| 100 | + } | ||
| 101 | + | ||
| 102 | + public String getApp() { | ||
| 103 | + return app; | ||
| 104 | + } | ||
| 105 | + | ||
| 106 | + public void setApp(String app) { | ||
| 107 | + this.app = app; | ||
| 108 | + } | ||
| 109 | + | ||
| 110 | + public String getStream() { | ||
| 111 | + return stream; | ||
| 112 | + } | ||
| 113 | + | ||
| 114 | + public void setStream(String stream) { | ||
| 115 | + this.stream = stream; | ||
| 116 | + } | ||
| 117 | + | ||
| 118 | + public String getCallId() { | ||
| 119 | + return callId; | ||
| 120 | + } | ||
| 121 | + | ||
| 122 | + public void setCallId(String callId) { | ||
| 123 | + this.callId = callId; | ||
| 124 | + } | ||
| 125 | + | ||
| 126 | + public long getStartTime() { | ||
| 127 | + return startTime; | ||
| 128 | + } | ||
| 129 | + | ||
| 130 | + public void setStartTime(long startTime) { | ||
| 131 | + this.startTime = startTime; | ||
| 132 | + } | ||
| 133 | + | ||
| 134 | + public long getEndTime() { | ||
| 135 | + return endTime; | ||
| 136 | + } | ||
| 137 | + | ||
| 138 | + public void setEndTime(long endTime) { | ||
| 139 | + this.endTime = endTime; | ||
| 140 | + } | ||
| 141 | + | ||
| 142 | + public String getMediaServerId() { | ||
| 143 | + return mediaServerId; | ||
| 144 | + } | ||
| 145 | + | ||
| 146 | + public void setMediaServerId(String mediaServerId) { | ||
| 147 | + this.mediaServerId = mediaServerId; | ||
| 148 | + } | ||
| 149 | + | ||
| 150 | + public String getFileName() { | ||
| 151 | + return fileName; | ||
| 152 | + } | ||
| 153 | + | ||
| 154 | + public void setFileName(String fileName) { | ||
| 155 | + this.fileName = fileName; | ||
| 156 | + } | ||
| 157 | + | ||
| 158 | + public String getFilePath() { | ||
| 159 | + return filePath; | ||
| 160 | + } | ||
| 161 | + | ||
| 162 | + public void setFilePath(String filePath) { | ||
| 163 | + this.filePath = filePath; | ||
| 164 | + } | ||
| 165 | + | ||
| 166 | + public String getFolder() { | ||
| 167 | + return folder; | ||
| 168 | + } | ||
| 169 | + | ||
| 170 | + public void setFolder(String folder) { | ||
| 171 | + this.folder = folder; | ||
| 172 | + } | ||
| 173 | + | ||
| 174 | + public long getFileSize() { | ||
| 175 | + return fileSize; | ||
| 176 | + } | ||
| 177 | + | ||
| 178 | + public void setFileSize(long fileSize) { | ||
| 179 | + this.fileSize = fileSize; | ||
| 180 | + } | ||
| 181 | + | ||
| 182 | + public long getTimeLen() { | ||
| 183 | + return timeLen; | ||
| 184 | + } | ||
| 185 | + | ||
| 186 | + public void setTimeLen(long timeLen) { | ||
| 187 | + this.timeLen = timeLen; | ||
| 188 | + } | ||
| 189 | + | ||
| 190 | + public Boolean getCollect() { | ||
| 191 | + return collect; | ||
| 192 | + } | ||
| 193 | + | ||
| 194 | + public void setCollect(Boolean collect) { | ||
| 195 | + this.collect = collect; | ||
| 196 | + } | ||
| 197 | + | ||
| 198 | + public Boolean getReserve() { | ||
| 199 | + return reserve; | ||
| 200 | + } | ||
| 201 | + | ||
| 202 | + public void setReserve(Boolean reserve) { | ||
| 203 | + this.reserve = reserve; | ||
| 204 | + } | ||
| 205 | +} |
src/main/java/com/genersoft/iot/vmp/service/bean/DownloadFileInfo.java
0 → 100644
| 1 | +package com.genersoft.iot.vmp.service.bean; | ||
| 2 | + | ||
| 3 | +public class DownloadFileInfo { | ||
| 4 | + | ||
| 5 | + private String httpPath; | ||
| 6 | + private String httpsPath; | ||
| 7 | + private String httpDomainPath; | ||
| 8 | + private String httpsDomainPath; | ||
| 9 | + | ||
| 10 | + public String getHttpPath() { | ||
| 11 | + return httpPath; | ||
| 12 | + } | ||
| 13 | + | ||
| 14 | + public void setHttpPath(String httpPath) { | ||
| 15 | + this.httpPath = httpPath; | ||
| 16 | + } | ||
| 17 | + | ||
| 18 | + public String getHttpsPath() { | ||
| 19 | + return httpsPath; | ||
| 20 | + } | ||
| 21 | + | ||
| 22 | + public void setHttpsPath(String httpsPath) { | ||
| 23 | + this.httpsPath = httpsPath; | ||
| 24 | + } | ||
| 25 | + | ||
| 26 | + public String getHttpDomainPath() { | ||
| 27 | + return httpDomainPath; | ||
| 28 | + } | ||
| 29 | + | ||
| 30 | + public void setHttpDomainPath(String httpDomainPath) { | ||
| 31 | + this.httpDomainPath = httpDomainPath; | ||
| 32 | + } | ||
| 33 | + | ||
| 34 | + public String getHttpsDomainPath() { | ||
| 35 | + return httpsDomainPath; | ||
| 36 | + } | ||
| 37 | + | ||
| 38 | + public void setHttpsDomainPath(String httpsDomainPath) { | ||
| 39 | + this.httpsDomainPath = httpsDomainPath; | ||
| 40 | + } | ||
| 41 | +} |
src/main/java/com/genersoft/iot/vmp/service/bean/WvpRedisMsg.java
| @@ -29,12 +29,12 @@ public class WvpRedisMsg { | @@ -29,12 +29,12 @@ public class WvpRedisMsg { | ||
| 29 | * 消息的ID | 29 | * 消息的ID |
| 30 | */ | 30 | */ |
| 31 | private String serial; | 31 | private String serial; |
| 32 | - private Object content; | 32 | + private String content; |
| 33 | 33 | ||
| 34 | private final static String requestTag = "req"; | 34 | private final static String requestTag = "req"; |
| 35 | private final static String responseTag = "res"; | 35 | private final static String responseTag = "res"; |
| 36 | 36 | ||
| 37 | - public static WvpRedisMsg getRequestInstance(String fromId, String toId, String cmd, String serial, Object content) { | 37 | + public static WvpRedisMsg getRequestInstance(String fromId, String toId, String cmd, String serial, String content) { |
| 38 | WvpRedisMsg wvpRedisMsg = new WvpRedisMsg(); | 38 | WvpRedisMsg wvpRedisMsg = new WvpRedisMsg(); |
| 39 | wvpRedisMsg.setType(requestTag); | 39 | wvpRedisMsg.setType(requestTag); |
| 40 | wvpRedisMsg.setFromId(fromId); | 40 | wvpRedisMsg.setFromId(fromId); |
| @@ -51,7 +51,7 @@ public class WvpRedisMsg { | @@ -51,7 +51,7 @@ public class WvpRedisMsg { | ||
| 51 | return wvpRedisMsg; | 51 | return wvpRedisMsg; |
| 52 | } | 52 | } |
| 53 | 53 | ||
| 54 | - public static WvpRedisMsg getResponseInstance(String fromId, String toId, String cmd, String serial, Object content) { | 54 | + public static WvpRedisMsg getResponseInstance(String fromId, String toId, String cmd, String serial, String content) { |
| 55 | WvpRedisMsg wvpRedisMsg = new WvpRedisMsg(); | 55 | WvpRedisMsg wvpRedisMsg = new WvpRedisMsg(); |
| 56 | wvpRedisMsg.setType(responseTag); | 56 | wvpRedisMsg.setType(responseTag); |
| 57 | wvpRedisMsg.setFromId(fromId); | 57 | wvpRedisMsg.setFromId(fromId); |
| @@ -106,11 +106,11 @@ public class WvpRedisMsg { | @@ -106,11 +106,11 @@ public class WvpRedisMsg { | ||
| 106 | this.cmd = cmd; | 106 | this.cmd = cmd; |
| 107 | } | 107 | } |
| 108 | 108 | ||
| 109 | - public Object getContent() { | 109 | + public String getContent() { |
| 110 | return content; | 110 | return content; |
| 111 | } | 111 | } |
| 112 | 112 | ||
| 113 | - public void setContent(Object content) { | 113 | + public void setContent(String content) { |
| 114 | this.content = content; | 114 | this.content = content; |
| 115 | } | 115 | } |
| 116 | } | 116 | } |
src/main/java/com/genersoft/iot/vmp/service/impl/CloudRecordServiceImpl.java
0 → 100644
| 1 | +package com.genersoft.iot.vmp.service.impl; | ||
| 2 | + | ||
| 3 | +import com.alibaba.fastjson2.JSONArray; | ||
| 4 | +import com.alibaba.fastjson2.JSONObject; | ||
| 5 | +import com.baomidou.dynamic.datasource.annotation.DS; | ||
| 6 | +import com.genersoft.iot.vmp.conf.exception.ControllerException; | ||
| 7 | +import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager; | ||
| 8 | +import com.genersoft.iot.vmp.media.zlm.AssistRESTfulUtils; | ||
| 9 | +import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; | ||
| 10 | +import com.genersoft.iot.vmp.media.zlm.dto.StreamAuthorityInfo; | ||
| 11 | +import com.genersoft.iot.vmp.media.zlm.dto.hook.OnRecordMp4HookParam; | ||
| 12 | +import com.genersoft.iot.vmp.service.ICloudRecordService; | ||
| 13 | +import com.genersoft.iot.vmp.service.IMediaServerService; | ||
| 14 | +import com.genersoft.iot.vmp.service.bean.CloudRecordItem; | ||
| 15 | +import com.genersoft.iot.vmp.service.bean.DownloadFileInfo; | ||
| 16 | +import com.genersoft.iot.vmp.storager.IRedisCatchStorage; | ||
| 17 | +import com.genersoft.iot.vmp.storager.dao.CloudRecordServiceMapper; | ||
| 18 | +import com.genersoft.iot.vmp.utils.CloudRecordUtils; | ||
| 19 | +import com.genersoft.iot.vmp.utils.DateUtil; | ||
| 20 | +import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; | ||
| 21 | +import com.github.pagehelper.PageHelper; | ||
| 22 | +import com.github.pagehelper.PageInfo; | ||
| 23 | +import org.apache.commons.lang3.ObjectUtils; | ||
| 24 | +import org.slf4j.Logger; | ||
| 25 | +import org.slf4j.LoggerFactory; | ||
| 26 | +import org.springframework.beans.factory.annotation.Autowired; | ||
| 27 | +import org.springframework.stereotype.Service; | ||
| 28 | + | ||
| 29 | +import java.time.*; | ||
| 30 | +import java.util.*; | ||
| 31 | + | ||
| 32 | +@Service | ||
| 33 | +@DS("share") | ||
| 34 | +public class CloudRecordServiceImpl implements ICloudRecordService { | ||
| 35 | + | ||
| 36 | + private final static Logger logger = LoggerFactory.getLogger(CloudRecordServiceImpl.class); | ||
| 37 | + | ||
| 38 | + @Autowired | ||
| 39 | + private CloudRecordServiceMapper cloudRecordServiceMapper; | ||
| 40 | + | ||
| 41 | + @Autowired | ||
| 42 | + private IMediaServerService mediaServerService; | ||
| 43 | + | ||
| 44 | + @Autowired | ||
| 45 | + private IRedisCatchStorage redisCatchStorage; | ||
| 46 | + | ||
| 47 | + @Autowired | ||
| 48 | + private AssistRESTfulUtils assistRESTfulUtils; | ||
| 49 | + | ||
| 50 | + @Autowired | ||
| 51 | + private VideoStreamSessionManager streamSession; | ||
| 52 | + | ||
| 53 | + @Override | ||
| 54 | + public PageInfo<CloudRecordItem> getList(int page, int count, String query, String app, String stream, String startTime, String endTime, List<MediaServerItem> mediaServerItems) { | ||
| 55 | + // 开始时间和结束时间在数据库中都是以秒为单位的 | ||
| 56 | + Long startTimeStamp = null; | ||
| 57 | + Long endTimeStamp = null; | ||
| 58 | + if (startTime != null ) { | ||
| 59 | + if (!DateUtil.verification(startTime, DateUtil.formatter)) { | ||
| 60 | + throw new ControllerException(ErrorCode.ERROR100.getCode(), "开始时间格式错误,正确格式为: " + DateUtil.formatter); | ||
| 61 | + } | ||
| 62 | + startTimeStamp = DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(startTime); | ||
| 63 | + | ||
| 64 | + } | ||
| 65 | + if (endTime != null ) { | ||
| 66 | + if (!DateUtil.verification(endTime, DateUtil.formatter)) { | ||
| 67 | + throw new ControllerException(ErrorCode.ERROR100.getCode(), "结束时间格式错误,正确格式为: " + DateUtil.formatter); | ||
| 68 | + } | ||
| 69 | + endTimeStamp = DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(endTime); | ||
| 70 | + | ||
| 71 | + } | ||
| 72 | + PageHelper.startPage(page, count); | ||
| 73 | + List<CloudRecordItem> all = cloudRecordServiceMapper.getList(query, app, stream, startTimeStamp, endTimeStamp, | ||
| 74 | + null, mediaServerItems); | ||
| 75 | + return new PageInfo<>(all); | ||
| 76 | + } | ||
| 77 | + | ||
| 78 | + @Override | ||
| 79 | + public List<String> getDateList(String app, String stream, int year, int month, List<MediaServerItem> mediaServerItems) { | ||
| 80 | + LocalDate startDate = LocalDate.of(year, month, 1); | ||
| 81 | + LocalDate endDate; | ||
| 82 | + if (month == 12) { | ||
| 83 | + endDate = LocalDate.of(year + 1, 1, 1); | ||
| 84 | + }else { | ||
| 85 | + endDate = LocalDate.of(year, month + 1, 1); | ||
| 86 | + } | ||
| 87 | + long startTimeStamp = startDate.atStartOfDay().toInstant(ZoneOffset.ofHours(8)).getEpochSecond(); | ||
| 88 | + long endTimeStamp = endDate.atStartOfDay().toInstant(ZoneOffset.ofHours(8)).getEpochSecond(); | ||
| 89 | + List<CloudRecordItem> cloudRecordItemList = cloudRecordServiceMapper.getList(null, app, stream, startTimeStamp, | ||
| 90 | + endTimeStamp, null, mediaServerItems); | ||
| 91 | + if (cloudRecordItemList.isEmpty()) { | ||
| 92 | + return new ArrayList<>(); | ||
| 93 | + } | ||
| 94 | + Set<String> resultSet = new HashSet<>(); | ||
| 95 | + cloudRecordItemList.stream().forEach(cloudRecordItem -> { | ||
| 96 | + String date = DateUtil.timestampTo_yyyy_MM_dd(cloudRecordItem.getStartTime()); | ||
| 97 | + resultSet.add(date); | ||
| 98 | + }); | ||
| 99 | + return new ArrayList<>(resultSet); | ||
| 100 | + } | ||
| 101 | + | ||
| 102 | + @Override | ||
| 103 | + public void addRecord(OnRecordMp4HookParam param) { | ||
| 104 | + CloudRecordItem cloudRecordItem = CloudRecordItem.getInstance(param); | ||
| 105 | + StreamAuthorityInfo streamAuthorityInfo = redisCatchStorage.getStreamAuthorityInfo(param.getApp(), param.getStream()); | ||
| 106 | + if (streamAuthorityInfo != null) { | ||
| 107 | + cloudRecordItem.setCallId(streamAuthorityInfo.getCallId()); | ||
| 108 | + } | ||
| 109 | + logger.info("[添加录像记录] {}/{} 文件大小:{}, 时长: {}秒", param.getApp(), param.getStream(), param.getFile_size(),param.getTime_len()); | ||
| 110 | + cloudRecordServiceMapper.add(cloudRecordItem); | ||
| 111 | + } | ||
| 112 | + | ||
| 113 | + @Override | ||
| 114 | + public String addTask(String app, String stream, MediaServerItem mediaServerItem, String startTime, String endTime, | ||
| 115 | + String callId, String remoteHost, boolean filterMediaServer) { | ||
| 116 | + // 参数校验 | ||
| 117 | + assert app != null; | ||
| 118 | + assert stream != null; | ||
| 119 | + if (mediaServerItem.getRecordAssistPort() == 0) { | ||
| 120 | + throw new ControllerException(ErrorCode.ERROR100.getCode(), "为配置Assist服务"); | ||
| 121 | + } | ||
| 122 | + Long startTimeStamp = null; | ||
| 123 | + Long endTimeStamp = null; | ||
| 124 | + if (startTime != null) { | ||
| 125 | + startTimeStamp = DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(startTime); | ||
| 126 | + } | ||
| 127 | + if (endTime != null) { | ||
| 128 | + endTimeStamp = DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(endTime); | ||
| 129 | + } | ||
| 130 | + | ||
| 131 | + List<MediaServerItem> mediaServers = new ArrayList<>(); | ||
| 132 | + mediaServers.add(mediaServerItem); | ||
| 133 | + // 检索相关的录像文件 | ||
| 134 | + List<String> filePathList = cloudRecordServiceMapper.queryRecordFilePathList(app, stream, startTimeStamp, | ||
| 135 | + endTimeStamp, callId, filterMediaServer ? mediaServers : null); | ||
| 136 | + if (filePathList == null || filePathList.isEmpty()) { | ||
| 137 | + throw new ControllerException(ErrorCode.ERROR100.getCode(), "未检索到视频文件"); | ||
| 138 | + } | ||
| 139 | + JSONObject result = assistRESTfulUtils.addTask(mediaServerItem, app, stream, startTime, endTime, callId, filePathList, remoteHost); | ||
| 140 | + if (result.getInteger("code") != 0) { | ||
| 141 | + throw new ControllerException(result.getInteger("code"), result.getString("msg")); | ||
| 142 | + } | ||
| 143 | + return result.getString("data"); | ||
| 144 | + } | ||
| 145 | + | ||
| 146 | + @Override | ||
| 147 | + public JSONArray queryTask(String app, String stream, String callId, String taskId, String mediaServerId, | ||
| 148 | + Boolean isEnd, String scheme) { | ||
| 149 | + MediaServerItem mediaServerItem = null; | ||
| 150 | + if (mediaServerId == null) { | ||
| 151 | + mediaServerItem = mediaServerService.getDefaultMediaServer(); | ||
| 152 | + }else { | ||
| 153 | + mediaServerItem = mediaServerService.getOne(mediaServerId); | ||
| 154 | + } | ||
| 155 | + if (mediaServerItem == null) { | ||
| 156 | + throw new ControllerException(ErrorCode.ERROR100.getCode(), "未找到可用的流媒体"); | ||
| 157 | + } | ||
| 158 | + | ||
| 159 | + JSONObject result = assistRESTfulUtils.queryTaskList(mediaServerItem, app, stream, callId, taskId, isEnd, scheme); | ||
| 160 | + if (result == null || result.getInteger("code") != 0) { | ||
| 161 | + throw new ControllerException(ErrorCode.ERROR100.getCode(), result == null ? "查询任务列表失败" : result.getString("msg")); | ||
| 162 | + } | ||
| 163 | + return result.getJSONArray("data"); | ||
| 164 | + } | ||
| 165 | + | ||
| 166 | + @Override | ||
| 167 | + public int changeCollect(boolean result, String app, String stream, String mediaServerId, String startTime, String endTime, String callId) { | ||
| 168 | + // 开始时间和结束时间在数据库中都是以秒为单位的 | ||
| 169 | + Long startTimeStamp = null; | ||
| 170 | + Long endTimeStamp = null; | ||
| 171 | + if (startTime != null ) { | ||
| 172 | + if (!DateUtil.verification(startTime, DateUtil.formatter)) { | ||
| 173 | + throw new ControllerException(ErrorCode.ERROR100.getCode(), "开始时间格式错误,正确格式为: " + DateUtil.formatter); | ||
| 174 | + } | ||
| 175 | + startTimeStamp = DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(startTime); | ||
| 176 | + | ||
| 177 | + } | ||
| 178 | + if (endTime != null ) { | ||
| 179 | + if (!DateUtil.verification(endTime, DateUtil.formatter)) { | ||
| 180 | + throw new ControllerException(ErrorCode.ERROR100.getCode(), "结束时间格式错误,正确格式为: " + DateUtil.formatter); | ||
| 181 | + } | ||
| 182 | + endTimeStamp = DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(endTime); | ||
| 183 | + | ||
| 184 | + } | ||
| 185 | + | ||
| 186 | + List<MediaServerItem> mediaServerItems; | ||
| 187 | + if (!ObjectUtils.isEmpty(mediaServerId)) { | ||
| 188 | + mediaServerItems = new ArrayList<>(); | ||
| 189 | + MediaServerItem mediaServerItem = mediaServerService.getOne(mediaServerId); | ||
| 190 | + if (mediaServerItem == null) { | ||
| 191 | + throw new ControllerException(ErrorCode.ERROR100.getCode(), "未找到流媒体: " + mediaServerId); | ||
| 192 | + } | ||
| 193 | + mediaServerItems.add(mediaServerItem); | ||
| 194 | + } else { | ||
| 195 | + mediaServerItems = null; | ||
| 196 | + } | ||
| 197 | + | ||
| 198 | + List<CloudRecordItem> all = cloudRecordServiceMapper.getList(null, app, stream, startTimeStamp, endTimeStamp, | ||
| 199 | + callId, mediaServerItems); | ||
| 200 | + if (all.isEmpty()) { | ||
| 201 | + throw new ControllerException(ErrorCode.ERROR100.getCode(), "未找到待收藏的视频"); | ||
| 202 | + } | ||
| 203 | + int limitCount = 50; | ||
| 204 | + int resultCount = 0; | ||
| 205 | + if (all.size() > limitCount) { | ||
| 206 | + for (int i = 0; i < all.size(); i += limitCount) { | ||
| 207 | + int toIndex = i + limitCount; | ||
| 208 | + if (i + limitCount > all.size()) { | ||
| 209 | + toIndex = all.size(); | ||
| 210 | + } | ||
| 211 | + resultCount += cloudRecordServiceMapper.updateCollectList(result, all.subList(i, toIndex)); | ||
| 212 | + | ||
| 213 | + } | ||
| 214 | + }else { | ||
| 215 | + resultCount = cloudRecordServiceMapper.updateCollectList(result, all); | ||
| 216 | + } | ||
| 217 | + return resultCount; | ||
| 218 | + } | ||
| 219 | + | ||
| 220 | + @Override | ||
| 221 | + public int changeCollectById(Integer recordId, boolean result) { | ||
| 222 | + return cloudRecordServiceMapper.changeCollectById(result, recordId); | ||
| 223 | + } | ||
| 224 | + | ||
| 225 | + @Override | ||
| 226 | + public DownloadFileInfo getPlayUrlPath(Integer recordId) { | ||
| 227 | + CloudRecordItem recordItem = cloudRecordServiceMapper.queryOne(recordId); | ||
| 228 | + if (recordItem == null) { | ||
| 229 | + throw new ControllerException(ErrorCode.ERROR400.getCode(), "资源不存在"); | ||
| 230 | + } | ||
| 231 | + String filePath = recordItem.getFilePath(); | ||
| 232 | + MediaServerItem mediaServerItem = mediaServerService.getOne(recordItem.getMediaServerId()); | ||
| 233 | + return CloudRecordUtils.getDownloadFilePath(mediaServerItem, filePath); | ||
| 234 | + } | ||
| 235 | +} |
src/main/java/com/genersoft/iot/vmp/service/impl/DeviceAlarmServiceImpl.java
| 1 | package com.genersoft.iot.vmp.service.impl; | 1 | package com.genersoft.iot.vmp.service.impl; |
| 2 | 2 | ||
| 3 | +import com.baomidou.dynamic.datasource.annotation.DS; | ||
| 3 | import com.genersoft.iot.vmp.gb28181.bean.DeviceAlarm; | 4 | import com.genersoft.iot.vmp.gb28181.bean.DeviceAlarm; |
| 4 | import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem; | 5 | import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem; |
| 5 | import com.genersoft.iot.vmp.service.IDeviceAlarmService; | 6 | import com.genersoft.iot.vmp.service.IDeviceAlarmService; |
| @@ -12,6 +13,7 @@ import org.springframework.stereotype.Service; | @@ -12,6 +13,7 @@ import org.springframework.stereotype.Service; | ||
| 12 | import java.util.List; | 13 | import java.util.List; |
| 13 | 14 | ||
| 14 | @Service | 15 | @Service |
| 16 | +@DS("master") | ||
| 15 | public class DeviceAlarmServiceImpl implements IDeviceAlarmService { | 17 | public class DeviceAlarmServiceImpl implements IDeviceAlarmService { |
| 16 | 18 | ||
| 17 | @Autowired | 19 | @Autowired |
src/main/java/com/genersoft/iot/vmp/service/impl/DeviceChannelServiceImpl.java
| 1 | package com.genersoft.iot.vmp.service.impl; | 1 | package com.genersoft.iot.vmp.service.impl; |
| 2 | 2 | ||
| 3 | +import com.baomidou.dynamic.datasource.annotation.DS; | ||
| 3 | import com.genersoft.iot.vmp.common.InviteInfo; | 4 | import com.genersoft.iot.vmp.common.InviteInfo; |
| 4 | import com.genersoft.iot.vmp.common.InviteSessionType; | 5 | import com.genersoft.iot.vmp.common.InviteSessionType; |
| 5 | import com.genersoft.iot.vmp.gb28181.bean.Device; | 6 | import com.genersoft.iot.vmp.gb28181.bean.Device; |
| @@ -27,6 +28,7 @@ import java.util.concurrent.CopyOnWriteArrayList; | @@ -27,6 +28,7 @@ import java.util.concurrent.CopyOnWriteArrayList; | ||
| 27 | * @author lin | 28 | * @author lin |
| 28 | */ | 29 | */ |
| 29 | @Service | 30 | @Service |
| 31 | +@DS("master") | ||
| 30 | public class DeviceChannelServiceImpl implements IDeviceChannelService { | 32 | public class DeviceChannelServiceImpl implements IDeviceChannelService { |
| 31 | 33 | ||
| 32 | private final static Logger logger = LoggerFactory.getLogger(DeviceChannelServiceImpl.class); | 34 | private final static Logger logger = LoggerFactory.getLogger(DeviceChannelServiceImpl.class); |
| @@ -243,6 +245,10 @@ public class DeviceChannelServiceImpl implements IDeviceChannelService { | @@ -243,6 +245,10 @@ public class DeviceChannelServiceImpl implements IDeviceChannelService { | ||
| 243 | 245 | ||
| 244 | @Override | 246 | @Override |
| 245 | public void batchUpdateChannel(List<DeviceChannel> channels) { | 247 | public void batchUpdateChannel(List<DeviceChannel> channels) { |
| 248 | + String now = DateUtil.getNow(); | ||
| 249 | + for (DeviceChannel channel : channels) { | ||
| 250 | + channel.setUpdateTime(now); | ||
| 251 | + } | ||
| 246 | channelMapper.batchUpdate(channels); | 252 | channelMapper.batchUpdate(channels); |
| 247 | for (DeviceChannel channel : channels) { | 253 | for (DeviceChannel channel : channels) { |
| 248 | if (channel.getParentId() != null) { | 254 | if (channel.getParentId() != null) { |
src/main/java/com/genersoft/iot/vmp/service/impl/DeviceServiceImpl.java
| 1 | package com.genersoft.iot.vmp.service.impl; | 1 | package com.genersoft.iot.vmp.service.impl; |
| 2 | 2 | ||
| 3 | +import com.baomidou.dynamic.datasource.annotation.DS; | ||
| 3 | import com.genersoft.iot.vmp.common.VideoManagerConstants; | 4 | import com.genersoft.iot.vmp.common.VideoManagerConstants; |
| 4 | import com.genersoft.iot.vmp.conf.DynamicTask; | 5 | import com.genersoft.iot.vmp.conf.DynamicTask; |
| 5 | import com.genersoft.iot.vmp.conf.UserSetting; | 6 | import com.genersoft.iot.vmp.conf.UserSetting; |
| @@ -46,6 +47,7 @@ import java.util.concurrent.TimeUnit; | @@ -46,6 +47,7 @@ import java.util.concurrent.TimeUnit; | ||
| 46 | * 设备业务(目录订阅) | 47 | * 设备业务(目录订阅) |
| 47 | */ | 48 | */ |
| 48 | @Service | 49 | @Service |
| 50 | +@DS("master") | ||
| 49 | public class DeviceServiceImpl implements IDeviceService { | 51 | public class DeviceServiceImpl implements IDeviceService { |
| 50 | 52 | ||
| 51 | private final static Logger logger = LoggerFactory.getLogger(DeviceServiceImpl.class); | 53 | private final static Logger logger = LoggerFactory.getLogger(DeviceServiceImpl.class); |
| @@ -162,6 +164,19 @@ public class DeviceServiceImpl implements IDeviceService { | @@ -162,6 +164,19 @@ public class DeviceServiceImpl implements IDeviceService { | ||
| 162 | sync(device); | 164 | sync(device); |
| 163 | // TODO 如果设备下的通道级联到了其他平台,那么需要发送事件或者notify给上级平台 | 165 | // TODO 如果设备下的通道级联到了其他平台,那么需要发送事件或者notify给上级平台 |
| 164 | } | 166 | } |
| 167 | + // 上线添加订阅 | ||
| 168 | + if (device.getSubscribeCycleForCatalog() > 0) { | ||
| 169 | + // 查询在线设备那些开启了订阅,为设备开启定时的目录订阅 | ||
| 170 | + addCatalogSubscribe(device); | ||
| 171 | + } | ||
| 172 | + if (device.getSubscribeCycleForMobilePosition() > 0) { | ||
| 173 | + addMobilePositionSubscribe(device); | ||
| 174 | + } | ||
| 175 | + if (userSetting.getDeviceStatusNotify()) { | ||
| 176 | + // 发送redis消息 | ||
| 177 | + redisCatchStorage.sendDeviceOrChannelStatus(device.getDeviceId(), null, true); | ||
| 178 | + } | ||
| 179 | + | ||
| 165 | }else { | 180 | }else { |
| 166 | if (deviceChannelMapper.queryAllChannels(device.getDeviceId()).size() == 0) { | 181 | if (deviceChannelMapper.queryAllChannels(device.getDeviceId()).size() == 0) { |
| 167 | logger.info("[设备上线]: {},通道数为0,查询通道信息", device.getDeviceId()); | 182 | logger.info("[设备上线]: {},通道数为0,查询通道信息", device.getDeviceId()); |
| @@ -174,22 +189,10 @@ public class DeviceServiceImpl implements IDeviceService { | @@ -174,22 +189,10 @@ public class DeviceServiceImpl implements IDeviceService { | ||
| 174 | 189 | ||
| 175 | } | 190 | } |
| 176 | 191 | ||
| 177 | - // 上线添加订阅 | ||
| 178 | - if (device.getSubscribeCycleForCatalog() > 0) { | ||
| 179 | - // 查询在线设备那些开启了订阅,为设备开启定时的目录订阅 | ||
| 180 | - addCatalogSubscribe(device); | ||
| 181 | - } | ||
| 182 | - if (device.getSubscribeCycleForMobilePosition() > 0) { | ||
| 183 | - addMobilePositionSubscribe(device); | ||
| 184 | - } | ||
| 185 | // 刷新过期任务 | 192 | // 刷新过期任务 |
| 186 | String registerExpireTaskKey = VideoManagerConstants.REGISTER_EXPIRE_TASK_KEY_PREFIX + device.getDeviceId(); | 193 | String registerExpireTaskKey = VideoManagerConstants.REGISTER_EXPIRE_TASK_KEY_PREFIX + device.getDeviceId(); |
| 187 | // 如果第一次注册那么必须在60 * 3时间内收到一个心跳,否则设备离线 | 194 | // 如果第一次注册那么必须在60 * 3时间内收到一个心跳,否则设备离线 |
| 188 | dynamicTask.startDelay(registerExpireTaskKey, ()-> offline(device.getDeviceId(), "首次注册后未能收到心跳"), device.getKeepaliveIntervalTime() * 1000 * 3); | 195 | dynamicTask.startDelay(registerExpireTaskKey, ()-> offline(device.getDeviceId(), "首次注册后未能收到心跳"), device.getKeepaliveIntervalTime() * 1000 * 3); |
| 189 | - if (userSetting.getDeviceStatusNotify()) { | ||
| 190 | - // 发送redis消息 | ||
| 191 | - redisCatchStorage.sendDeviceOrChannelStatus(device.getDeviceId(), null, true); | ||
| 192 | - } | ||
| 193 | 196 | ||
| 194 | // | 197 | // |
| 195 | // try { | 198 | // try { |
| @@ -213,6 +216,13 @@ public class DeviceServiceImpl implements IDeviceService { | @@ -213,6 +216,13 @@ public class DeviceServiceImpl implements IDeviceService { | ||
| 213 | } | 216 | } |
| 214 | String registerExpireTaskKey = VideoManagerConstants.REGISTER_EXPIRE_TASK_KEY_PREFIX + deviceId; | 217 | String registerExpireTaskKey = VideoManagerConstants.REGISTER_EXPIRE_TASK_KEY_PREFIX + deviceId; |
| 215 | dynamicTask.stop(registerExpireTaskKey); | 218 | dynamicTask.stop(registerExpireTaskKey); |
| 219 | + if (device.isOnLine()) { | ||
| 220 | + if (userSetting.getDeviceStatusNotify()) { | ||
| 221 | + // 发送redis消息 | ||
| 222 | + redisCatchStorage.sendDeviceOrChannelStatus(device.getDeviceId(), null, false); | ||
| 223 | + } | ||
| 224 | + } | ||
| 225 | + | ||
| 216 | device.setOnLine(false); | 226 | device.setOnLine(false); |
| 217 | redisCatchStorage.updateDevice(device); | 227 | redisCatchStorage.updateDevice(device); |
| 218 | deviceMapper.update(device); | 228 | deviceMapper.update(device); |
| @@ -224,7 +234,7 @@ public class DeviceServiceImpl implements IDeviceService { | @@ -224,7 +234,7 @@ public class DeviceServiceImpl implements IDeviceService { | ||
| 224 | for (SsrcTransaction ssrcTransaction : ssrcTransactions) { | 234 | for (SsrcTransaction ssrcTransaction : ssrcTransactions) { |
| 225 | mediaServerService.releaseSsrc(ssrcTransaction.getMediaServerId(), ssrcTransaction.getSsrc()); | 235 | mediaServerService.releaseSsrc(ssrcTransaction.getMediaServerId(), ssrcTransaction.getSsrc()); |
| 226 | mediaServerService.closeRTPServer(ssrcTransaction.getMediaServerId(), ssrcTransaction.getStream()); | 236 | mediaServerService.closeRTPServer(ssrcTransaction.getMediaServerId(), ssrcTransaction.getStream()); |
| 227 | - streamSession.remove(deviceId, ssrcTransaction.getChannelId(), ssrcTransaction.getStream()); | 237 | + streamSession.removeByCallId(deviceId, ssrcTransaction.getChannelId(), ssrcTransaction.getCallId()); |
| 228 | } | 238 | } |
| 229 | } | 239 | } |
| 230 | // 移除订阅 | 240 | // 移除订阅 |
| @@ -299,7 +309,7 @@ public class DeviceServiceImpl implements IDeviceService { | @@ -299,7 +309,7 @@ public class DeviceServiceImpl implements IDeviceService { | ||
| 299 | // 设置最小值为30 | 309 | // 设置最小值为30 |
| 300 | int subscribeCycleForCatalog = Math.max(device.getSubscribeCycleForMobilePosition(),30); | 310 | int subscribeCycleForCatalog = Math.max(device.getSubscribeCycleForMobilePosition(),30); |
| 301 | // 刷新订阅 | 311 | // 刷新订阅 |
| 302 | - dynamicTask.startCron(device.getDeviceId() + "mobile_position" , mobilePositionSubscribeTask, (subscribeCycleForCatalog) * 1000); | 312 | + dynamicTask.startCron(device.getDeviceId() + "mobile_position" , mobilePositionSubscribeTask, subscribeCycleForCatalog * 1000); |
| 303 | return true; | 313 | return true; |
| 304 | } | 314 | } |
| 305 | 315 |
src/main/java/com/genersoft/iot/vmp/service/impl/GbStreamServiceImpl.java
| 1 | package com.genersoft.iot.vmp.service.impl; | 1 | package com.genersoft.iot.vmp.service.impl; |
| 2 | 2 | ||
| 3 | +import com.baomidou.dynamic.datasource.annotation.DS; | ||
| 3 | import com.genersoft.iot.vmp.gb28181.bean.*; | 4 | import com.genersoft.iot.vmp.gb28181.bean.*; |
| 4 | import com.genersoft.iot.vmp.gb28181.event.EventPublisher; | 5 | import com.genersoft.iot.vmp.gb28181.event.EventPublisher; |
| 5 | import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent; | 6 | import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent; |
| @@ -25,6 +26,7 @@ import java.util.ArrayList; | @@ -25,6 +26,7 @@ import java.util.ArrayList; | ||
| 25 | import java.util.List; | 26 | import java.util.List; |
| 26 | 27 | ||
| 27 | @Service | 28 | @Service |
| 29 | +@DS("master") | ||
| 28 | public class GbStreamServiceImpl implements IGbStreamService { | 30 | public class GbStreamServiceImpl implements IGbStreamService { |
| 29 | 31 | ||
| 30 | private final static Logger logger = LoggerFactory.getLogger(GbStreamServiceImpl.class); | 32 | private final static Logger logger = LoggerFactory.getLogger(GbStreamServiceImpl.class); |
| @@ -77,8 +79,6 @@ public class GbStreamServiceImpl implements IGbStreamService { | @@ -77,8 +79,6 @@ public class GbStreamServiceImpl implements IGbStreamService { | ||
| 77 | } | 79 | } |
| 78 | try { | 80 | try { |
| 79 | List<DeviceChannel> deviceChannelList = new ArrayList<>(); | 81 | List<DeviceChannel> deviceChannelList = new ArrayList<>(); |
| 80 | - | ||
| 81 | - | ||
| 82 | for (int i = 0; i < gbStreams.size(); i++) { | 82 | for (int i = 0; i < gbStreams.size(); i++) { |
| 83 | GbStream gbStream = gbStreams.get(i); | 83 | GbStream gbStream = gbStreams.get(i); |
| 84 | gbStream.setCatalogId(catalogId); | 84 | gbStream.setCatalogId(catalogId); |
| @@ -251,18 +251,17 @@ public class GbStreamServiceImpl implements IGbStreamService { | @@ -251,18 +251,17 @@ public class GbStreamServiceImpl implements IGbStreamService { | ||
| 251 | return ; | 251 | return ; |
| 252 | } | 252 | } |
| 253 | if (ObjectUtils.isEmpty(catalogId)) { | 253 | if (ObjectUtils.isEmpty(catalogId)) { |
| 254 | - catalogId = platform.getDeviceGBId(); | 254 | + catalogId = null; |
| 255 | } | 255 | } |
| 256 | - if (platformGbStreamMapper.delByPlatformAndCatalogId(platformId, catalogId) > 0) { | ||
| 257 | - List<GbStream> gbStreams = platformGbStreamMapper.queryChannelInParentPlatformAndCatalog(platformId, catalogId); | ||
| 258 | - List<DeviceChannel> deviceChannelList = new ArrayList<>(); | ||
| 259 | - for (GbStream gbStream : gbStreams) { | ||
| 260 | - DeviceChannel deviceChannel = new DeviceChannel(); | ||
| 261 | - deviceChannel.setChannelId(gbStream.getGbId()); | ||
| 262 | - deviceChannelList.add(deviceChannel); | ||
| 263 | - } | ||
| 264 | - eventPublisher.catalogEventPublish(platformId, deviceChannelList, CatalogEvent.DEL); | 256 | + List<GbStream> gbStreams = platformGbStreamMapper.queryChannelInParentPlatformAndCatalog(platformId, catalogId); |
| 257 | + List<DeviceChannel> deviceChannelList = new ArrayList<>(); | ||
| 258 | + for (GbStream gbStream : gbStreams) { | ||
| 259 | + DeviceChannel deviceChannel = new DeviceChannel(); | ||
| 260 | + deviceChannel.setChannelId(gbStream.getGbId()); | ||
| 261 | + deviceChannelList.add(deviceChannel); | ||
| 265 | } | 262 | } |
| 263 | + eventPublisher.catalogEventPublish(platformId, deviceChannelList, CatalogEvent.DEL); | ||
| 264 | + platformGbStreamMapper.delByPlatformAndCatalogId(platformId, catalogId); | ||
| 266 | } | 265 | } |
| 267 | 266 | ||
| 268 | @Override | 267 | @Override |
src/main/java/com/genersoft/iot/vmp/service/impl/InviteStreamServiceImpl.java
| 1 | package com.genersoft.iot.vmp.service.impl; | 1 | package com.genersoft.iot.vmp.service.impl; |
| 2 | 2 | ||
| 3 | import com.alibaba.fastjson2.JSON; | 3 | import com.alibaba.fastjson2.JSON; |
| 4 | +import com.baomidou.dynamic.datasource.annotation.DS; | ||
| 4 | import com.genersoft.iot.vmp.common.InviteInfo; | 5 | import com.genersoft.iot.vmp.common.InviteInfo; |
| 5 | import com.genersoft.iot.vmp.common.InviteSessionStatus; | 6 | import com.genersoft.iot.vmp.common.InviteSessionStatus; |
| 6 | import com.genersoft.iot.vmp.common.InviteSessionType; | 7 | import com.genersoft.iot.vmp.common.InviteSessionType; |
| @@ -20,6 +21,7 @@ import java.util.concurrent.ConcurrentHashMap; | @@ -20,6 +21,7 @@ import java.util.concurrent.ConcurrentHashMap; | ||
| 20 | import java.util.concurrent.CopyOnWriteArrayList; | 21 | import java.util.concurrent.CopyOnWriteArrayList; |
| 21 | 22 | ||
| 22 | @Service | 23 | @Service |
| 24 | +@DS("master") | ||
| 23 | public class InviteStreamServiceImpl implements IInviteStreamService { | 25 | public class InviteStreamServiceImpl implements IInviteStreamService { |
| 24 | 26 | ||
| 25 | private final Logger logger = LoggerFactory.getLogger(InviteStreamServiceImpl.class); | 27 | private final Logger logger = LoggerFactory.getLogger(InviteStreamServiceImpl.class); |
| @@ -116,9 +118,12 @@ public class InviteStreamServiceImpl implements IInviteStreamService { | @@ -116,9 +118,12 @@ public class InviteStreamServiceImpl implements IInviteStreamService { | ||
| 116 | ":" + (stream != null ? stream : "*") | 118 | ":" + (stream != null ? stream : "*") |
| 117 | + ":*"; | 119 | + ":*"; |
| 118 | List<Object> scanResult = RedisUtil.scan(redisTemplate, key); | 120 | List<Object> scanResult = RedisUtil.scan(redisTemplate, key); |
| 119 | - if (scanResult.size() != 1) { | 121 | + if (scanResult.isEmpty()) { |
| 120 | return null; | 122 | return null; |
| 121 | } | 123 | } |
| 124 | + if (scanResult.size() != 1) { | ||
| 125 | + logger.warn("[获取InviteInfo] 发现 key: {}存在多条", key); | ||
| 126 | + } | ||
| 122 | 127 | ||
| 123 | return (InviteInfo) redisTemplate.opsForValue().get(scanResult.get(0)); | 128 | return (InviteInfo) redisTemplate.opsForValue().get(scanResult.get(0)); |
| 124 | } | 129 | } |
src/main/java/com/genersoft/iot/vmp/service/impl/LogServiceImpl.java
| 1 | package com.genersoft.iot.vmp.service.impl; | 1 | package com.genersoft.iot.vmp.service.impl; |
| 2 | 2 | ||
| 3 | +import com.baomidou.dynamic.datasource.annotation.DS; | ||
| 3 | import com.genersoft.iot.vmp.gb28181.bean.DeviceAlarm; | 4 | import com.genersoft.iot.vmp.gb28181.bean.DeviceAlarm; |
| 4 | import com.genersoft.iot.vmp.service.ILogService; | 5 | import com.genersoft.iot.vmp.service.ILogService; |
| 5 | import com.genersoft.iot.vmp.storager.dao.LogMapper; | 6 | import com.genersoft.iot.vmp.storager.dao.LogMapper; |
| @@ -12,6 +13,7 @@ import org.springframework.stereotype.Service; | @@ -12,6 +13,7 @@ import org.springframework.stereotype.Service; | ||
| 12 | import java.util.List; | 13 | import java.util.List; |
| 13 | 14 | ||
| 14 | @Service | 15 | @Service |
| 16 | +@DS("master") | ||
| 15 | public class LogServiceImpl implements ILogService { | 17 | public class LogServiceImpl implements ILogService { |
| 16 | 18 | ||
| 17 | @Autowired | 19 | @Autowired |
src/main/java/com/genersoft/iot/vmp/service/impl/MediaServerServiceImpl.java
| @@ -3,6 +3,7 @@ package com.genersoft.iot.vmp.service.impl; | @@ -3,6 +3,7 @@ package com.genersoft.iot.vmp.service.impl; | ||
| 3 | import com.alibaba.fastjson2.JSON; | 3 | import com.alibaba.fastjson2.JSON; |
| 4 | import com.alibaba.fastjson2.JSONArray; | 4 | import com.alibaba.fastjson2.JSONArray; |
| 5 | import com.alibaba.fastjson2.JSONObject; | 5 | import com.alibaba.fastjson2.JSONObject; |
| 6 | +import com.baomidou.dynamic.datasource.annotation.DS; | ||
| 6 | import com.genersoft.iot.vmp.common.CommonCallback; | 7 | import com.genersoft.iot.vmp.common.CommonCallback; |
| 7 | import com.genersoft.iot.vmp.common.VideoManagerConstants; | 8 | import com.genersoft.iot.vmp.common.VideoManagerConstants; |
| 8 | import com.genersoft.iot.vmp.conf.DynamicTask; | 9 | import com.genersoft.iot.vmp.conf.DynamicTask; |
| @@ -53,6 +54,7 @@ import java.util.concurrent.ExecutionException; | @@ -53,6 +54,7 @@ import java.util.concurrent.ExecutionException; | ||
| 53 | * 媒体服务器节点管理 | 54 | * 媒体服务器节点管理 |
| 54 | */ | 55 | */ |
| 55 | @Service | 56 | @Service |
| 57 | +@DS("master") | ||
| 56 | public class MediaServerServiceImpl implements IMediaServerService { | 58 | public class MediaServerServiceImpl implements IMediaServerService { |
| 57 | 59 | ||
| 58 | private final static Logger logger = LoggerFactory.getLogger(MediaServerServiceImpl.class); | 60 | private final static Logger logger = LoggerFactory.getLogger(MediaServerServiceImpl.class); |
| @@ -165,14 +167,13 @@ public class MediaServerServiceImpl implements IMediaServerService { | @@ -165,14 +167,13 @@ public class MediaServerServiceImpl implements IMediaServerService { | ||
| 165 | if (streamId == null) { | 167 | if (streamId == null) { |
| 166 | streamId = String.format("%08x", Long.parseLong(ssrc)).toUpperCase(); | 168 | streamId = String.format("%08x", Long.parseLong(ssrc)).toUpperCase(); |
| 167 | } | 169 | } |
| 168 | - int ssrcCheckParam = 0; | ||
| 169 | - if (ssrcCheck && tcpMode > 1) { | 170 | + if (ssrcCheck && tcpMode > 0) { |
| 170 | // 目前zlm不支持 tcp模式更新ssrc,暂时关闭ssrc校验 | 171 | // 目前zlm不支持 tcp模式更新ssrc,暂时关闭ssrc校验 |
| 171 | - logger.warn("[openRTPServer] TCP被动/TCP主动收流时,默认关闭ssrc检验"); | 172 | + logger.warn("[openRTPServer] 平台对接时下级可能自定义ssrc,但是tcp模式zlm收流目前无法更新ssrc,可能收流超时,此时请使用udp收流或者关闭ssrc校验"); |
| 172 | } | 173 | } |
| 173 | int rtpServerPort; | 174 | int rtpServerPort; |
| 174 | if (mediaServerItem.isRtpEnable()) { | 175 | if (mediaServerItem.isRtpEnable()) { |
| 175 | - rtpServerPort = zlmServerFactory.createRTPServer(mediaServerItem, streamId, (ssrcCheck && tcpMode == 0) ? Long.parseLong(ssrc) : 0, port, onlyAuto, reUsePort, tcpMode); | 176 | + rtpServerPort = zlmServerFactory.createRTPServer(mediaServerItem, streamId, ssrcCheck ? Long.parseLong(ssrc) : 0, port, onlyAuto, reUsePort, tcpMode); |
| 176 | } else { | 177 | } else { |
| 177 | rtpServerPort = mediaServerItem.getRtpProxyPort(); | 178 | rtpServerPort = mediaServerItem.getRtpProxyPort(); |
| 178 | } | 179 | } |
| @@ -205,7 +206,10 @@ public class MediaServerServiceImpl implements IMediaServerService { | @@ -205,7 +206,10 @@ public class MediaServerServiceImpl implements IMediaServerService { | ||
| 205 | @Override | 206 | @Override |
| 206 | public void closeRTPServer(String mediaServerId, String streamId) { | 207 | public void closeRTPServer(String mediaServerId, String streamId) { |
| 207 | MediaServerItem mediaServerItem = this.getOne(mediaServerId); | 208 | MediaServerItem mediaServerItem = this.getOne(mediaServerId); |
| 208 | - closeRTPServer(mediaServerItem, streamId); | 209 | + if (mediaServerItem.isRtpEnable()) { |
| 210 | + closeRTPServer(mediaServerItem, streamId); | ||
| 211 | + } | ||
| 212 | + zlmresTfulUtils.closeStreams(mediaServerItem, "rtp", streamId); | ||
| 209 | } | 213 | } |
| 210 | 214 | ||
| 211 | @Override | 215 | @Override |
| @@ -313,7 +317,6 @@ public class MediaServerServiceImpl implements IMediaServerService { | @@ -313,7 +317,6 @@ public class MediaServerServiceImpl implements IMediaServerService { | ||
| 313 | 317 | ||
| 314 | @Override | 318 | @Override |
| 315 | public MediaServerItem getDefaultMediaServer() { | 319 | public MediaServerItem getDefaultMediaServer() { |
| 316 | - | ||
| 317 | return mediaServerMapper.queryDefault(); | 320 | return mediaServerMapper.queryDefault(); |
| 318 | } | 321 | } |
| 319 | 322 | ||
| @@ -428,17 +431,6 @@ public class MediaServerServiceImpl implements IMediaServerService { | @@ -428,17 +431,6 @@ public class MediaServerServiceImpl implements IMediaServerService { | ||
| 428 | 431 | ||
| 429 | 432 | ||
| 430 | if (serverItem.isAutoConfig()) { | 433 | if (serverItem.isAutoConfig()) { |
| 431 | - // 查看assist服务的录像路径配置 | ||
| 432 | - if (serverItem.getRecordAssistPort() > 0 && userSetting.getRecordPath() == null) { | ||
| 433 | - JSONObject info = assistRESTfulUtils.getInfo(serverItem, null); | ||
| 434 | - if (info != null && info.getInteger("code") != null && info.getInteger("code") == 0 ) { | ||
| 435 | - JSONObject dataJson = info.getJSONObject("data"); | ||
| 436 | - if (dataJson != null) { | ||
| 437 | - String recordPath = dataJson.getString("record"); | ||
| 438 | - userSetting.setRecordPath(recordPath); | ||
| 439 | - } | ||
| 440 | - } | ||
| 441 | - } | ||
| 442 | setZLMConfig(serverItem, "0".equals(zlmServerConfig.getHookEnable())); | 434 | setZLMConfig(serverItem, "0".equals(zlmServerConfig.getHookEnable())); |
| 443 | } | 435 | } |
| 444 | final String zlmKeepaliveKey = zlmKeepaliveKeyPrefix + serverItem.getId(); | 436 | final String zlmKeepaliveKey = zlmKeepaliveKeyPrefix + serverItem.getId(); |
| @@ -573,34 +565,30 @@ public class MediaServerServiceImpl implements IMediaServerService { | @@ -573,34 +565,30 @@ public class MediaServerServiceImpl implements IMediaServerService { | ||
| 573 | logger.info("[ZLM] 正在设置 :{} -> {}:{}", | 565 | logger.info("[ZLM] 正在设置 :{} -> {}:{}", |
| 574 | mediaServerItem.getId(), mediaServerItem.getIp(), mediaServerItem.getHttpPort()); | 566 | mediaServerItem.getId(), mediaServerItem.getIp(), mediaServerItem.getHttpPort()); |
| 575 | String protocol = sslEnabled ? "https" : "http"; | 567 | String protocol = sslEnabled ? "https" : "http"; |
| 576 | - String hookPrex = String.format("%s://%s:%s/index/hook", protocol, mediaServerItem.getHookIp(), serverPort); | 568 | + String hookPrefix = String.format("%s://%s:%s/index/hook", protocol, mediaServerItem.getHookIp(), serverPort); |
| 577 | 569 | ||
| 578 | Map<String, Object> param = new HashMap<>(); | 570 | Map<String, Object> param = new HashMap<>(); |
| 579 | param.put("api.secret",mediaServerItem.getSecret()); // -profile:v Baseline | 571 | param.put("api.secret",mediaServerItem.getSecret()); // -profile:v Baseline |
| 580 | if (mediaServerItem.getRtspPort() != 0) { | 572 | if (mediaServerItem.getRtspPort() != 0) { |
| 581 | - param.put("ffmpeg.snap", "%s -rtsp_transport tcp -i %s -y -f mjpeg -t 0.001 %s"); | 573 | + param.put("ffmpeg.snap", "%s -rtsp_transport tcp -i %s -y -f mjpeg -frames:v 1 %s"); |
| 582 | } | 574 | } |
| 583 | param.put("hook.enable","1"); | 575 | param.put("hook.enable","1"); |
| 584 | param.put("hook.on_flow_report",""); | 576 | param.put("hook.on_flow_report",""); |
| 585 | - param.put("hook.on_play",String.format("%s/on_play", hookPrex)); | 577 | + param.put("hook.on_play",String.format("%s/on_play", hookPrefix)); |
| 586 | param.put("hook.on_http_access",""); | 578 | param.put("hook.on_http_access",""); |
| 587 | - param.put("hook.on_publish", String.format("%s/on_publish", hookPrex)); | 579 | + param.put("hook.on_publish", String.format("%s/on_publish", hookPrefix)); |
| 588 | param.put("hook.on_record_ts",""); | 580 | param.put("hook.on_record_ts",""); |
| 589 | param.put("hook.on_rtsp_auth",""); | 581 | param.put("hook.on_rtsp_auth",""); |
| 590 | param.put("hook.on_rtsp_realm",""); | 582 | param.put("hook.on_rtsp_realm",""); |
| 591 | - param.put("hook.on_server_started",String.format("%s/on_server_started", hookPrex)); | 583 | + param.put("hook.on_server_started",String.format("%s/on_server_started", hookPrefix)); |
| 592 | param.put("hook.on_shell_login",""); | 584 | param.put("hook.on_shell_login",""); |
| 593 | - param.put("hook.on_stream_changed",String.format("%s/on_stream_changed", hookPrex)); | ||
| 594 | - param.put("hook.on_stream_none_reader",String.format("%s/on_stream_none_reader", hookPrex)); | ||
| 595 | - param.put("hook.on_stream_not_found",String.format("%s/on_stream_not_found", hookPrex)); | ||
| 596 | - param.put("hook.on_server_keepalive",String.format("%s/on_server_keepalive", hookPrex)); | ||
| 597 | - param.put("hook.on_send_rtp_stopped",String.format("%s/on_send_rtp_stopped", hookPrex)); | ||
| 598 | - param.put("hook.on_rtp_server_timeout",String.format("%s/on_rtp_server_timeout", hookPrex)); | ||
| 599 | - if (mediaServerItem.getRecordAssistPort() > 0) { | ||
| 600 | - param.put("hook.on_record_mp4",String.format("http://127.0.0.1:%s/api/record/on_record_mp4", mediaServerItem.getRecordAssistPort())); | ||
| 601 | - }else { | ||
| 602 | - param.put("hook.on_record_mp4",""); | ||
| 603 | - } | 585 | + param.put("hook.on_stream_changed",String.format("%s/on_stream_changed", hookPrefix)); |
| 586 | + param.put("hook.on_stream_none_reader",String.format("%s/on_stream_none_reader", hookPrefix)); | ||
| 587 | + param.put("hook.on_stream_not_found",String.format("%s/on_stream_not_found", hookPrefix)); | ||
| 588 | + param.put("hook.on_server_keepalive",String.format("%s/on_server_keepalive", hookPrefix)); | ||
| 589 | + param.put("hook.on_send_rtp_stopped",String.format("%s/on_send_rtp_stopped", hookPrefix)); | ||
| 590 | + param.put("hook.on_rtp_server_timeout",String.format("%s/on_rtp_server_timeout", hookPrefix)); | ||
| 591 | + param.put("hook.on_record_mp4",String.format("%s/on_record_mp4", hookPrefix)); | ||
| 604 | param.put("hook.timeoutSec","20"); | 592 | param.put("hook.timeoutSec","20"); |
| 605 | // 推流断开后可以在超时时间内重新连接上继续推流,这样播放器会接着播放。 | 593 | // 推流断开后可以在超时时间内重新连接上继续推流,这样播放器会接着播放。 |
| 606 | // 置0关闭此特性(推流断开会导致立即断开播放器) | 594 | // 置0关闭此特性(推流断开会导致立即断开播放器) |
| @@ -609,15 +597,14 @@ public class MediaServerServiceImpl implements IMediaServerService { | @@ -609,15 +597,14 @@ public class MediaServerServiceImpl implements IMediaServerService { | ||
| 609 | param.put("protocol.continue_push_ms", "3000" ); | 597 | param.put("protocol.continue_push_ms", "3000" ); |
| 610 | // 最多等待未初始化的Track时间,单位毫秒,超时之后会忽略未初始化的Track, 设置此选项优化那些音频错误的不规范流, | 598 | // 最多等待未初始化的Track时间,单位毫秒,超时之后会忽略未初始化的Track, 设置此选项优化那些音频错误的不规范流, |
| 611 | // 等zlm支持给每个rtpServer设置关闭音频的时候可以不设置此选项 | 599 | // 等zlm支持给每个rtpServer设置关闭音频的时候可以不设置此选项 |
| 612 | -// param.put("general.wait_track_ready_ms", "3000" ); | ||
| 613 | if (mediaServerItem.isRtpEnable() && !ObjectUtils.isEmpty(mediaServerItem.getRtpPortRange())) { | 600 | if (mediaServerItem.isRtpEnable() && !ObjectUtils.isEmpty(mediaServerItem.getRtpPortRange())) { |
| 614 | param.put("rtp_proxy.port_range", mediaServerItem.getRtpPortRange().replace(",", "-")); | 601 | param.put("rtp_proxy.port_range", mediaServerItem.getRtpPortRange().replace(",", "-")); |
| 615 | } | 602 | } |
| 616 | 603 | ||
| 617 | - if (userSetting.getRecordPath() != null) { | ||
| 618 | - File recordPathFile = new File(userSetting.getRecordPath()); | ||
| 619 | - File mp4SavePathFile = recordPathFile.getParentFile().getAbsoluteFile(); | ||
| 620 | - param.put("protocol.mp4_save_path", mp4SavePathFile.getAbsoluteFile()); | 604 | + if (!ObjectUtils.isEmpty(mediaServerItem.getRecordPath())) { |
| 605 | + File recordPathFile = new File(mediaServerItem.getRecordPath()); | ||
| 606 | + param.put("protocol.mp4_save_path", recordPathFile.getParentFile().getPath()); | ||
| 607 | + param.put("protocol.downloadRoot", recordPathFile.getParentFile().getPath()); | ||
| 621 | param.put("record.appName", recordPathFile.getName()); | 608 | param.put("record.appName", recordPathFile.getName()); |
| 622 | } | 609 | } |
| 623 | 610 | ||
| @@ -722,6 +709,7 @@ public class MediaServerServiceImpl implements IMediaServerService { | @@ -722,6 +709,7 @@ public class MediaServerServiceImpl implements IMediaServerService { | ||
| 722 | ssrcFactory.initMediaServerSSRC(mediaServerItem.getId(), null); | 709 | ssrcFactory.initMediaServerSSRC(mediaServerItem.getId(), null); |
| 723 | String key = VideoManagerConstants.MEDIA_SERVER_PREFIX + userSetting.getServerId() + "_" + mediaServerItem.getId(); | 710 | String key = VideoManagerConstants.MEDIA_SERVER_PREFIX + userSetting.getServerId() + "_" + mediaServerItem.getId(); |
| 724 | redisTemplate.opsForValue().set(key, mediaServerItem); | 711 | redisTemplate.opsForValue().set(key, mediaServerItem); |
| 712 | + resetOnlineServerItem(mediaServerItem); | ||
| 725 | clearRTPServer(mediaServerItem); | 713 | clearRTPServer(mediaServerItem); |
| 726 | } | 714 | } |
| 727 | final String zlmKeepaliveKey = zlmKeepaliveKeyPrefix + mediaServerItem.getId(); | 715 | final String zlmKeepaliveKey = zlmKeepaliveKeyPrefix + mediaServerItem.getId(); |
| @@ -750,15 +738,6 @@ public class MediaServerServiceImpl implements IMediaServerService { | @@ -750,15 +738,6 @@ public class MediaServerServiceImpl implements IMediaServerService { | ||
| 750 | } | 738 | } |
| 751 | 739 | ||
| 752 | @Override | 740 | @Override |
| 753 | - public boolean checkRtpServer(MediaServerItem mediaServerItem, String app, String stream) { | ||
| 754 | - JSONObject rtpInfo = zlmresTfulUtils.getRtpInfo(mediaServerItem, stream); | ||
| 755 | - if(rtpInfo.getInteger("code") == 0){ | ||
| 756 | - return rtpInfo.getBoolean("exist"); | ||
| 757 | - } | ||
| 758 | - return false; | ||
| 759 | - } | ||
| 760 | - | ||
| 761 | - @Override | ||
| 762 | public MediaServerLoad getLoad(MediaServerItem mediaServerItem) { | 741 | public MediaServerLoad getLoad(MediaServerItem mediaServerItem) { |
| 763 | MediaServerLoad result = new MediaServerLoad(); | 742 | MediaServerLoad result = new MediaServerLoad(); |
| 764 | result.setId(mediaServerItem.getId()); | 743 | result.setId(mediaServerItem.getId()); |
| @@ -771,88 +750,7 @@ public class MediaServerServiceImpl implements IMediaServerService { | @@ -771,88 +750,7 @@ public class MediaServerServiceImpl implements IMediaServerService { | ||
| 771 | } | 750 | } |
| 772 | 751 | ||
| 773 | @Override | 752 | @Override |
| 774 | - public List<RecordFile> getRecords(String app, String stream, String startTime, String endTime, List<MediaServerItem> mediaServerItems) { | ||
| 775 | - Assert.notNull(app, "app不存在"); | ||
| 776 | - Assert.notNull(stream, "stream不存在"); | ||
| 777 | - Assert.notNull(startTime, "startTime不存在"); | ||
| 778 | - Assert.notNull(endTime, "endTime不存在"); | ||
| 779 | - Assert.notEmpty(mediaServerItems, "流媒体列表为空"); | ||
| 780 | - | ||
| 781 | - CompletableFuture[] completableFutures = new CompletableFuture[mediaServerItems.size()]; | ||
| 782 | - for (int i = 0; i < mediaServerItems.size(); i++) { | ||
| 783 | - completableFutures[i] = getRecordFilesForOne(app, stream, startTime, endTime, mediaServerItems.get(i)); | ||
| 784 | - } | ||
| 785 | - List<RecordFile> result = new ArrayList<>(); | ||
| 786 | - for (int i = 0; i < completableFutures.length; i++) { | ||
| 787 | - try { | ||
| 788 | - List<RecordFile> list = (List<RecordFile>) completableFutures[i].get(); | ||
| 789 | - if (!list.isEmpty()) { | ||
| 790 | - for (int g = 0; g < list.size(); g++) { | ||
| 791 | - list.get(g).setMediaServerId(mediaServerItems.get(i).getId()); | ||
| 792 | - } | ||
| 793 | - result.addAll(list); | ||
| 794 | - } | ||
| 795 | - } catch (InterruptedException e) { | ||
| 796 | - throw new RuntimeException(e); | ||
| 797 | - } catch (ExecutionException e) { | ||
| 798 | - throw new RuntimeException(e); | ||
| 799 | - } | ||
| 800 | - } | ||
| 801 | - Comparator<RecordFile> comparator = Comparator.comparing(RecordFile::getFileName); | ||
| 802 | - result.sort(comparator); | ||
| 803 | - return result; | ||
| 804 | - } | ||
| 805 | - | ||
| 806 | - @Override | ||
| 807 | - public List<String> getRecordDates(String app, String stream, int year, int month, List<MediaServerItem> mediaServerItems) { | ||
| 808 | - Assert.notNull(app, "app不存在"); | ||
| 809 | - Assert.notNull(stream, "stream不存在"); | ||
| 810 | - Assert.notEmpty(mediaServerItems, "流媒体列表为空"); | ||
| 811 | - CompletableFuture[] completableFutures = new CompletableFuture[mediaServerItems.size()]; | ||
| 812 | - | ||
| 813 | - for (int i = 0; i < mediaServerItems.size(); i++) { | ||
| 814 | - completableFutures[i] = getRecordDatesForOne(app, stream, year, month, mediaServerItems.get(i)); | ||
| 815 | - } | ||
| 816 | - List<String> result = new ArrayList<>(); | ||
| 817 | - CompletableFuture.allOf(completableFutures).join(); | ||
| 818 | - for (CompletableFuture completableFuture : completableFutures) { | ||
| 819 | - try { | ||
| 820 | - List<String> list = (List<String>) completableFuture.get(); | ||
| 821 | - result.addAll(list); | ||
| 822 | - } catch (InterruptedException e) { | ||
| 823 | - throw new RuntimeException(e); | ||
| 824 | - } catch (ExecutionException e) { | ||
| 825 | - throw new RuntimeException(e); | ||
| 826 | - } | ||
| 827 | - } | ||
| 828 | - Collections.sort(result); | ||
| 829 | - return result; | ||
| 830 | - } | ||
| 831 | - | ||
| 832 | - @Async | ||
| 833 | - public CompletableFuture<List<String>> getRecordDatesForOne(String app, String stream, int year, int month, MediaServerItem mediaServerItem) { | ||
| 834 | - JSONObject fileListJson = assistRESTfulUtils.getDateList(mediaServerItem, app, stream, year, month); | ||
| 835 | - if (fileListJson != null && !fileListJson.isEmpty()) { | ||
| 836 | - if (fileListJson.getString("code") != null && fileListJson.getInteger("code") == 0) { | ||
| 837 | - JSONArray data = fileListJson.getJSONArray("data"); | ||
| 838 | - return CompletableFuture.completedFuture(data.toJavaList(String.class)); | ||
| 839 | - } | ||
| 840 | - } | ||
| 841 | - return CompletableFuture.completedFuture(new ArrayList<>()); | ||
| 842 | - } | ||
| 843 | - | ||
| 844 | - @Async | ||
| 845 | - public CompletableFuture<List<RecordFile>> getRecordFilesForOne(String app, String stream, String startTime, String endTime, MediaServerItem mediaServerItem) { | ||
| 846 | - JSONObject fileListJson = assistRESTfulUtils.getFileList(mediaServerItem, 1, 100000000, app, stream, startTime, endTime); | ||
| 847 | - if (fileListJson != null && !fileListJson.isEmpty()) { | ||
| 848 | - if (fileListJson.getString("code") != null && fileListJson.getInteger("code") == 0) { | ||
| 849 | - JSONObject data = fileListJson.getJSONObject("data"); | ||
| 850 | - JSONArray list = data.getJSONArray("list"); | ||
| 851 | - if (list != null) { | ||
| 852 | - return CompletableFuture.completedFuture(list.toJavaList(RecordFile.class)); | ||
| 853 | - } | ||
| 854 | - } | ||
| 855 | - } | ||
| 856 | - return CompletableFuture.completedFuture(new ArrayList<>()); | 753 | + public List<MediaServerItem> getAllWithAssistPort() { |
| 754 | + return mediaServerMapper.queryAllWithAssistPort(); | ||
| 857 | } | 755 | } |
| 858 | } | 756 | } |
src/main/java/com/genersoft/iot/vmp/service/impl/MediaServiceImpl.java
| @@ -64,7 +64,7 @@ public class MediaServiceImpl implements IMediaService { | @@ -64,7 +64,7 @@ public class MediaServiceImpl implements IMediaService { | ||
| 64 | if (data == null) { | 64 | if (data == null) { |
| 65 | return null; | 65 | return null; |
| 66 | } | 66 | } |
| 67 | - JSONObject mediaJSON = JSON.parseObject(JSON.toJSONString(data.get(0)), JSONObject.class); | 67 | + JSONObject mediaJSON = data.getJSONObject(0); |
| 68 | JSONArray tracks = mediaJSON.getJSONArray("tracks"); | 68 | JSONArray tracks = mediaJSON.getJSONArray("tracks"); |
| 69 | if (authority) { | 69 | if (authority) { |
| 70 | streamInfo = getStreamInfoByAppAndStream(mediaInfo, app, stream, tracks, addr, calld, true); | 70 | streamInfo = getStreamInfoByAppAndStream(mediaInfo, app, stream, tracks, addr, calld, true); |
src/main/java/com/genersoft/iot/vmp/service/impl/PlatformChannelServiceImpl.java
| 1 | package com.genersoft.iot.vmp.service.impl; | 1 | package com.genersoft.iot.vmp.service.impl; |
| 2 | 2 | ||
| 3 | +import com.baomidou.dynamic.datasource.annotation.DS; | ||
| 3 | import com.genersoft.iot.vmp.gb28181.bean.*; | 4 | import com.genersoft.iot.vmp.gb28181.bean.*; |
| 4 | import com.genersoft.iot.vmp.gb28181.event.EventPublisher; | 5 | import com.genersoft.iot.vmp.gb28181.event.EventPublisher; |
| 5 | import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent; | 6 | import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent; |
| @@ -27,6 +28,7 @@ import java.util.Map; | @@ -27,6 +28,7 @@ import java.util.Map; | ||
| 27 | * @author lin | 28 | * @author lin |
| 28 | */ | 29 | */ |
| 29 | @Service | 30 | @Service |
| 31 | +@DS("master") | ||
| 30 | public class PlatformChannelServiceImpl implements IPlatformChannelService { | 32 | public class PlatformChannelServiceImpl implements IPlatformChannelService { |
| 31 | 33 | ||
| 32 | private final static Logger logger = LoggerFactory.getLogger(PlatformChannelServiceImpl.class); | 34 | private final static Logger logger = LoggerFactory.getLogger(PlatformChannelServiceImpl.class); |
| @@ -165,10 +167,9 @@ public class PlatformChannelServiceImpl implements IPlatformChannelService { | @@ -165,10 +167,9 @@ public class PlatformChannelServiceImpl implements IPlatformChannelService { | ||
| 165 | catalogId = null; | 167 | catalogId = null; |
| 166 | } | 168 | } |
| 167 | 169 | ||
| 168 | - if ((result = platformChannelMapper.delChannelForGBByCatalogId(platformId, catalogId)) > 0) { | ||
| 169 | - List<DeviceChannel> deviceChannels = platformChannelMapper.queryAllChannelInCatalog(platformId, catalogId); | ||
| 170 | - eventPublisher.catalogEventPublish(platformId, deviceChannels, CatalogEvent.DEL); | ||
| 171 | - } | ||
| 172 | - return result; | 170 | + List<DeviceChannel> deviceChannels = platformChannelMapper.queryAllChannelInCatalog(platformId, catalogId); |
| 171 | + eventPublisher.catalogEventPublish(platformId, deviceChannels, CatalogEvent.DEL); | ||
| 172 | + | ||
| 173 | + return platformChannelMapper.delChannelForGBByCatalogId(platformId, catalogId); | ||
| 173 | } | 174 | } |
| 174 | } | 175 | } |
src/main/java/com/genersoft/iot/vmp/service/impl/PlatformServiceImpl.java
| @@ -2,6 +2,7 @@ package com.genersoft.iot.vmp.service.impl; | @@ -2,6 +2,7 @@ package com.genersoft.iot.vmp.service.impl; | ||
| 2 | 2 | ||
| 3 | import com.genersoft.iot.vmp.common.InviteInfo; | 3 | import com.genersoft.iot.vmp.common.InviteInfo; |
| 4 | import com.genersoft.iot.vmp.common.InviteSessionType; | 4 | import com.genersoft.iot.vmp.common.InviteSessionType; |
| 5 | +import com.baomidou.dynamic.datasource.annotation.DS; | ||
| 5 | import com.genersoft.iot.vmp.conf.DynamicTask; | 6 | import com.genersoft.iot.vmp.conf.DynamicTask; |
| 6 | import com.genersoft.iot.vmp.conf.UserSetting; | 7 | import com.genersoft.iot.vmp.conf.UserSetting; |
| 7 | import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException; | 8 | import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException; |
| @@ -55,6 +56,7 @@ import java.util.*; | @@ -55,6 +56,7 @@ import java.util.*; | ||
| 55 | * @author lin | 56 | * @author lin |
| 56 | */ | 57 | */ |
| 57 | @Service | 58 | @Service |
| 59 | +@DS("master") | ||
| 58 | public class PlatformServiceImpl implements IPlatformService { | 60 | public class PlatformServiceImpl implements IPlatformService { |
| 59 | 61 | ||
| 60 | private final static String REGISTER_KEY_PREFIX = "platform_register_"; | 62 | private final static String REGISTER_KEY_PREFIX = "platform_register_"; |
| @@ -169,7 +171,7 @@ public class PlatformServiceImpl implements IPlatformService { | @@ -169,7 +171,7 @@ public class PlatformServiceImpl implements IPlatformService { | ||
| 169 | dynamicTask.stop(registerTaskKey); | 171 | dynamicTask.stop(registerTaskKey); |
| 170 | // 注销旧的 | 172 | // 注销旧的 |
| 171 | try { | 173 | try { |
| 172 | - if (parentPlatformOld.isStatus()) { | 174 | + if (parentPlatformOld.isStatus() && parentPlatformCatchOld != null) { |
| 173 | logger.info("保存平台{}时发现旧平台在线,发送注销命令", parentPlatformOld.getServerGBId()); | 175 | logger.info("保存平台{}时发现旧平台在线,发送注销命令", parentPlatformOld.getServerGBId()); |
| 174 | commanderForPlatform.unregister(parentPlatformOld, parentPlatformCatchOld.getSipTransactionInfo(), null, eventResult -> { | 176 | commanderForPlatform.unregister(parentPlatformOld, parentPlatformCatchOld.getSipTransactionInfo(), null, eventResult -> { |
| 175 | logger.info("[国标级联] 注销成功, 平台:{}", parentPlatformOld.getServerGBId()); | 177 | logger.info("[国标级联] 注销成功, 平台:{}", parentPlatformOld.getServerGBId()); |
| @@ -286,6 +288,7 @@ public class PlatformServiceImpl implements IPlatformService { | @@ -286,6 +288,7 @@ public class PlatformServiceImpl implements IPlatformService { | ||
| 286 | } | 288 | } |
| 287 | if (parentPlatform.isAutoPushChannel()) { | 289 | if (parentPlatform.isAutoPushChannel()) { |
| 288 | if (subscribeHolder.getCatalogSubscribe(parentPlatform.getServerGBId()) == null) { | 290 | if (subscribeHolder.getCatalogSubscribe(parentPlatform.getServerGBId()) == null) { |
| 291 | + logger.info("[国标级联]:{}, 添加自动通道推送模拟订阅信息", parentPlatform.getServerGBId()); | ||
| 289 | addSimulatedSubscribeInfo(parentPlatform); | 292 | addSimulatedSubscribeInfo(parentPlatform); |
| 290 | } | 293 | } |
| 291 | }else { | 294 | }else { |
| @@ -363,9 +366,16 @@ public class PlatformServiceImpl implements IPlatformService { | @@ -363,9 +366,16 @@ public class PlatformServiceImpl implements IPlatformService { | ||
| 363 | // 清除心跳任务 | 366 | // 清除心跳任务 |
| 364 | dynamicTask.stop(keepaliveTaskKey); | 367 | dynamicTask.stop(keepaliveTaskKey); |
| 365 | } | 368 | } |
| 366 | - // 停止目录订阅回复 | ||
| 367 | - logger.info("[平台离线] {}, 停止订阅回复", parentPlatform.getServerGBId()); | ||
| 368 | - subscribeHolder.removeAllSubscribe(parentPlatform.getServerGBId()); | 369 | + // 停止订阅回复 |
| 370 | + SubscribeInfo catalogSubscribe = subscribeHolder.getCatalogSubscribe(parentPlatform.getServerGBId()); | ||
| 371 | + if (catalogSubscribe != null) { | ||
| 372 | + if (catalogSubscribe.getExpires() > 0) { | ||
| 373 | + logger.info("[平台离线] {}, 停止目录订阅回复", parentPlatform.getServerGBId()); | ||
| 374 | + subscribeHolder.removeCatalogSubscribe(parentPlatform.getServerGBId()); | ||
| 375 | + } | ||
| 376 | + } | ||
| 377 | + logger.info("[平台离线] {}, 停止移动位置订阅回复", parentPlatform.getServerGBId()); | ||
| 378 | + subscribeHolder.removeMobilePositionSubscribe(parentPlatform.getServerGBId()); | ||
| 369 | // 发起定时自动重新注册 | 379 | // 发起定时自动重新注册 |
| 370 | if (!stopRegister) { | 380 | if (!stopRegister) { |
| 371 | // 设置为60秒自动尝试重新注册 | 381 | // 设置为60秒自动尝试重新注册 |
src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java
| 1 | package com.genersoft.iot.vmp.service.impl; | 1 | package com.genersoft.iot.vmp.service.impl; |
| 2 | 2 | ||
| 3 | +import com.alibaba.fastjson2.JSONArray; | ||
| 3 | import com.alibaba.fastjson2.JSONObject; | 4 | import com.alibaba.fastjson2.JSONObject; |
| 5 | +import com.baomidou.dynamic.datasource.annotation.DS; | ||
| 4 | import com.genersoft.iot.vmp.common.InviteInfo; | 6 | import com.genersoft.iot.vmp.common.InviteInfo; |
| 5 | import com.genersoft.iot.vmp.common.InviteSessionStatus; | 7 | import com.genersoft.iot.vmp.common.InviteSessionStatus; |
| 6 | import com.genersoft.iot.vmp.common.InviteSessionType; | 8 | import com.genersoft.iot.vmp.common.InviteSessionType; |
| @@ -23,7 +25,12 @@ import com.genersoft.iot.vmp.media.zlm.*; | @@ -23,7 +25,12 @@ import com.genersoft.iot.vmp.media.zlm.*; | ||
| 23 | import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeFactory; | 25 | import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeFactory; |
| 24 | import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForStreamChange; | 26 | import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForStreamChange; |
| 25 | import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; | 27 | import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; |
| 28 | +import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils; | ||
| 29 | +import com.genersoft.iot.vmp.media.zlm.ZLMServerFactory; | ||
| 30 | +import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe; | ||
| 31 | +import com.genersoft.iot.vmp.media.zlm.dto.*; | ||
| 26 | import com.genersoft.iot.vmp.media.zlm.dto.hook.HookParam; | 32 | import com.genersoft.iot.vmp.media.zlm.dto.hook.HookParam; |
| 33 | +import com.genersoft.iot.vmp.media.zlm.dto.hook.OnRecordMp4HookParam; | ||
| 27 | import com.genersoft.iot.vmp.media.zlm.dto.hook.OnStreamChangedHookParam; | 34 | import com.genersoft.iot.vmp.media.zlm.dto.hook.OnStreamChangedHookParam; |
| 28 | import com.genersoft.iot.vmp.service.*; | 35 | import com.genersoft.iot.vmp.service.*; |
| 29 | import com.genersoft.iot.vmp.service.bean.ErrorCallback; | 36 | import com.genersoft.iot.vmp.service.bean.ErrorCallback; |
| @@ -31,8 +38,11 @@ import com.genersoft.iot.vmp.service.bean.InviteErrorCode; | @@ -31,8 +38,11 @@ import com.genersoft.iot.vmp.service.bean.InviteErrorCode; | ||
| 31 | import com.genersoft.iot.vmp.service.bean.RequestPushStreamMsg; | 38 | import com.genersoft.iot.vmp.service.bean.RequestPushStreamMsg; |
| 32 | import com.genersoft.iot.vmp.service.bean.SSRCInfo; | 39 | import com.genersoft.iot.vmp.service.bean.SSRCInfo; |
| 33 | import com.genersoft.iot.vmp.service.redisMsg.RedisGbPlayMsgListener; | 40 | import com.genersoft.iot.vmp.service.redisMsg.RedisGbPlayMsgListener; |
| 41 | +import com.genersoft.iot.vmp.service.bean.*; | ||
| 34 | import com.genersoft.iot.vmp.storager.IRedisCatchStorage; | 42 | import com.genersoft.iot.vmp.storager.IRedisCatchStorage; |
| 35 | import com.genersoft.iot.vmp.storager.IVideoManagerStorage; | 43 | import com.genersoft.iot.vmp.storager.IVideoManagerStorage; |
| 44 | +import com.genersoft.iot.vmp.storager.dao.CloudRecordServiceMapper; | ||
| 45 | +import com.genersoft.iot.vmp.utils.CloudRecordUtils; | ||
| 36 | import com.genersoft.iot.vmp.utils.DateUtil; | 46 | import com.genersoft.iot.vmp.utils.DateUtil; |
| 37 | import com.genersoft.iot.vmp.vmanager.bean.AudioBroadcastResult; | 47 | import com.genersoft.iot.vmp.vmanager.bean.AudioBroadcastResult; |
| 38 | import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; | 48 | import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; |
| @@ -61,6 +71,7 @@ import java.util.*; | @@ -61,6 +71,7 @@ import java.util.*; | ||
| 61 | 71 | ||
| 62 | @SuppressWarnings(value = {"rawtypes", "unchecked"}) | 72 | @SuppressWarnings(value = {"rawtypes", "unchecked"}) |
| 63 | @Service | 73 | @Service |
| 74 | +@DS("master") | ||
| 64 | public class PlayServiceImpl implements IPlayService { | 75 | public class PlayServiceImpl implements IPlayService { |
| 65 | 76 | ||
| 66 | private final static Logger logger = LoggerFactory.getLogger(PlayServiceImpl.class); | 77 | private final static Logger logger = LoggerFactory.getLogger(PlayServiceImpl.class); |
| @@ -93,12 +104,18 @@ public class PlayServiceImpl implements IPlayService { | @@ -93,12 +104,18 @@ public class PlayServiceImpl implements IPlayService { | ||
| 93 | private SendRtpPortManager sendRtpPortManager; | 104 | private SendRtpPortManager sendRtpPortManager; |
| 94 | 105 | ||
| 95 | @Autowired | 106 | @Autowired |
| 107 | + private ZlmHttpHookSubscribe subscribe; | ||
| 108 | + | ||
| 109 | + @Autowired | ||
| 96 | private ZLMRESTfulUtils zlmresTfulUtils; | 110 | private ZLMRESTfulUtils zlmresTfulUtils; |
| 97 | 111 | ||
| 98 | @Autowired | 112 | @Autowired |
| 99 | private AssistRESTfulUtils assistRESTfulUtils; | 113 | private AssistRESTfulUtils assistRESTfulUtils; |
| 100 | 114 | ||
| 101 | @Autowired | 115 | @Autowired |
| 116 | + private ZLMServerFactory zlmServerFactory; | ||
| 117 | + | ||
| 118 | + @Autowired | ||
| 102 | private IMediaService mediaService; | 119 | private IMediaService mediaService; |
| 103 | 120 | ||
| 104 | @Autowired | 121 | @Autowired |
| @@ -117,7 +134,7 @@ public class PlayServiceImpl implements IPlayService { | @@ -117,7 +134,7 @@ public class PlayServiceImpl implements IPlayService { | ||
| 117 | private DynamicTask dynamicTask; | 134 | private DynamicTask dynamicTask; |
| 118 | 135 | ||
| 119 | @Autowired | 136 | @Autowired |
| 120 | - private ZlmHttpHookSubscribe subscribe; | 137 | + private CloudRecordServiceMapper cloudRecordServiceMapper; |
| 121 | 138 | ||
| 122 | @Autowired | 139 | @Autowired |
| 123 | private ISIPCommanderForPlatform commanderForPlatform; | 140 | private ISIPCommanderForPlatform commanderForPlatform; |
| @@ -407,6 +424,15 @@ public class PlayServiceImpl implements IPlayService { | @@ -407,6 +424,15 @@ public class PlayServiceImpl implements IPlayService { | ||
| 407 | HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", ssrcInfo.getStream(), true, "rtsp", mediaServerItem.getId()); | 424 | HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", ssrcInfo.getStream(), true, "rtsp", mediaServerItem.getId()); |
| 408 | subscribe.removeSubscribe(hookSubscribe); | 425 | subscribe.removeSubscribe(hookSubscribe); |
| 409 | } | 426 | } |
| 427 | + }else { | ||
| 428 | + logger.info("[点播超时] 收流超时 deviceId: {}, channelId: {},码流类型:{},端口:{}, SSRC: {}", | ||
| 429 | + device.getDeviceId(), channelId, device.isSwitchPrimarySubStream() ? "辅码流" : "主码流", | ||
| 430 | + ssrcInfo.getPort(), ssrcInfo.getSsrc()); | ||
| 431 | + | ||
| 432 | + mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc()); | ||
| 433 | + | ||
| 434 | + mediaServerService.closeRTPServer(mediaServerItem.getId(), ssrcInfo.getStream()); | ||
| 435 | + streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream()); | ||
| 410 | } | 436 | } |
| 411 | }, userSetting.getPlayTimeout()); | 437 | }, userSetting.getPlayTimeout()); |
| 412 | 438 | ||
| @@ -437,6 +463,7 @@ public class PlayServiceImpl implements IPlayService { | @@ -437,6 +463,7 @@ public class PlayServiceImpl implements IPlayService { | ||
| 437 | InviteOKHandler(eventResult, ssrcInfo, mediaServerItem, device, channelId, | 463 | InviteOKHandler(eventResult, ssrcInfo, mediaServerItem, device, channelId, |
| 438 | timeOutTaskKey, callback, inviteInfo, InviteSessionType.PLAY); | 464 | timeOutTaskKey, callback, inviteInfo, InviteSessionType.PLAY); |
| 439 | }, (event) -> { | 465 | }, (event) -> { |
| 466 | + logger.info("[点播失败] deviceId: {}, channelId:{}, {}: {}", device.getDeviceId(), channelId, event.statusCode, event.msg); | ||
| 440 | dynamicTask.stop(timeOutTaskKey); | 467 | dynamicTask.stop(timeOutTaskKey); |
| 441 | mediaServerService.closeRTPServer(mediaServerItem, ssrcInfo.getStream()); | 468 | mediaServerService.closeRTPServer(mediaServerItem, ssrcInfo.getStream()); |
| 442 | // 释放ssrc | 469 | // 释放ssrc |
| @@ -478,7 +505,13 @@ public class PlayServiceImpl implements IPlayService { | @@ -478,7 +505,13 @@ public class PlayServiceImpl implements IPlayService { | ||
| 478 | if (!device.getStreamMode().equalsIgnoreCase("TCP-ACTIVE")) { | 505 | if (!device.getStreamMode().equalsIgnoreCase("TCP-ACTIVE")) { |
| 479 | return; | 506 | return; |
| 480 | } | 507 | } |
| 481 | - String substring = contentString.substring(0, contentString.indexOf("y=")); | 508 | + |
| 509 | + String substring; | ||
| 510 | + if (contentString.indexOf("y=") > 0) { | ||
| 511 | + substring = contentString.substring(0, contentString.indexOf("y=")); | ||
| 512 | + }else { | ||
| 513 | + substring = contentString; | ||
| 514 | + } | ||
| 482 | try { | 515 | try { |
| 483 | SessionDescription sdp = SdpFactory.getInstance().createSessionDescription(substring); | 516 | SessionDescription sdp = SdpFactory.getInstance().createSessionDescription(substring); |
| 484 | int port = -1; | 517 | int port = -1; |
| @@ -568,7 +601,7 @@ public class PlayServiceImpl implements IPlayService { | @@ -568,7 +601,7 @@ public class PlayServiceImpl implements IPlayService { | ||
| 568 | deviceChannel.setStreamId(streamInfo.getStream()); | 601 | deviceChannel.setStreamId(streamInfo.getStream()); |
| 569 | storager.startPlay(deviceId, channelId, streamInfo.getStream()); | 602 | storager.startPlay(deviceId, channelId, streamInfo.getStream()); |
| 570 | } | 603 | } |
| 571 | - InviteInfo inviteInfo = inviteStreamService.getInviteInfoByDeviceAndChannel(InviteSessionType.PLAYBACK, deviceId, channelId); | 604 | + InviteInfo inviteInfo = inviteStreamService.getInviteInfoByStream(InviteSessionType.PLAYBACK, ((OnStreamChangedHookParam) param).getStream()); |
| 572 | if (inviteInfo != null) { | 605 | if (inviteInfo != null) { |
| 573 | inviteInfo.setStatus(InviteSessionStatus.ok); | 606 | inviteInfo.setStatus(InviteSessionStatus.ok); |
| 574 | 607 | ||
| @@ -598,23 +631,6 @@ public class PlayServiceImpl implements IPlayService { | @@ -598,23 +631,6 @@ public class PlayServiceImpl implements IPlayService { | ||
| 598 | } | 631 | } |
| 599 | 632 | ||
| 600 | @Override | 633 | @Override |
| 601 | - public MediaServerItem getNewMediaServerItemHasAssist(Device device) { | ||
| 602 | - if (device == null) { | ||
| 603 | - return null; | ||
| 604 | - } | ||
| 605 | - MediaServerItem mediaServerItem; | ||
| 606 | - if (ObjectUtils.isEmpty(device.getMediaServerId()) || "auto".equals(device.getMediaServerId())) { | ||
| 607 | - mediaServerItem = mediaServerService.getMediaServerForMinimumLoad(true); | ||
| 608 | - } else { | ||
| 609 | - mediaServerItem = mediaServerService.getOne(device.getMediaServerId()); | ||
| 610 | - } | ||
| 611 | - if (mediaServerItem == null) { | ||
| 612 | - logger.warn("[获取可用的ZLM节点]未找到可使用的ZLM..."); | ||
| 613 | - } | ||
| 614 | - return mediaServerItem; | ||
| 615 | - } | ||
| 616 | - | ||
| 617 | - @Override | ||
| 618 | public void playBack(String deviceId, String channelId, String startTime, | 634 | public void playBack(String deviceId, String channelId, String startTime, |
| 619 | String endTime, ErrorCallback<Object> callback) { | 635 | String endTime, ErrorCallback<Object> callback) { |
| 620 | Device device = storager.queryVideoDevice(deviceId); | 636 | Device device = storager.queryVideoDevice(deviceId); |
| @@ -711,7 +727,6 @@ public class PlayServiceImpl implements IPlayService { | @@ -711,7 +727,6 @@ public class PlayServiceImpl implements IPlayService { | ||
| 711 | // 处理收到200ok后的TCP主动连接以及SSRC不一致的问题 | 727 | // 处理收到200ok后的TCP主动连接以及SSRC不一致的问题 |
| 712 | InviteOKHandler(eventResult, ssrcInfo, mediaServerItem, device, channelId, | 728 | InviteOKHandler(eventResult, ssrcInfo, mediaServerItem, device, channelId, |
| 713 | playBackTimeOutTaskKey, callback, inviteInfo, InviteSessionType.PLAYBACK); | 729 | playBackTimeOutTaskKey, callback, inviteInfo, InviteSessionType.PLAYBACK); |
| 714 | - | ||
| 715 | }, errorEvent); | 730 | }, errorEvent); |
| 716 | } catch (InvalidArgumentException | SipException | ParseException e) { | 731 | } catch (InvalidArgumentException | SipException | ParseException e) { |
| 717 | logger.error("[命令发送失败] 录像回放: {}", e.getMessage()); | 732 | logger.error("[命令发送失败] 录像回放: {}", e.getMessage()); |
| @@ -732,6 +747,10 @@ public class PlayServiceImpl implements IPlayService { | @@ -732,6 +747,10 @@ public class PlayServiceImpl implements IPlayService { | ||
| 732 | ResponseEvent responseEvent = (ResponseEvent) eventResult.event; | 747 | ResponseEvent responseEvent = (ResponseEvent) eventResult.event; |
| 733 | String contentString = new String(responseEvent.getResponse().getRawContent()); | 748 | String contentString = new String(responseEvent.getResponse().getRawContent()); |
| 734 | String ssrcInResponse = SipUtils.getSsrcFromSdp(contentString); | 749 | String ssrcInResponse = SipUtils.getSsrcFromSdp(contentString); |
| 750 | + // 兼容回复的消息中缺少ssrc(y字段)的情况 | ||
| 751 | + if (ssrcInResponse == null) { | ||
| 752 | + ssrcInResponse = ssrcInfo.getSsrc(); | ||
| 753 | + } | ||
| 735 | if (ssrcInfo.getSsrc().equals(ssrcInResponse)) { | 754 | if (ssrcInfo.getSsrc().equals(ssrcInResponse)) { |
| 736 | // ssrc 一致 | 755 | // ssrc 一致 |
| 737 | if (mediaServerItem.isRtpEnable()) { | 756 | if (mediaServerItem.isRtpEnable()) { |
| @@ -809,13 +828,15 @@ public class PlayServiceImpl implements IPlayService { | @@ -809,13 +828,15 @@ public class PlayServiceImpl implements IPlayService { | ||
| 809 | } | 828 | } |
| 810 | 829 | ||
| 811 | 830 | ||
| 831 | + | ||
| 832 | + | ||
| 812 | @Override | 833 | @Override |
| 813 | public void download(String deviceId, String channelId, String startTime, String endTime, int downloadSpeed, ErrorCallback<Object> callback) { | 834 | public void download(String deviceId, String channelId, String startTime, String endTime, int downloadSpeed, ErrorCallback<Object> callback) { |
| 814 | Device device = storager.queryVideoDevice(deviceId); | 835 | Device device = storager.queryVideoDevice(deviceId); |
| 815 | if (device == null) { | 836 | if (device == null) { |
| 816 | return; | 837 | return; |
| 817 | } | 838 | } |
| 818 | - MediaServerItem newMediaServerItem = getNewMediaServerItemHasAssist(device); | 839 | + MediaServerItem newMediaServerItem = this.getNewMediaServerItem(device); |
| 819 | if (newMediaServerItem == null) { | 840 | if (newMediaServerItem == null) { |
| 820 | callback.run(InviteErrorCode.ERROR_FOR_ASSIST_NOT_READY.getCode(), | 841 | callback.run(InviteErrorCode.ERROR_FOR_ASSIST_NOT_READY.getCode(), |
| 821 | InviteErrorCode.ERROR_FOR_ASSIST_NOT_READY.getMsg(), | 842 | InviteErrorCode.ERROR_FOR_ASSIST_NOT_READY.getMsg(), |
| @@ -894,6 +915,28 @@ public class PlayServiceImpl implements IPlayService { | @@ -894,6 +915,28 @@ public class PlayServiceImpl implements IPlayService { | ||
| 894 | // 处理收到200ok后的TCP主动连接以及SSRC不一致的问题 | 915 | // 处理收到200ok后的TCP主动连接以及SSRC不一致的问题 |
| 895 | InviteOKHandler(eventResult, ssrcInfo, mediaServerItem, device, channelId, | 916 | InviteOKHandler(eventResult, ssrcInfo, mediaServerItem, device, channelId, |
| 896 | downLoadTimeOutTaskKey, callback, inviteInfo, InviteSessionType.DOWNLOAD); | 917 | downLoadTimeOutTaskKey, callback, inviteInfo, InviteSessionType.DOWNLOAD); |
| 918 | + | ||
| 919 | + // 注册录像回调事件,录像下载结束后写入下载地址 | ||
| 920 | + ZlmHttpHookSubscribe.Event hookEventForRecord = (mediaServerItemInuse, hookParam) -> { | ||
| 921 | + logger.info("[录像下载] 收到录像写入磁盘消息: , {}/{}-{}", | ||
| 922 | + inviteInfo.getDeviceId(), inviteInfo.getChannelId(), ssrcInfo.getStream()); | ||
| 923 | + logger.info("[录像下载] 收到录像写入磁盘消息内容: " + hookParam); | ||
| 924 | + OnRecordMp4HookParam recordMp4HookParam = (OnRecordMp4HookParam)hookParam; | ||
| 925 | + String filePath = recordMp4HookParam.getFile_path(); | ||
| 926 | + DownloadFileInfo downloadFileInfo = CloudRecordUtils.getDownloadFilePath(mediaServerItem, filePath); | ||
| 927 | + InviteInfo inviteInfoForNew = inviteStreamService.getInviteInfo(inviteInfo.getType(), inviteInfo.getDeviceId() | ||
| 928 | + , inviteInfo.getChannelId(), inviteInfo.getStream()); | ||
| 929 | + inviteInfoForNew.getStreamInfo().setDownLoadFilePath(downloadFileInfo); | ||
| 930 | + inviteStreamService.updateInviteInfo(inviteInfoForNew); | ||
| 931 | + }; | ||
| 932 | + HookSubscribeForRecordMp4 hookSubscribe = HookSubscribeFactory.on_record_mp4( | ||
| 933 | + mediaServerItem.getId(), "rtp", ssrcInfo.getStream()); | ||
| 934 | + | ||
| 935 | + // 设置过期时间,下载失败时自动处理订阅数据 | ||
| 936 | +// long difference = DateUtil.getDifference(startTime, endTime)/1000; | ||
| 937 | +// Instant expiresInstant = Instant.now().plusSeconds(TimeUnit.MINUTES.toSeconds(difference * 2)); | ||
| 938 | +// hookSubscribe.setExpires(expiresInstant); | ||
| 939 | + subscribe.addSubscribe(hookSubscribe, hookEventForRecord); | ||
| 897 | }); | 940 | }); |
| 898 | } catch (InvalidArgumentException | SipException | ParseException e) { | 941 | } catch (InvalidArgumentException | SipException | ParseException e) { |
| 899 | logger.error("[命令发送失败] 录像下载: {}", e.getMessage()); | 942 | logger.error("[命令发送失败] 录像下载: {}", e.getMessage()); |
| @@ -909,47 +952,71 @@ public class PlayServiceImpl implements IPlayService { | @@ -909,47 +952,71 @@ public class PlayServiceImpl implements IPlayService { | ||
| 909 | @Override | 952 | @Override |
| 910 | public StreamInfo getDownLoadInfo(String deviceId, String channelId, String stream) { | 953 | public StreamInfo getDownLoadInfo(String deviceId, String channelId, String stream) { |
| 911 | InviteInfo inviteInfo = inviteStreamService.getInviteInfo(InviteSessionType.DOWNLOAD, deviceId, channelId, stream); | 954 | InviteInfo inviteInfo = inviteStreamService.getInviteInfo(InviteSessionType.DOWNLOAD, deviceId, channelId, stream); |
| 955 | + if (inviteInfo == null || inviteInfo.getStreamInfo() == null) { | ||
| 956 | + logger.warn("[获取下载进度] 未查询到录像下载的信息"); | ||
| 957 | + return null; | ||
| 958 | + } | ||
| 912 | 959 | ||
| 913 | - if (inviteInfo != null && inviteInfo.getStreamInfo() != null) { | ||
| 914 | - if (inviteInfo.getStreamInfo().getProgress() == 1) { | ||
| 915 | - return inviteInfo.getStreamInfo(); | ||
| 916 | - } | 960 | + if (inviteInfo.getStreamInfo().getProgress() == 1) { |
| 961 | + return inviteInfo.getStreamInfo(); | ||
| 962 | + } | ||
| 917 | 963 | ||
| 918 | - // 获取当前已下载时长 | ||
| 919 | - String mediaServerId = inviteInfo.getStreamInfo().getMediaServerId(); | ||
| 920 | - MediaServerItem mediaServerItem = mediaServerService.getOne(mediaServerId); | ||
| 921 | - if (mediaServerItem == null) { | ||
| 922 | - logger.warn("查询录像信息时发现节点已离线"); | ||
| 923 | - return null; | ||
| 924 | - } | ||
| 925 | - if (mediaServerItem.getRecordAssistPort() > 0) { | ||
| 926 | - JSONObject jsonObject = assistRESTfulUtils.fileDuration(mediaServerItem, inviteInfo.getStreamInfo().getApp(), inviteInfo.getStreamInfo().getStream(), null); | ||
| 927 | - if (jsonObject == null) { | ||
| 928 | - throw new ControllerException(ErrorCode.ERROR100.getCode(), "连接Assist服务失败"); | ||
| 929 | - } | ||
| 930 | - if (jsonObject.getInteger("code") == 0) { | ||
| 931 | - long duration = jsonObject.getLong("data"); | 964 | + // 获取当前已下载时长 |
| 965 | + String mediaServerId = inviteInfo.getStreamInfo().getMediaServerId(); | ||
| 966 | + MediaServerItem mediaServerItem = mediaServerService.getOne(mediaServerId); | ||
| 967 | + if (mediaServerItem == null) { | ||
| 968 | + logger.warn("[获取下载进度] 查询录像信息时发现节点不存在"); | ||
| 969 | + return null; | ||
| 970 | + } | ||
| 971 | + SsrcTransaction ssrcTransaction = streamSession.getSsrcTransaction(deviceId, channelId, null, stream); | ||
| 932 | 972 | ||
| 933 | - if (duration == 0) { | ||
| 934 | - inviteInfo.getStreamInfo().setProgress(0); | ||
| 935 | - } else { | ||
| 936 | - String startTime = inviteInfo.getStreamInfo().getStartTime(); | ||
| 937 | - String endTime = inviteInfo.getStreamInfo().getEndTime(); | ||
| 938 | - long start = DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(startTime); | ||
| 939 | - long end = DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(endTime); | ||
| 940 | - | ||
| 941 | - BigDecimal currentCount = new BigDecimal(duration / 1000); | ||
| 942 | - BigDecimal totalCount = new BigDecimal(end - start); | ||
| 943 | - BigDecimal divide = currentCount.divide(totalCount, 2, RoundingMode.HALF_UP); | ||
| 944 | - double process = divide.doubleValue(); | ||
| 945 | - inviteInfo.getStreamInfo().setProgress(process); | ||
| 946 | - } | ||
| 947 | - inviteStreamService.updateInviteInfo(inviteInfo); | ||
| 948 | - } | 973 | + if (ssrcTransaction == null) { |
| 974 | + logger.warn("[获取下载进度] 下载已结束"); | ||
| 975 | + return null; | ||
| 976 | + } | ||
| 977 | + | ||
| 978 | + JSONObject mediaListJson= zlmresTfulUtils.getMediaList(mediaServerItem, "rtp", stream); | ||
| 979 | + if (mediaListJson == null) { | ||
| 980 | + logger.warn("[获取下载进度] 从zlm查询进度失败"); | ||
| 981 | + return null; | ||
| 982 | + } | ||
| 983 | + if (mediaListJson.getInteger("code") != 0) { | ||
| 984 | + logger.warn("[获取下载进度] 从zlm查询进度出现错误: {}", mediaListJson.getString("msg")); | ||
| 985 | + return null; | ||
| 986 | + } | ||
| 987 | + JSONArray data = mediaListJson.getJSONArray("data"); | ||
| 988 | + if (data == null) { | ||
| 989 | + logger.warn("[获取下载进度] 从zlm查询进度时未返回数据"); | ||
| 990 | + return null; | ||
| 991 | + } | ||
| 992 | + JSONObject mediaJSON = data.getJSONObject(0); | ||
| 993 | + JSONArray tracks = mediaJSON.getJSONArray("tracks"); | ||
| 994 | + if (tracks.isEmpty()) { | ||
| 995 | + logger.warn("[获取下载进度] 从zlm查询进度时未返回数据"); | ||
| 996 | + return null; | ||
| 997 | + } | ||
| 998 | + JSONObject jsonObject = tracks.getJSONObject(0); | ||
| 999 | + long duration = jsonObject.getLongValue("duration"); | ||
| 1000 | + if (duration == 0) { | ||
| 1001 | + inviteInfo.getStreamInfo().setProgress(0); | ||
| 1002 | + } else { | ||
| 1003 | + String startTime = inviteInfo.getStreamInfo().getStartTime(); | ||
| 1004 | + String endTime = inviteInfo.getStreamInfo().getEndTime(); | ||
| 1005 | + // 此时start和end单位是秒 | ||
| 1006 | + long start = DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(startTime); | ||
| 1007 | + long end = DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(endTime); | ||
| 1008 | + | ||
| 1009 | + BigDecimal currentCount = new BigDecimal(duration); | ||
| 1010 | + BigDecimal totalCount = new BigDecimal((end - start) * 1000); | ||
| 1011 | + BigDecimal divide = currentCount.divide(totalCount, 2, RoundingMode.HALF_UP); | ||
| 1012 | + double process = divide.doubleValue(); | ||
| 1013 | + if (process > 0.999) { | ||
| 1014 | + process = 1.0; | ||
| 949 | } | 1015 | } |
| 950 | - return inviteInfo.getStreamInfo(); | 1016 | + inviteInfo.getStreamInfo().setProgress(process); |
| 951 | } | 1017 | } |
| 952 | - return null; | 1018 | + inviteStreamService.updateInviteInfo(inviteInfo); |
| 1019 | + return inviteInfo.getStreamInfo(); | ||
| 953 | } | 1020 | } |
| 954 | 1021 | ||
| 955 | private StreamInfo onPublishHandlerForDownload(MediaServerItem mediaServerItemInuse, HookParam hookParam, String deviceId, String channelId, String startTime, String endTime) { | 1022 | private StreamInfo onPublishHandlerForDownload(MediaServerItem mediaServerItemInuse, HookParam hookParam, String deviceId, String channelId, String startTime, String endTime) { |
| @@ -1219,7 +1286,12 @@ public class PlayServiceImpl implements IPlayService { | @@ -1219,7 +1286,12 @@ public class PlayServiceImpl implements IPlayService { | ||
| 1219 | throw new ServiceException("mediaServer不存在"); | 1286 | throw new ServiceException("mediaServer不存在"); |
| 1220 | } | 1287 | } |
| 1221 | // zlm 暂停RTP超时检查 | 1288 | // zlm 暂停RTP超时检查 |
| 1222 | - JSONObject jsonObject = zlmresTfulUtils.pauseRtpCheck(mediaServerItem, streamId); | 1289 | + // 使用zlm中的流ID |
| 1290 | + String streamKey = inviteInfo.getStream(); | ||
| 1291 | + if (!mediaServerItem.isRtpEnable()) { | ||
| 1292 | + streamKey = Long.toHexString(Long.parseLong(inviteInfo.getSsrcInfo().getSsrc())).toUpperCase(); | ||
| 1293 | + } | ||
| 1294 | + JSONObject jsonObject = zlmresTfulUtils.pauseRtpCheck(mediaServerItem, streamKey); | ||
| 1223 | if (jsonObject == null || jsonObject.getInteger("code") != 0) { | 1295 | if (jsonObject == null || jsonObject.getInteger("code") != 0) { |
| 1224 | throw new ServiceException("暂停RTP接收失败"); | 1296 | throw new ServiceException("暂停RTP接收失败"); |
| 1225 | } | 1297 | } |
| @@ -1242,7 +1314,12 @@ public class PlayServiceImpl implements IPlayService { | @@ -1242,7 +1314,12 @@ public class PlayServiceImpl implements IPlayService { | ||
| 1242 | throw new ServiceException("mediaServer不存在"); | 1314 | throw new ServiceException("mediaServer不存在"); |
| 1243 | } | 1315 | } |
| 1244 | // zlm 暂停RTP超时检查 | 1316 | // zlm 暂停RTP超时检查 |
| 1245 | - JSONObject jsonObject = zlmresTfulUtils.resumeRtpCheck(mediaServerItem, streamId); | 1317 | + // 使用zlm中的流ID |
| 1318 | + String streamKey = inviteInfo.getStream(); | ||
| 1319 | + if (!mediaServerItem.isRtpEnable()) { | ||
| 1320 | + streamKey = Long.toHexString(Long.parseLong(inviteInfo.getSsrcInfo().getSsrc())).toUpperCase(); | ||
| 1321 | + } | ||
| 1322 | + JSONObject jsonObject = zlmresTfulUtils.resumeRtpCheck(mediaServerItem, streamKey); | ||
| 1246 | if (jsonObject == null || jsonObject.getInteger("code") != 0) { | 1323 | if (jsonObject == null || jsonObject.getInteger("code") != 0) { |
| 1247 | throw new ServiceException("继续RTP接收失败"); | 1324 | throw new ServiceException("继续RTP接收失败"); |
| 1248 | } | 1325 | } |
src/main/java/com/genersoft/iot/vmp/service/impl/RoleServerImpl.java
| 1 | package com.genersoft.iot.vmp.service.impl; | 1 | package com.genersoft.iot.vmp.service.impl; |
| 2 | 2 | ||
| 3 | +import com.baomidou.dynamic.datasource.annotation.DS; | ||
| 3 | import com.genersoft.iot.vmp.service.IRoleService; | 4 | import com.genersoft.iot.vmp.service.IRoleService; |
| 4 | import com.genersoft.iot.vmp.storager.dao.RoleMapper; | 5 | import com.genersoft.iot.vmp.storager.dao.RoleMapper; |
| 5 | import com.genersoft.iot.vmp.storager.dao.dto.Role; | 6 | import com.genersoft.iot.vmp.storager.dao.dto.Role; |
| @@ -9,6 +10,7 @@ import org.springframework.stereotype.Service; | @@ -9,6 +10,7 @@ import org.springframework.stereotype.Service; | ||
| 9 | import java.util.List; | 10 | import java.util.List; |
| 10 | 11 | ||
| 11 | @Service | 12 | @Service |
| 13 | +@DS("master") | ||
| 12 | public class RoleServerImpl implements IRoleService { | 14 | public class RoleServerImpl implements IRoleService { |
| 13 | 15 | ||
| 14 | @Autowired | 16 | @Autowired |
src/main/java/com/genersoft/iot/vmp/service/impl/StreamProxyServiceImpl.java
| @@ -2,6 +2,7 @@ package com.genersoft.iot.vmp.service.impl; | @@ -2,6 +2,7 @@ package com.genersoft.iot.vmp.service.impl; | ||
| 2 | 2 | ||
| 3 | import com.alibaba.fastjson2.JSONArray; | 3 | import com.alibaba.fastjson2.JSONArray; |
| 4 | import com.alibaba.fastjson2.JSONObject; | 4 | import com.alibaba.fastjson2.JSONObject; |
| 5 | +import com.baomidou.dynamic.datasource.annotation.DS; | ||
| 5 | import com.genersoft.iot.vmp.common.GeneralCallback; | 6 | import com.genersoft.iot.vmp.common.GeneralCallback; |
| 6 | import com.genersoft.iot.vmp.common.StreamInfo; | 7 | import com.genersoft.iot.vmp.common.StreamInfo; |
| 7 | import com.genersoft.iot.vmp.conf.DynamicTask; | 8 | import com.genersoft.iot.vmp.conf.DynamicTask; |
| @@ -53,6 +54,7 @@ import java.util.stream.Collectors; | @@ -53,6 +54,7 @@ import java.util.stream.Collectors; | ||
| 53 | * 视频代理业务 | 54 | * 视频代理业务 |
| 54 | */ | 55 | */ |
| 55 | @Service | 56 | @Service |
| 57 | +@DS("master") | ||
| 56 | public class StreamProxyServiceImpl implements IStreamProxyService { | 58 | public class StreamProxyServiceImpl implements IStreamProxyService { |
| 57 | 59 | ||
| 58 | private final static Logger logger = LoggerFactory.getLogger(StreamProxyServiceImpl.class); | 60 | private final static Logger logger = LoggerFactory.getLogger(StreamProxyServiceImpl.class); |
| @@ -126,7 +128,13 @@ public class StreamProxyServiceImpl implements IStreamProxyService { | @@ -126,7 +128,13 @@ public class StreamProxyServiceImpl implements IStreamProxyService { | ||
| 126 | } | 128 | } |
| 127 | JSONArray dataArray = jsonObject.getJSONArray("data"); | 129 | JSONArray dataArray = jsonObject.getJSONArray("data"); |
| 128 | JSONObject mediaServerConfig = dataArray.getJSONObject(0); | 130 | JSONObject mediaServerConfig = dataArray.getJSONObject(0); |
| 131 | + if (ObjectUtils.isEmpty(param.getFfmpegCmdKey())) { | ||
| 132 | + param.setFfmpegCmdKey("ffmpeg.cmd"); | ||
| 133 | + } | ||
| 129 | String ffmpegCmd = mediaServerConfig.getString(param.getFfmpegCmdKey()); | 134 | String ffmpegCmd = mediaServerConfig.getString(param.getFfmpegCmdKey()); |
| 135 | + if (ffmpegCmd == null) { | ||
| 136 | + throw new ControllerException(ErrorCode.ERROR100.getCode(), "ffmpeg拉流代理无法获取ffmpeg cmd"); | ||
| 137 | + } | ||
| 130 | String schema = getSchemaFromFFmpegCmd(ffmpegCmd); | 138 | String schema = getSchemaFromFFmpegCmd(ffmpegCmd); |
| 131 | if (schema == null) { | 139 | if (schema == null) { |
| 132 | throw new ControllerException(ErrorCode.ERROR100.getCode(), "ffmpeg拉流代理无法从ffmpeg cmd中获取到输出格式"); | 140 | throw new ControllerException(ErrorCode.ERROR100.getCode(), "ffmpeg拉流代理无法从ffmpeg cmd中获取到输出格式"); |
| @@ -401,6 +409,8 @@ public class StreamProxyServiceImpl implements IStreamProxyService { | @@ -401,6 +409,8 @@ public class StreamProxyServiceImpl implements IStreamProxyService { | ||
| 401 | logger.info("启用代理失败: {}/{}->{}({})", app, stream, jsonObject.getString("msg"), | 409 | logger.info("启用代理失败: {}/{}->{}({})", app, stream, jsonObject.getString("msg"), |
| 402 | streamProxy.getSrcUrl() == null? streamProxy.getUrl():streamProxy.getSrcUrl()); | 410 | streamProxy.getSrcUrl() == null? streamProxy.getUrl():streamProxy.getSrcUrl()); |
| 403 | } | 411 | } |
| 412 | + } else if (streamProxy != null && streamProxy.isEnable()) { | ||
| 413 | + return true ; | ||
| 404 | } | 414 | } |
| 405 | return result; | 415 | return result; |
| 406 | } | 416 | } |
| @@ -452,7 +462,7 @@ public class StreamProxyServiceImpl implements IStreamProxyService { | @@ -452,7 +462,7 @@ public class StreamProxyServiceImpl implements IStreamProxyService { | ||
| 452 | streamProxyMapper.deleteAutoRemoveItemByMediaServerId(mediaServerId); | 462 | streamProxyMapper.deleteAutoRemoveItemByMediaServerId(mediaServerId); |
| 453 | 463 | ||
| 454 | // 移除拉流代理生成的流信息 | 464 | // 移除拉流代理生成的流信息 |
| 455 | -// syncPullStream(mediaServerId); | 465 | + syncPullStream(mediaServerId); |
| 456 | 466 | ||
| 457 | // 恢复流代理, 只查找这个这个流媒体 | 467 | // 恢复流代理, 只查找这个这个流媒体 |
| 458 | List<StreamProxyItem> streamProxyListForEnable = storager.getStreamProxyListForEnableInMediaServer( | 468 | List<StreamProxyItem> streamProxyListForEnable = storager.getStreamProxyListForEnableInMediaServer( |
src/main/java/com/genersoft/iot/vmp/service/impl/StreamPushServiceImpl.java
| @@ -4,6 +4,7 @@ import com.alibaba.fastjson2.JSON; | @@ -4,6 +4,7 @@ import com.alibaba.fastjson2.JSON; | ||
| 4 | import com.alibaba.fastjson2.JSONArray; | 4 | import com.alibaba.fastjson2.JSONArray; |
| 5 | import com.alibaba.fastjson2.JSONObject; | 5 | import com.alibaba.fastjson2.JSONObject; |
| 6 | import com.alibaba.fastjson2.TypeReference; | 6 | import com.alibaba.fastjson2.TypeReference; |
| 7 | +import com.baomidou.dynamic.datasource.annotation.DS; | ||
| 7 | import com.genersoft.iot.vmp.conf.MediaConfig; | 8 | import com.genersoft.iot.vmp.conf.MediaConfig; |
| 8 | import com.genersoft.iot.vmp.conf.UserSetting; | 9 | import com.genersoft.iot.vmp.conf.UserSetting; |
| 9 | import com.genersoft.iot.vmp.gb28181.bean.*; | 10 | import com.genersoft.iot.vmp.gb28181.bean.*; |
| @@ -36,6 +37,7 @@ import java.util.*; | @@ -36,6 +37,7 @@ import java.util.*; | ||
| 36 | import java.util.stream.Collectors; | 37 | import java.util.stream.Collectors; |
| 37 | 38 | ||
| 38 | @Service | 39 | @Service |
| 40 | +@DS("master") | ||
| 39 | public class StreamPushServiceImpl implements IStreamPushService { | 41 | public class StreamPushServiceImpl implements IStreamPushService { |
| 40 | 42 | ||
| 41 | private final static Logger logger = LoggerFactory.getLogger(StreamPushServiceImpl.class); | 43 | private final static Logger logger = LoggerFactory.getLogger(StreamPushServiceImpl.class); |
| @@ -282,6 +284,8 @@ public class StreamPushServiceImpl implements IStreamPushService { | @@ -282,6 +284,8 @@ public class StreamPushServiceImpl implements IStreamPushService { | ||
| 282 | redisCatchStorage.sendStreamChangeMsg(type, jsonObject); | 284 | redisCatchStorage.sendStreamChangeMsg(type, jsonObject); |
| 283 | // 移除redis内流的信息 | 285 | // 移除redis内流的信息 |
| 284 | redisCatchStorage.removeStream(mediaServerItem.getId(), "PUSH", offlineOnStreamChangedHookParam.getApp(), offlineOnStreamChangedHookParam.getStream()); | 286 | redisCatchStorage.removeStream(mediaServerItem.getId(), "PUSH", offlineOnStreamChangedHookParam.getApp(), offlineOnStreamChangedHookParam.getStream()); |
| 287 | + // 冗余数据,自己系统中自用 | ||
| 288 | + redisCatchStorage.removePushListItem(offlineOnStreamChangedHookParam.getApp(), offlineOnStreamChangedHookParam.getStream(), mediaServerItem.getId()); | ||
| 285 | } | 289 | } |
| 286 | } | 290 | } |
| 287 | 291 | ||
| @@ -319,6 +323,9 @@ public class StreamPushServiceImpl implements IStreamPushService { | @@ -319,6 +323,9 @@ public class StreamPushServiceImpl implements IStreamPushService { | ||
| 319 | jsonObject.put("register", false); | 323 | jsonObject.put("register", false); |
| 320 | jsonObject.put("mediaServerId", mediaServerId); | 324 | jsonObject.put("mediaServerId", mediaServerId); |
| 321 | redisCatchStorage.sendStreamChangeMsg(type, jsonObject); | 325 | redisCatchStorage.sendStreamChangeMsg(type, jsonObject); |
| 326 | + | ||
| 327 | + // 冗余数据,自己系统中自用 | ||
| 328 | + redisCatchStorage.removePushListItem(onStreamChangedHookParam.getApp(), onStreamChangedHookParam.getStream(), mediaServerId); | ||
| 322 | } | 329 | } |
| 323 | } | 330 | } |
| 324 | } | 331 | } |
src/main/java/com/genersoft/iot/vmp/service/impl/UserServiceImpl.java
| 1 | package com.genersoft.iot.vmp.service.impl; | 1 | package com.genersoft.iot.vmp.service.impl; |
| 2 | 2 | ||
| 3 | +import com.baomidou.dynamic.datasource.annotation.DS; | ||
| 3 | import com.genersoft.iot.vmp.service.IUserService; | 4 | import com.genersoft.iot.vmp.service.IUserService; |
| 4 | import com.genersoft.iot.vmp.storager.dao.UserMapper; | 5 | import com.genersoft.iot.vmp.storager.dao.UserMapper; |
| 5 | import com.genersoft.iot.vmp.storager.dao.dto.User; | 6 | import com.genersoft.iot.vmp.storager.dao.dto.User; |
| @@ -12,6 +13,7 @@ import org.springframework.util.DigestUtils; | @@ -12,6 +13,7 @@ import org.springframework.util.DigestUtils; | ||
| 12 | import java.util.List; | 13 | import java.util.List; |
| 13 | 14 | ||
| 14 | @Service | 15 | @Service |
| 16 | +@DS("master") | ||
| 15 | public class UserServiceImpl implements IUserService { | 17 | public class UserServiceImpl implements IUserService { |
| 16 | 18 | ||
| 17 | @Autowired | 19 | @Autowired |