Bläddra i källkod

Merge branch 'wvp-28181-2.0' into main-dev

# Conflicts:
#	src/main/java/com/genersoft/iot/vmp/conf/UserSetting.java
#	src/main/java/com/genersoft/iot/vmp/gb28181/bean/Device.java
#	src/main/java/com/genersoft/iot/vmp/gb28181/transmit/callback/DeferredResultHolder.java
#	src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommanderForPlatform.java
#	src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java
#	src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/response/impl/InviteResponseProcessor.java
#	src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRTPServerFactory.java
#	src/main/java/com/genersoft/iot/vmp/service/IPlayService.java
#	src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java
#	src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/play/PlayController.java
#	src/main/resources/all-application.yml
#	web_src/config/index.js
#	web_src/src/components/dialog/devicePlayer.vue
648540858 2 år sedan
förälder
incheckning
5a7a7a12bd
100 ändrade filer med 2367 tillägg och 1327 borttagningar
  1. 3 1
      README.md
  2. 12 12
      doc/README.md
  3. 47 4
      doc/_content/introduction/config.md
  4. BIN
      doc/_media/1372762149.jpg
  5. BIN
      doc/_media/903207146.jpg
  6. BIN
      doc/_media/logo.jpg
  7. 6 6
      doc/index.html
  8. 1 0
      doc/lib/css/vue.css
  9. 9 0
      doc/lib/js/docsify-copy-code.min.js
  10. 1 0
      doc/lib/js/docsify-plantuml.min.js
  11. 1 0
      doc/lib/js/docsify@4.js
  12. 1 0
      doc/lib/js/search.min.js
  13. 1 0
      doc/lib/js/zoom-image.min.js
  14. BIN
      libs/jdbc-aarch/kingbase8-8.6.0.jar
  15. BIN
      libs/jdbc-aarch/kingbase8-8.6.0.jre7.jar
  16. BIN
      libs/jdbc-aarch/postgresql-42.2.9.jar
  17. BIN
      libs/jdbc-aarch/postgresql-42.2.9.jre7.jar
  18. 21 2
      pom.xml
  19. 2 1
      sql/2.6.6-2.6.7更新.sql
  20. 479 0
      sql/2.6.8升级2.6.9.sql
  21. 13 13
      sql/clean.sql
  22. 283 542
      sql/初始化.sql
  23. 42 0
      src/main/java/com/genersoft/iot/vmp/common/CivilCodePo.java
  24. 5 0
      src/main/java/com/genersoft/iot/vmp/common/GeneralCallback.java
  25. 19 1
      src/main/java/com/genersoft/iot/vmp/common/InviteInfo.java
  26. 15 0
      src/main/java/com/genersoft/iot/vmp/common/StreamInfo.java
  27. 5 0
      src/main/java/com/genersoft/iot/vmp/common/VideoManagerConstants.java
  28. 101 0
      src/main/java/com/genersoft/iot/vmp/conf/CivilCodeFileConf.java
  29. 1 1
      src/main/java/com/genersoft/iot/vmp/conf/MediaConfig.java
  30. 36 0
      src/main/java/com/genersoft/iot/vmp/conf/MybatisConfig.java
  31. 1 1
      src/main/java/com/genersoft/iot/vmp/conf/ProxyServletConfig.java
  32. 1 1
      src/main/java/com/genersoft/iot/vmp/conf/SipConfig.java
  33. 1 1
      src/main/java/com/genersoft/iot/vmp/conf/SipPlatformRunner.java
  34. 1 1
      src/main/java/com/genersoft/iot/vmp/conf/SpringDocConfig.java
  35. 1 1
      src/main/java/com/genersoft/iot/vmp/conf/ThreadPoolTaskConfig.java
  36. 40 1
      src/main/java/com/genersoft/iot/vmp/conf/UserSetting.java
  37. 1 1
      src/main/java/com/genersoft/iot/vmp/conf/VersionConfig.java
  38. 4 0
      src/main/java/com/genersoft/iot/vmp/conf/redis/RedisMsgListenConfig.java
  39. 4 0
      src/main/java/com/genersoft/iot/vmp/conf/security/AnonymousAuthenticationEntryPoint.java
  40. 1 1
      src/main/java/com/genersoft/iot/vmp/conf/security/WebSecurityConfig.java
  41. 25 22
      src/main/java/com/genersoft/iot/vmp/gb28181/bean/Device.java
  42. 3 3
      src/main/java/com/genersoft/iot/vmp/gb28181/bean/DeviceChannel.java
  43. 46 0
      src/main/java/com/genersoft/iot/vmp/gb28181/bean/Gb28181Sdp.java
  44. 1 1
      src/main/java/com/genersoft/iot/vmp/gb28181/bean/GbStream.java
  45. 0 14
      src/main/java/com/genersoft/iot/vmp/gb28181/bean/ParentPlatform.java
  46. 1 1
      src/main/java/com/genersoft/iot/vmp/gb28181/bean/PlatformGbStream.java
  47. 0 10
      src/main/java/com/genersoft/iot/vmp/gb28181/bean/TreeType.java
  48. 8 16
      src/main/java/com/genersoft/iot/vmp/gb28181/session/SSRCFactory.java
  49. 9 1
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/callback/DeferredResultHolder.java
  50. 1 1
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommanderForPlatform.java
  51. 2 2
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderPlarformProvider.java
  52. 37 17
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java
  53. 143 52
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java
  54. 1 2
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/ByeRequestProcessor.java
  55. 21 38
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java
  56. 23 4
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/NotifyRequestForCatalogProcessor.java
  57. 14 5
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/NotifyRequestProcessor.java
  58. 1 2
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/RegisterRequestProcessor.java
  59. 1 1
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/AlarmNotifyMessageHandler.java
  60. 2 2
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/KeepaliveNotifyMessageHandler.java
  61. 8 2
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/MobilePositionNotifyMessageHandler.java
  62. 1 1
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/DeviceStatusQueryMessageHandler.java
  63. 6 1
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/CatalogResponseMessageHandler.java
  64. 1 6
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/DeviceInfoResponseMessageHandler.java
  65. 25 5
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/MobilePositionResponseMessageHandler.java
  66. 4 14
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/response/impl/InviteResponseProcessor.java
  67. 1 1
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/response/impl/RegisterResponseProcessor.java
  68. 81 1
      src/main/java/com/genersoft/iot/vmp/gb28181/utils/SipUtils.java
  69. 328 181
      src/main/java/com/genersoft/iot/vmp/gb28181/utils/XmlUtil.java
  70. 15 15
      src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java
  71. 0 1
      src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRESTfulUtils.java
  72. 21 17
      src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRTPServerFactory.java
  73. 2 2
      src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRunner.java
  74. 2 1
      src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMServerConfig.java
  75. 2 1
      src/main/java/com/genersoft/iot/vmp/media/zlm/ZlmHttpHookSubscribe.java
  76. 45 55
      src/main/java/com/genersoft/iot/vmp/media/zlm/dto/StreamProxyItem.java
  77. 60 0
      src/main/java/com/genersoft/iot/vmp/media/zlm/dto/StreamPushItem.java
  78. 2 0
      src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/HookResultForOnPublish.java
  79. 10 1
      src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnPlayHookParam.java
  80. 10 1
      src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnPublishHookParam.java
  81. 11 0
      src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnRtpServerTimeoutHookParam.java
  82. 8 0
      src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnSendRtpStoppedHookParam.java
  83. 7 0
      src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnServerKeepaliveHookParam.java
  84. 10 0
      src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnStreamChangedHookParam.java
  85. 10 0
      src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnStreamNoneReaderHookParam.java
  86. 10 1
      src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnStreamNotFoundHookParam.java
  87. 2 2
      src/main/java/com/genersoft/iot/vmp/service/IDeviceChannelService.java
  88. 2 2
      src/main/java/com/genersoft/iot/vmp/service/IDeviceService.java
  89. 12 2
      src/main/java/com/genersoft/iot/vmp/service/IInviteStreamService.java
  90. 9 7
      src/main/java/com/genersoft/iot/vmp/service/IPlayService.java
  91. 0 8
      src/main/java/com/genersoft/iot/vmp/service/IRecordInfoServer.java
  92. 4 3
      src/main/java/com/genersoft/iot/vmp/service/IStreamProxyService.java
  93. 2 2
      src/main/java/com/genersoft/iot/vmp/service/IStreamPushService.java
  94. 1 1
      src/main/java/com/genersoft/iot/vmp/service/bean/InviteErrorCallback.java
  95. 1 0
      src/main/java/com/genersoft/iot/vmp/service/bean/InviteErrorCode.java
  96. 9 5
      src/main/java/com/genersoft/iot/vmp/service/impl/DeviceChannelServiceImpl.java
  97. 66 158
      src/main/java/com/genersoft/iot/vmp/service/impl/DeviceServiceImpl.java
  98. 18 29
      src/main/java/com/genersoft/iot/vmp/service/impl/GbStreamServiceImpl.java
  99. 63 16
      src/main/java/com/genersoft/iot/vmp/service/impl/InviteStreamServiceImpl.java
  100. 0 0
      src/main/java/com/genersoft/iot/vmp/service/impl/MediaServerServiceImpl.java

+ 3 - 1
README.md

@@ -27,7 +27,7 @@ wvp使用文档 [https://doc.wvp-pro.cn](https://doc.wvp-pro.cn)
 ZLM使用文档 [https://github.com/ZLMediaKit/ZLMediaKit](https://github.com/ZLMediaKit/ZLMediaKit)
 > wvp文档由gitee提供服务,如果遇到打不开请多刷新几次。
 
-# 社群地址
+# 付费社群
 [![社群](doc/_media/shequ.png "shequ")](https://t.zsxq.com/0d8VAD3Dm)
 > 收费是为了提供更好的服务,也是对作者更大的激励。加入星球的用户三天后可以私信我留下微信号,我会拉大家入群。加入三天内不满意可以直接退款,大家不需要有顾虑,来白嫖三天也不是不可以。
 
@@ -104,6 +104,8 @@ https://gitee.com/pan648540858/wvp-GB28181-pro.git
 - [X] 云端录像,推流/代理/国标视频均可以录制在云端服务器,支持预览和下载
 - [X] 支持打包可执行jar和war
 - [X] 支持跨域请求,支持前后端分离部署
+- [X] 支持Mysql,Postgresql,金仓等数据库
+- [X] 支持Onvif(目前在onvif分支,需要安装onvif服务,服务请在知识星球获取)
 
 # 授权协议
 本项目自有代码使用宽松的MIT协议,在保留版权信息的情况下可以自由应用于各自商用、非商业的项目。 但是本项目也零碎的使用了一些其他的开源代码,在商用的情况下请自行替代或剔除; 由于使用本项目而产生的商业纠纷或侵权行为一概与本项目及开发者无关,请自行承担法律风险。 在使用本项目代码时,也应该在授权协议中同时表明本项目依赖的第三方库的协议

+ 12 - 12
doc/README.md

@@ -14,7 +14,7 @@
 - 完全开源,且使用MIT许可协议。保留版权的情况下可以用于商业项目。
 - 支持多流媒体节点负载均衡。
 
-# 社群
+# 付费社群
 [![社群](_media/shequ.png "shequ")](https://t.zsxq.com/0d8VAD3Dm)
 > 收费是为了提供更好的服务,也是对作者更大的激励。加入星球的用户三天后可以私信我留下微信号,我会拉大家入群。加入三天内不满意可以直接退款,大家不需要有顾虑,来白嫖三天也不是不可以。
 
@@ -62,16 +62,16 @@
 - [X] 注册
 - [X] 注销
 - [X] 实时视音频点播
-- [ ] 设备控制
-  - [ ] 云台控制
+- [X] 设备控制
+  - [X] 云台控制
   - [ ] 远程启动
-  - [ ] 录像控制
-  - [ ] 报警布防/撤防
-  - [ ] 报警复位
-  - [ ] 强制关键帧
-  - [ ] 拉框放大
-  - [ ] 拉框缩小
-  - [ ] 看守位控制
+  - [X] 录像控制
+  - [X] 报警布防/撤防
+  - [X] 报警复位
+  - [X] 强制关键帧
+  - [X] 拉框放大
+  - [X] 拉框缩小
+  - [X] 看守位控制
   - [ ] 设备配置
 - [ ] 报警事件通知和分发
 - [X] 设备目录订阅
@@ -79,7 +79,7 @@
   - [X] 设备目录查询
   - [X] 设备状态查询
   - [ ] 设备配置查询
-  - [ ] 设备预置位查询
+  - [X] 设备预置位查询
 - [X] 状态信息报送
 - [X] 设备视音频文件检索
 - [X] 历史视音频的回放
@@ -87,7 +87,7 @@
   - [x] 暂停
   - [x] 进/退
   - [x] 停止
-- [ ] 视音频文件下载
+- [X] 视音频文件下载
 - [ ] ~~校时~~
 - [X] 订阅和通知
   - [X] 事件订阅

+ 47 - 4
doc/_content/introduction/config.md

@@ -29,10 +29,53 @@ java -jar wvp-pro-*.jar
 ```
 这也是我自己最常用的方式。
 ## 2 配置WVP-PRO
-### 2.1 Mysql数据库配置
-首先你需要创建一个名为wvp(也可使用其他名字)的数据库,并使用sql/mysql.sql导入数据库,初始化数据库结构。
-(这里注意,取决于版本,新版的sql文件夹下有update.sql,补丁包,一定要注意运行导入)
-在application-dev.yml中配置(使用1.2方式的是在jar包的同级目录的application.yml)配置数据库连接,包括数据库连接信息,密码。
+wvp支持多种数据库,包括Mysql,Postgresql,金仓等,配置任选一种即可。
+### 2.1 数据库配置
+####  2.1.1 初始化数据库
+首先使用创建数据库,然后使用sql/初始化.sql初始化数据库,如果是从旧版升级上来的,使用升级sql更新。
+####  2.1.2 Mysql数据库配置
+数据库名称以wvp为例
+```yaml
+spring:
+  datasource:
+    type: com.zaxxer.hikari.HikariDataSource
+    driver-class-name: com.mysql.cj.jdbc.Driver
+    url: jdbc:mysql://127.0.0.1:3306/wvp?useUnicode=true&characterEncoding=UTF8&rewriteBatchedStatements=true&serverTimezone=PRC&useSSL=false&allowMultiQueries=true&allowPublicKeyRetrieval=true
+    username: root
+    password: 12345678
+
+mybatis:
+  configuration:
+    map-underscore-to-camel-case: true
+```
+####  2.1.3 Postgresql数据库配置
+数据库名称以wvp为例
+```yaml
+spring:
+  datasource:
+    type: com.zaxxer.hikari.HikariDataSource
+    driver-class-name: org.postgresql.Driver
+    url: jdbc:postgresql://127.0.0.1:3306/wvp?useUnicode=true&characterEncoding=UTF8&rewriteBatchedStatements=true&serverTimezone=PRC&useSSL=false&allowMultiQueries=true&allowPublicKeyRetrieval=true
+    username: root
+    password: 12345678
+
+pagehelper:
+  helper-dialect: postgresql
+```
+####  2.1.4 金仓数据库配置
+数据库名称以wvp为例
+```yaml
+spring:
+  datasource:
+    type: com.zaxxer.hikari.HikariDataSource
+    driver-class-name: com.kingbase8.Driver
+    url: jdbc:kingbase8://127.0.0.1:3306/wvp?useUnicode=true&characterEncoding=utf8
+    username: root
+    password: 12345678
+
+pagehelper:
+  helper-dialect: postgresql
+```
 ### 2.2 Redis数据库配置
 配置wvp中的redis连接信息,建议wvp自己单独使用一个db。
 ### 2.3 配置服务启动端口(可直接使用默认配置)

BIN
doc/_media/1372762149.jpg


BIN
doc/_media/903207146.jpg


BIN
doc/_media/logo.jpg


+ 6 - 6
doc/index.html

@@ -7,7 +7,7 @@
   <meta name="description" content="Description">
   <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0">
   <link rel="icon" href="_media/favicon.ico" type="image/x-icon" />
-  <link rel="stylesheet" href="//cdn.jsdelivr.net/npm/docsify@4/lib/themes/vue.css">
+  <link rel="stylesheet" href="./lib/css/vue.css">
 <!--  <link rel="stylesheet" href="//cdn.jsdelivr.net/npm/docsify/lib/themes/dark.css">-->
   <style>
     .cover{
@@ -47,11 +47,11 @@
     }
   </script>
   <!-- Docsify v4 -->
-  <script src="//cdn.jsdelivr.net/npm/docsify@4"></script>
-  <script src="//unpkg.com/docsify-plantuml/dist/docsify-plantuml.min.js"></script>
-  <script src="//cdn.jsdelivr.net/npm/docsify/lib/plugins/search.min.js"></script>
-  <script src="//cdn.jsdelivr.net/npm/docsify/lib/plugins/zoom-image.min.js"></script>
-  <script src="//cdn.jsdelivr.net/npm/docsify-copy-code/dist/docsify-copy-code.min.js"></script>
+  <script src="./lib/js/docsify@4.js"></script>
+  <script src="./lib/js/docsify-plantuml.min.js"></script>
+  <script src="./lib/js/search.min.js"></script>
+  <script src="./lib/js/zoom-image.min.js"></script>
+  <script src="./lib/js/docsify-copy-code.min.js"></script>
 
   </script>
 <!--  <script src="//cdn.jsdelivr.net/npm/docsify/lib/plugins/disqus.min.js"></script>-->

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 1 - 0
doc/lib/css/vue.css


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 9 - 0
doc/lib/js/docsify-copy-code.min.js


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 1 - 0
doc/lib/js/docsify-plantuml.min.js


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 1 - 0
doc/lib/js/docsify@4.js


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 1 - 0
doc/lib/js/search.min.js


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 1 - 0
doc/lib/js/zoom-image.min.js


BIN
libs/jdbc-aarch/kingbase8-8.6.0.jar


BIN
libs/jdbc-aarch/kingbase8-8.6.0.jre7.jar


BIN
libs/jdbc-aarch/postgresql-42.2.9.jar


BIN
libs/jdbc-aarch/postgresql-42.2.9.jre7.jar


+ 21 - 2
pom.xml

@@ -11,7 +11,7 @@
 
 	<groupId>com.genersoft</groupId>
 	<artifactId>wvp-pro</artifactId>
-	<version>2.6.8</version>
+	<version>2.6.9</version>
 	<name>web video platform</name>
 	<description>国标28181视频平台</description>
 	<packaging>${project.packaging}</packaging>
@@ -135,11 +135,30 @@
 			<version>8.0.30</version>
 		</dependency>
 
+		<!--postgresql-->
+		<dependency>
+			<groupId>org.postgresql</groupId>
+			<artifactId>postgresql</artifactId>
+			<version>42.5.1</version>
+		</dependency>
+
+		<!-- kingbase人大金仓 -->
+		<!-- 手动下载驱动后安装 -->
+		<!-- mvn install:install-file -Dfile=/home/lin/soft/kingbase/jdbc-aarch/kingbase8-8.6.0.jar -DgroupId=com.kingbase -DartifactId=kingbase8 -Dversion=8.6.0 -Dpackaging=jar
+ -->
+		<dependency>
+			<groupId>com.kingbase</groupId>
+			<artifactId>kingbase8</artifactId>
+			<version>8.6.0</version>
+			<scope>system</scope>
+			<systemPath>${basedir}/libs/jdbc-aarch/kingbase8-8.6.0.jar</systemPath>
+		</dependency>
+
 		<!--Mybatis分页插件 -->
 		<dependency>
 			<groupId>com.github.pagehelper</groupId>
 			<artifactId>pagehelper-spring-boot-starter</artifactId>
-			<version>1.4.3</version>
+			<version>1.4.6</version>
 		</dependency>
 
 		<!--在线文档 -->

+ 2 - 1
sql/2.6.6-2.6.7更新.sql

@@ -7,6 +7,7 @@ alter table parent_platform
 alter table device
     add mediaServerId varchar(50) default null;
 
-
+ALTER TABLE device
+    ADD COLUMN `switchPrimarySubStream` bit(1) NOT NULL DEFAULT b'0' COMMENT '开启主子码流切换的开关(0-不开启,1-开启)现在已知支持设备为 大华、TP——LINK全系设备' AFTER `keepalive_interval_time`
 
 

+ 479 - 0
sql/2.6.8升级2.6.9.sql

@@ -0,0 +1,479 @@
+alter table device
+    change deviceId device_id varchar(50) not null;
+
+alter table device
+    change streamMode stream_mode varchar(50) null;
+
+alter table device
+    change registerTime register_time varchar(50) null;
+
+alter table device
+    change keepaliveTime keepalive_time varchar(50) null;
+
+alter table device
+    change createTime create_time varchar(50) not null;
+
+alter table device
+    change updateTime update_time varchar(50) not null;
+
+alter table device
+    change subscribeCycleForCatalog subscribe_cycle_for_catalog bool default false;
+
+alter table device
+    change subscribeCycleForMobilePosition subscribe_cycle_for_mobile_position bool default false;
+
+alter table device
+    change mobilePositionSubmissionInterval mobile_position_submission_interval int default 5 not null;
+
+alter table device
+    change subscribeCycleForAlarm subscribe_cycle_for_alarm bool default false;
+
+alter table device
+    change hostAddress host_address varchar(50) null;
+
+alter table device
+    change ssrcCheck ssrc_check bool default false;
+
+alter table device
+    change geoCoordSys geo_coord_sys varchar(50) not null;
+
+alter table device
+    drop column treeType;
+
+alter table device
+    change mediaServerId media_server_id varchar(50) default 'auto' null;
+
+alter table device
+    change sdpIp sdp_ip varchar(50) null;
+
+alter table device
+    change localIp local_ip varchar(50) null;
+
+alter table device
+    change asMessageChannel as_message_channel bool default false;
+
+alter table device
+    change keepaliveIntervalTime keepalive_interval_time int null;
+
+alter table device
+    change online on_line varchar(50) null;
+
+alter table device
+    add COLUMN switch_primary_sub_stream bool default false comment '开启主子码流切换的开关(0-不开启,1-开启)现在已知支持设备为 大华、TP——LINK全系设备'
+
+
+alter table device_alarm
+    change deviceId device_id varchar(50) not null;
+
+alter table device_alarm
+    change channelId channel_id varchar(50) not null;
+
+alter table device_alarm
+    change alarmPriority alarm_priority varchar(50) not null;
+
+alter table device_alarm
+    change alarmMethod alarm_method varchar(50) null;
+
+alter table device_alarm
+    change alarmTime alarm_time varchar(50) not null;
+
+alter table device_alarm
+    change alarmDescription alarm_description varchar(255) null;
+
+alter table device_alarm
+    change alarmType alarm_type varchar(50) null;
+
+alter table device_alarm
+    change createTime create_time varchar(50) null;
+
+alter table device_channel
+    change channelId channel_id varchar(50) not null;
+
+alter table device_channel
+    change civilCode civil_code varchar(50) null;
+
+alter table device_channel
+    change parentId parent_id varchar(50) null;
+
+alter table device_channel
+    change safetyWay safety_way int null;
+
+alter table device_channel
+    change registerWay register_way int null;
+
+alter table device_channel
+    change certNum cert_num varchar(50) null;
+
+alter table device_channel
+    change errCode err_code int null;
+
+alter table device_channel
+    change endTime end_time varchar(50) null;
+
+alter table device_channel
+    change ipAddress ip_address varchar(50) null;
+
+alter table device_channel
+    change PTZType ptz_type int null;
+
+alter table device_channel
+    change status status bool default false;
+
+alter table device_channel
+    change streamId stream_id varchar(50) null;
+
+alter table device_channel
+    change deviceId device_id varchar(50) not null;
+
+
+alter table device_channel
+    change hasAudio has_audio bool default false;
+
+alter table device_channel
+    change createTime create_time varchar(50) not null;
+
+alter table device_channel
+    change updateTime update_time varchar(50) not null;
+
+alter table device_channel
+    change subCount sub_count int default 0 null;
+
+alter table device_channel
+    change longitudeGcj02 longitude_gcj02 double null;
+
+alter table device_channel
+    change latitudeGcj02 latitude_gcj02 double null;
+
+alter table device_channel
+    change longitudeWgs84 longitude_wgs84 double null;
+
+alter table device_channel
+    change latitudeWgs84 latitude_wgs84 double null;
+
+alter table device_channel
+    change businessGroupId business_group_id varchar(50) null;
+
+alter table device_channel
+    change gpsTime gps_time varchar(50) null;
+
+alter table device_mobile_position
+    change deviceId device_id varchar(50) not null;
+
+alter table device_mobile_position
+    change channelId channel_id varchar(50) not null;
+
+alter table device_mobile_position
+    change deviceName device_name varchar(255) null;
+
+alter table device_mobile_position
+    change reportSource report_source varchar(50) null;
+
+alter table device_mobile_position
+    change longitudeGcj02 longitude_gcj02 double null;
+
+alter table device_mobile_position
+    change latitudeGcj02 latitude_gcj02 double null;
+
+alter table device_mobile_position
+    change longitudeWgs84 longitude_wgs84 double null;
+
+alter table device_mobile_position
+    change latitudeWgs84 latitude_wgs84 double null;
+
+alter table device_mobile_position
+    change createTime create_time varchar(50) null;
+
+alter table gb_stream
+    change gbStreamId gb_stream_id int auto_increment;
+
+alter table gb_stream
+    change gbId gb_id varchar(50) not null;
+
+alter table gb_stream
+    change streamType stream_type varchar(50) null;
+
+alter table gb_stream
+    change mediaServerId media_server_id varchar(50) null;
+
+alter table gb_stream
+    change createTime create_time varchar(50) null;
+
+alter table log
+    change createTime create_time varchar(50) not null;
+
+alter table media_server
+    change hookIp hook_ip varchar(50) not null;
+
+alter table media_server
+    change sdpIp sdp_ip varchar(50) not null;
+
+alter table media_server
+    change streamIp stream_ip varchar(50) not null;
+
+alter table media_server
+    change httpPort http_port int not null;
+
+alter table media_server
+    change httpSSlPort http_ssl_port int not null;
+
+alter table media_server
+    change rtmpPort rtmp_port int not null;
+
+alter table media_server
+    change rtmpSSlPort rtmp_ssl_port int not null;
+
+alter table media_server
+    change rtpProxyPort rtp_proxy_port int not null;
+
+alter table media_server
+    change rtspPort rtsp_port int not null;
+
+alter table media_server
+    change rtspSSLPort rtsp_ssl_port int not null;
+
+alter table media_server
+    change autoConfig auto_config bool default true;
+
+alter table media_server
+    change rtpEnable rtp_enable bool default false;
+
+alter table media_server
+    change rtpPortRange rtp_port_range varchar(50) not null;
+
+alter table media_server
+    change recordAssistPort record_assist_port int not null;
+
+alter table media_server
+    change defaultServer default_server bool default false;
+
+alter table media_server
+    change createTime create_time varchar(50) not null;
+
+alter table media_server
+    change updateTime update_time varchar(50) not null;
+
+alter table media_server
+    change hookAliveInterval hook_alive_interval int not null;
+
+alter table parent_platform
+    change serverGBId server_gb_id varchar(50) not null;
+
+alter table parent_platform
+    change serverGBDomain server_gb_domain varchar(50) null;
+
+alter table parent_platform
+    change serverIP server_ip varchar(50) null;
+
+alter table parent_platform
+    change serverPort server_port int null;
+
+alter table parent_platform
+    change deviceGBId device_gb_id varchar(50) not null;
+
+alter table parent_platform
+    change deviceIp device_ip varchar(50) null;
+
+alter table parent_platform
+    change devicePort device_port varchar(50) null;
+
+alter table parent_platform
+    change keepTimeout keep_timeout varchar(50) null;
+
+alter table parent_platform
+    change characterSet character_set varchar(50) null;
+
+alter table parent_platform
+    change catalogId catalog_id varchar(50) not null;
+
+alter table parent_platform
+    change startOfflinePush start_offline_push bool default false;
+
+alter table parent_platform
+    change administrativeDivision administrative_division varchar(50) not null;
+
+alter table parent_platform
+    change catalogGroup catalog_group int default 1 null;
+
+alter table parent_platform
+    change createTime create_time varchar(50) null;
+
+alter table parent_platform
+    change updateTime update_time varchar(50) null;
+
+alter table parent_platform
+    drop column treeType;
+
+alter table parent_platform
+    change asMessageChannel as_message_channel bool default false;
+
+alter table parent_platform
+    change enable enable bool default false;
+
+alter table parent_platform
+    change ptz ptz bool default false;
+
+alter table parent_platform
+    change rtcp rtcp bool default false;
+
+alter table parent_platform
+    change status status bool default false;
+
+alter table parent_platform
+    change status status bool default false;
+
+alter table platform_catalog
+    change platformId platform_id varchar(50) not null;
+
+alter table platform_catalog
+    change parentId parent_id varchar(50) null;
+
+alter table platform_catalog
+    change civilCode civil_code varchar(50) null;
+
+alter table platform_catalog
+    change businessGroupId business_group_id varchar(50) null;
+
+alter table platform_gb_channel
+    change platformId platform_id varchar(50) not null;
+
+alter table platform_gb_channel
+    change catalogId catalog_id varchar(50) not null;
+
+alter table platform_gb_channel
+    change deviceChannelId device_channel_id int not null;
+
+alter table platform_gb_stream
+    change platformId platform_id varchar(50) not null;
+
+alter table platform_gb_stream
+    change catalogId catalog_id varchar(50) not null;
+
+alter table platform_gb_stream
+    change gbStreamId gb_stream_id int not null;
+
+alter table stream_proxy
+    change mediaServerId media_server_id varchar(50) null;
+
+alter table stream_proxy
+    change createTime create_time varchar(50) not null;
+
+alter table stream_proxy
+    change updateTime update_time varchar(50) null;
+
+alter table stream_proxy
+    change enable_remove_none_reader enable_remove_none_reader bool default false;
+
+alter table stream_proxy
+    change enable_disable_none_reader enable_disable_none_reader bool default false;
+
+alter table stream_proxy
+    change enable_audio enable_audio bool default false;
+
+alter table stream_proxy
+    change enable_mp4 enable_mp4 bool default false;
+
+alter table stream_proxy
+    change enable enable bool default false;
+
+alter table stream_push
+    change totalReaderCount total_reader_count varchar(50) null;
+
+alter table stream_push
+    change originType origin_type int null;
+
+alter table stream_push
+    change originTypeStr origin_type_str varchar(50) null;
+
+alter table stream_push
+    change createTime create_time varchar(50) null;
+
+alter table stream_push
+    change aliveSecond alive_second int null;
+
+alter table stream_push
+    change mediaServerId media_server_id varchar(50) null;
+
+alter table stream_push
+    change status status bool default false;
+
+alter table stream_push
+    change pushTime push_time varchar(50) null;
+
+alter table stream_push
+    change updateTime update_time varchar(50) null;
+
+alter table stream_push
+    change pushIng push_ing bool default false;
+
+alter table stream_push
+    change status status bool default false;
+
+alter table stream_push
+    change self self bool default false;
+
+alter table stream_push
+    drop column serverId;
+
+
+alter table user
+    change roleId role_id int not null;
+
+alter table user
+    change createTime create_time varchar(50) not null;
+
+alter table user
+    change updateTime update_time varchar(50) not null;
+
+alter table user
+    change pushKey push_key varchar(50) null;
+
+alter table user_role
+    change createTime create_time varchar(50) not null;
+
+alter table user_role
+    change updateTime update_time varchar(50) not null;
+
+rename table device to wvp_device;
+rename table device_alarm to wvp_device_alarm;
+rename table device_channel to wvp_device_channel;
+rename table device_mobile_position to wvp_device_mobile_position;
+rename table gb_stream to wvp_gb_stream;
+rename table log to wvp_log;
+rename table media_server to wvp_media_server;
+rename table parent_platform to wvp_platform;
+rename table platform_catalog to wvp_platform_catalog;
+rename table platform_gb_channel to wvp_platform_gb_channel;
+rename table platform_gb_stream to wvp_platform_gb_stream;
+rename table stream_proxy to wvp_stream_proxy;
+rename table stream_push to wvp_stream_push;
+rename table user to wvp_user;
+rename table user_role to wvp_user_role;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

+ 13 - 13
sql/clean.sql

@@ -1,13 +1,13 @@
-delete from  device;
-delete from  device_alarm;
-delete from  device_channel;
-delete from  device_mobile_position;
-delete from  gb_stream;
-delete from  log;
-delete from  media_server;
-delete from  parent_platform;
-delete from  platform_catalog;
-delete from  platform_gb_channel;
-delete from  platform_gb_stream;
-delete from  stream_proxy;
-delete from  stream_push;
+delete from  wvp-device;
+delete from  wvp-device_alarm;
+delete from  wvp-device_channel;
+delete from  wvp-device_mobile_position;
+delete from  wvp-gb_stream;
+delete from  wvp-log;
+delete from  wvp-media_server;
+delete from  wvp-parent_platform;
+delete from  wvp-platform_catalog;
+delete from  wvp-platform_gb_channel;
+delete from  wvp-platform_gb_stream;
+delete from  wvp-stream_proxy;
+delete from  wvp-stream_push;

+ 283 - 542
sql/初始化.sql

@@ -1,580 +1,286 @@
---
+/*建表*/
+create table wvp_device (
+                            id serial primary key ,
+                            device_id character varying(50) not null ,
+                            name character varying(255),
+                            manufacturer character varying(255),
+                            model character varying(255),
+                            firmware character varying(255),
+                            transport character varying(50),
+                            stream_mode character varying(50),
+                            on_line bool default false,
+                            register_time character varying(50),
+                            keepalive_time character varying(50),
+                            ip character varying(50),
+                            create_time character varying(50),
+                            update_time character varying(50),
+                            port integer,
+                            expires integer,
+                            subscribe_cycle_for_catalog integer DEFAULT 0,
+                            subscribe_cycle_for_mobile_position integer DEFAULT 0,
+                            mobile_position_submission_interval integer DEFAULT 5,
+                            subscribe_cycle_for_alarm integer DEFAULT 0,
+                            host_address character varying(50),
+                            charset character varying(50),
+                            ssrc_check bool default false,
+                            geo_coord_sys character varying(50),
+                            media_server_id character varying(50),
+                            custom_name character varying(255),
+                            sdp_ip character varying(50),
+                            local_ip character varying(50),
+                            password character varying(255),
+                            as_message_channel bool default false,
+                            keepalive_interval_time integer,
+                            switch_primary_sub_stream bool default false,
+                            constraint uk_device_device unique (device_id)
+);
+
+create table wvp_device_alarm (
+                                  id serial primary key ,
+                                  device_id character varying(50) not null,
+                                  channel_id character varying(50) not null,
+                                  alarm_priority character varying(50),
+                                  alarm_method character varying(50),
+                                  alarm_time character varying(50),
+                                  alarm_description character varying(255),
+                                  longitude double precision,
+                                  latitude double precision,
+                                  alarm_type character varying(50),
+                                  create_time character varying(50) not null
+);
+
+create table wvp_device_channel (
+                                    id serial primary key ,
+                                    channel_id character varying(50) not null,
+                                    name character varying(255),
+                                    manufacture character varying(50),
+                                    model character varying(50),
+                                    owner character varying(50),
+                                    civil_code character varying(50),
+                                    block character varying(50),
+                                    address character varying(50),
+                                    parent_id character varying(50),
+                                    safety_way integer,
+                                    register_way integer,
+                                    cert_num character varying(50),
+                                    certifiable integer,
+                                    err_code integer,
+                                    end_time character varying(50),
+                                    secrecy character varying(50),
+                                    ip_address character varying(50),
+                                    port integer,
+                                    password character varying(255),
+                                    ptz_type integer,
+                                    status bool default false,
+                                    longitude double precision,
+                                    latitude double precision,
+                                    stream_id character varying(50),
+                                    device_id character varying(50) not null,
+                                    parental character varying(50),
+                                    has_audio bool default false,
+                                    create_time character varying(50) not null,
+                                    update_time character varying(50) not null,
+                                    sub_count integer,
+                                    longitude_gcj02 double precision,
+                                    latitude_gcj02 double precision,
+                                    longitude_wgs84 double precision,
+                                    latitude_wgs84 double precision,
+                                    business_group_id character varying(50),
+                                    gps_time character varying(50),
+                                    constraint uk_wvp_device_channel_unique_device_channel unique (device_id, channel_id)
+);
+
+create table wvp_device_mobile_position (
+                                            id serial primary key,
+                                            device_id character varying(50) not null,
+                                            channel_id character varying(50) not null,
+                                            device_name character varying(255),
+                                            time character varying(50),
+                                            longitude double precision,
+                                            latitude double precision,
+                                            altitude double precision,
+                                            speed double precision,
+                                            direction double precision,
+                                            report_source character varying(50),
+                                            longitude_gcj02 double precision,
+                                            latitude_gcj02 double precision,
+                                            longitude_wgs84 double precision,
+                                            latitude_wgs84 double precision,
+                                            create_time character varying(50)
+);
+
+create table wvp_gb_stream (
+                               gb_stream_id serial primary key,
+                               app character varying(255) not null,
+                               stream character varying(255) not null,
+                               gb_id character varying(50) not null,
+                               name character varying(255),
+                               longitude double precision,
+                               latitude double precision,
+                               stream_type character varying(50),
+                               media_server_id character varying(50),
+                               create_time character varying(50),
+                               constraint uk_gb_stream_unique_gb_id unique (gb_id),
+                               constraint uk_gb_stream_unique_app_stream unique (app, stream)
+);
+
+create table wvp_log (
+                         id serial primary key ,
+                         name character varying(50),
+                         type character varying(50),
+                         uri character varying(200),
+                         address character varying(50),
+                         result character varying(50),
+                         timing bigint,
+                         username character varying(50),
+                         create_time character varying(50)
+);
+
+create table wvp_media_server (
+                                  id character varying(255) primary key ,
+                                  ip character varying(50),
+                                  hook_ip character varying(50),
+                                  sdp_ip character varying(50),
+                                  stream_ip character varying(50),
+                                  http_port integer,
+                                  http_ssl_port integer,
+                                  rtmp_port integer,
+                                  rtmp_ssl_port integer,
+                                  rtp_proxy_port integer,
+                                  rtsp_port integer,
+                                  rtsp_ssl_port integer,
+                                  auto_config bool default false,
+                                  secret character varying(50),
+                                  rtp_enable bool default false,
+                                  rtp_port_range character varying(50),
+                                  record_assist_port integer,
+                                  default_server bool default false,
+                                  create_time character varying(50),
+                                  update_time character varying(50),
+                                  hook_alive_interval integer,
+                                  constraint uk_media_server_unique_ip_http_port unique (ip, http_port)
+);
+
+create table wvp_platform (
+                              id serial primary key ,
+                              enable bool default false,
+                              name character varying(255),
+                              server_gb_id character varying(50),
+                              server_gb_domain character varying(50),
+                              server_ip character varying(50),
+                              server_port integer,
+                              device_gb_id character varying(50),
+                              device_ip character varying(50),
+                              device_port character varying(50),
+                              username character varying(255),
+                              password character varying(50),
+                              expires character varying(50),
+                              keep_timeout character varying(50),
+                              transport character varying(50),
+                              character_set character varying(50),
+                              catalog_id character varying(50),
+                              ptz bool default false,
+                              rtcp bool default false,
+                              status bool default false,
+                              start_offline_push bool default false,
+                              administrative_division character varying(50),
+                              catalog_group integer,
+                              create_time character varying(50),
+                              update_time character varying(50),
+                              as_message_channel bool default false,
+                              constraint uk_platform_unique_server_gb_id unique (server_gb_id)
+);
+
+create table wvp_platform_catalog (
+                                      id character varying(50),
+                                      platform_id character varying(50),
+                                      name character varying(255),
+                                      parent_id character varying(50),
+                                      civil_code character varying(50),
+                                      business_group_id character varying(50),
+                                      constraint uk_platform_catalog_id_platform_id unique (id, platform_id)
+);
+
+create table wvp_platform_gb_channel (
+                                         id serial primary key ,
+                                         platform_id character varying(50),
+                                         catalog_id character varying(50),
+                                         device_channel_id integer,
+                                         constraint uk_platform_gb_channel_platform_id_catalog_id_device_channel_id unique (platform_id, catalog_id, device_channel_id)
+);
+
+create table wvp_platform_gb_stream (
+                                        id serial primary key,
+                                        platform_id character varying(50),
+                                        catalog_id character varying(50),
+                                        gb_stream_id integer,
+                                        constraint uk_platform_gb_stream_platform_id_catalog_id_gb_stream_id unique (platform_id, catalog_id, gb_stream_id)
+);
+
+create table wvp_stream_proxy (
+                                  id serial primary key,
+                                  type character varying(50),
+                                  app character varying(255),
+                                  stream character varying(255),
+                                  url character varying(255),
+                                  src_url character varying(255),
+                                  dst_url character varying(255),
+                                  timeout_ms integer,
+                                  ffmpeg_cmd_key character varying(255),
+                                  rtp_type character varying(50),
+                                  media_server_id character varying(50),
+                                  enable_audio bool default false,
+                                  enable_mp4 bool default false,
+                                  enable bool default false,
+                                  status boolean,
+                                  enable_remove_none_reader bool default false,
+                                  create_time character varying(50),
+                                  name character varying(255),
+                                  update_time character varying(50),
+                                  enable_disable_none_reader bool default false,
+                                  constraint uk_stream_proxy_app_stream unique (app, stream)
+);
+
+create table wvp_stream_push (
+                                 id serial primary key,
+                                 app character varying(255),
+                                 stream character varying(255),
+                                 total_reader_count character varying(50),
+                                 origin_type integer,
+                                 origin_type_str character varying(50),
+                                 create_time character varying(50),
+                                 alive_second integer,
+                                 media_server_id character varying(50),
+                                 push_time character varying(50),
+                                 status bool default false,
+                                 update_time character varying(50),
+                                 push_ing bool default false,
+                                 self bool default false,
+                                 constraint uk_stream_push_app_stream unique (app, stream)
+);
+
+create table wvp_user (
+                          id serial primary key,
+                          username character varying(255),
+                          password character varying(255),
+                          role_id integer,
+                          create_time character varying(50),
+                          update_time character varying(50),
+                          push_key character varying(50),
+                          constraint uk_user_username unique (username)
+);
+
+create table wvp_user_role (
+                               id serial primary key,
+                               name character varying(50),
+                               authority character varying(50),
+                               create_time character varying(50),
+                               update_time character varying(50)
+);
+
+/*初始数据*/
+INSERT INTO wvp_user VALUES (1, 'admin','21232f297a57a5a743894a0e4a801fc3',1,'2021-04-13 14:14:57','2021-04-13 14:14:57','3e80d1762a324d5b0ff636e0bd16f1e3');
+INSERT INTO wvp_user_role VALUES (1, 'admin','0','2021-04-13 14:14:57','2021-04-13 14:14:57');
 
-/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
-/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
-/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
-/*!50503 SET NAMES utf8mb4 */;
-/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
-/*!40103 SET TIME_ZONE='+00:00' */;
-/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
-/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
-/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
-/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
 
---
---
 
-DROP TABLE IF EXISTS `device`;
-/*!40101 SET @saved_cs_client     = @@character_set_client */;
-/*!50503 SET character_set_client = utf8mb4 */;
-CREATE TABLE `device` (
-                          `id` int NOT NULL AUTO_INCREMENT,
-                          `deviceId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
-                          `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
-                          `manufacturer` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
-                          `model` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
-                          `firmware` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
-                          `transport` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
-                          `streamMode` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
-                          `online` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
-                          `mediaServerId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
-                          `registerTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
-                          `keepaliveTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
-                          `ip` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
-                          `createTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
-                          `updateTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
-                          `port` int DEFAULT NULL,
-                          `expires` int DEFAULT NULL,
-                          `keepaliveIntervalTime` int DEFAULT NULL,
-                          `subscribeCycleForCatalog` int DEFAULT NULL,
-                          `hostAddress` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
-                          `charset` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
-                          `subscribeCycleForMobilePosition` int DEFAULT NULL,
-                          `mobilePositionSubmissionInterval` int DEFAULT '5',
-                          `subscribeCycleForAlarm` int DEFAULT NULL,
-                          `ssrcCheck` int DEFAULT '0',
-                          `asMessageChannel` int DEFAULT '0',
-                          `geoCoordSys` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
-                          `treeType` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
-                          `custom_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
-                          `password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
-                          `sdpIp` varchar(50) COLLATE utf8mb4_general_ci DEFAULT NULL,
-                          `localIp` varchar(50) COLLATE utf8mb4_general_ci DEFAULT NULL,
-                          PRIMARY KEY (`id`),
-                          UNIQUE KEY `device_deviceId_uindex` (`deviceId`)
-) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
---
-
-LOCK TABLES `device` WRITE;
-/*!40000 ALTER TABLE `device` DISABLE KEYS */;
-/*!40000 ALTER TABLE `device` ENABLE KEYS */;
-UNLOCK TABLES;
-
---
---
-
-DROP TABLE IF EXISTS `device_alarm`;
-/*!40101 SET @saved_cs_client     = @@character_set_client */;
-/*!50503 SET character_set_client = utf8mb4 */;
-CREATE TABLE `device_alarm` (
-                                `id` int NOT NULL AUTO_INCREMENT,
-                                `deviceId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
-                                `channelId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
-                                `alarmPriority` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
-                                `alarmMethod` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
-                                `alarmTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
-                                `alarmDescription` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
-                                `longitude` double DEFAULT NULL,
-                                `latitude` double DEFAULT NULL,
-                                `alarmType` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
-                                `createTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
-                                PRIMARY KEY (`id`) USING BTREE
-) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
---
-
-LOCK TABLES `device_alarm` WRITE;
-/*!40000 ALTER TABLE `device_alarm` DISABLE KEYS */;
-/*!40000 ALTER TABLE `device_alarm` ENABLE KEYS */;
-UNLOCK TABLES;
-
---
---
-
-DROP TABLE IF EXISTS `device_channel`;
-/*!40101 SET @saved_cs_client     = @@character_set_client */;
-/*!50503 SET character_set_client = utf8mb4 */;
-CREATE TABLE `device_channel` (
-                                  `id` int NOT NULL AUTO_INCREMENT,
-                                  `channelId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
-                                  `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
-                                  `manufacture` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
-                                  `model` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
-                                  `owner` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
-                                  `civilCode` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
-                                  `block` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
-                                  `address` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
-                                  `parentId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
-                                  `safetyWay` int DEFAULT NULL,
-                                  `registerWay` int DEFAULT NULL,
-                                  `certNum` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
-                                  `certifiable` int DEFAULT NULL,
-                                  `errCode` int DEFAULT NULL,
-                                  `endTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
-                                  `secrecy` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
-                                  `ipAddress` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
-                                  `port` int DEFAULT NULL,
-                                  `password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
-                                  `PTZType` int DEFAULT NULL,
-                                  `status` int DEFAULT NULL,
-                                  `longitude` double DEFAULT NULL,
-                                  `latitude` double DEFAULT NULL,
-                                  `streamId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
-                                  `deviceId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
-                                  `parental` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
-                                  `hasAudio` bit(1) DEFAULT NULL,
-                                  `createTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
-                                  `updateTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
-                                  `subCount` int DEFAULT '0',
-                                  `longitudeGcj02` double DEFAULT NULL,
-                                  `latitudeGcj02` double DEFAULT NULL,
-                                  `longitudeWgs84` double DEFAULT NULL,
-                                  `latitudeWgs84` double DEFAULT NULL,
-                                  `businessGroupId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
-                                  `gpsTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
-                                  PRIMARY KEY (`id`),
-                                  UNIQUE KEY `device_channel_id_uindex` (`id`),
-                                  UNIQUE KEY `device_channel_pk` (`channelId`,`deviceId`)
-) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
---
-
-LOCK TABLES `device_channel` WRITE;
-/*!40000 ALTER TABLE `device_channel` DISABLE KEYS */;
-/*!40000 ALTER TABLE `device_channel` ENABLE KEYS */;
-UNLOCK TABLES;
-
---
---
-
-DROP TABLE IF EXISTS `device_mobile_position`;
-/*!40101 SET @saved_cs_client     = @@character_set_client */;
-/*!50503 SET character_set_client = utf8mb4 */;
-CREATE TABLE `device_mobile_position` (
-                                          `id` int NOT NULL AUTO_INCREMENT,
-                                          `deviceId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
-                                          `channelId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
-                                          `deviceName` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
-                                          `time` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
-                                          `longitude` double NOT NULL,
-                                          `latitude` double NOT NULL,
-                                          `altitude` double DEFAULT NULL,
-                                          `speed` double DEFAULT NULL,
-                                          `direction` double DEFAULT NULL,
-                                          `reportSource` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
-                                          `longitudeGcj02` double DEFAULT NULL,
-                                          `latitudeGcj02` double DEFAULT NULL,
-                                          `longitudeWgs84` double DEFAULT NULL,
-                                          `latitudeWgs84` double DEFAULT NULL,
-                                          `createTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
-                                          PRIMARY KEY (`id`)
-) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
---
-
-LOCK TABLES `device_mobile_position` WRITE;
-/*!40000 ALTER TABLE `device_mobile_position` DISABLE KEYS */;
-/*!40000 ALTER TABLE `device_mobile_position` ENABLE KEYS */;
-UNLOCK TABLES;
-
---
---
-
-DROP TABLE IF EXISTS `gb_stream`;
-/*!40101 SET @saved_cs_client     = @@character_set_client */;
-/*!50503 SET character_set_client = utf8mb4 */;
-CREATE TABLE `gb_stream` (
-                             `gbStreamId` int NOT NULL AUTO_INCREMENT,
-                             `app` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
-                             `stream` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
-                             `gbId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
-                             `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
-                             `longitude` double DEFAULT NULL,
-                             `latitude` double DEFAULT NULL,
-                             `streamType` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
-                             `mediaServerId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
-                             `createTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
-                             PRIMARY KEY (`gbStreamId`) USING BTREE,
-                             UNIQUE KEY `app` (`app`,`stream`) USING BTREE,
-                             UNIQUE KEY `gbId` (`gbId`) USING BTREE
-) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
---
-
-LOCK TABLES `gb_stream` WRITE;
-/*!40000 ALTER TABLE `gb_stream` DISABLE KEYS */;
-/*!40000 ALTER TABLE `gb_stream` ENABLE KEYS */;
-UNLOCK TABLES;
-
---
---
-
-DROP TABLE IF EXISTS `log`;
-/*!40101 SET @saved_cs_client     = @@character_set_client */;
-/*!50503 SET character_set_client = utf8mb4 */;
-CREATE TABLE `log` (
-                       `id` int NOT NULL AUTO_INCREMENT,
-                       `name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
-                       `type` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
-                       `uri` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
-                       `address` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
-                       `result` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
-                       `timing` bigint NOT NULL,
-                       `username` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
-                       `createTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
-                       PRIMARY KEY (`id`) USING BTREE
-) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
---
-
-LOCK TABLES `log` WRITE;
-/*!40000 ALTER TABLE `log` DISABLE KEYS */;
-/*!40000 ALTER TABLE `log` ENABLE KEYS */;
-UNLOCK TABLES;
-
---
---
-
-DROP TABLE IF EXISTS `media_server`;
-/*!40101 SET @saved_cs_client     = @@character_set_client */;
-/*!50503 SET character_set_client = utf8mb4 */;
-CREATE TABLE `media_server` (
-                                `id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
-                                `ip` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
-                                `hookIp` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
-                                `sdpIp` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
-                                `streamIp` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
-                                `httpPort` int NOT NULL,
-                                `httpSSlPort` int NOT NULL,
-                                `rtmpPort` int NOT NULL,
-                                `rtmpSSlPort` int NOT NULL,
-                                `rtpProxyPort` int NOT NULL,
-                                `rtspPort` int NOT NULL,
-                                `rtspSSLPort` int NOT NULL,
-                                `autoConfig` int NOT NULL,
-                                `secret` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
-                                `rtpEnable` int NOT NULL,
-                                `rtpPortRange` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
-                                `recordAssistPort` int NOT NULL,
-                                `defaultServer` int NOT NULL,
-                                `createTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
-                                `updateTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
-                                `hookAliveInterval` int NOT NULL,
-                                PRIMARY KEY (`id`) USING BTREE,
-                                UNIQUE KEY `media_server_i` (`ip`,`httpPort`) USING BTREE
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
---
-
-LOCK TABLES `media_server` WRITE;
-/*!40000 ALTER TABLE `media_server` DISABLE KEYS */;
-/*!40000 ALTER TABLE `media_server` ENABLE KEYS */;
-UNLOCK TABLES;
-
---
---
-
-DROP TABLE IF EXISTS `parent_platform`;
-/*!40101 SET @saved_cs_client     = @@character_set_client */;
-/*!50503 SET character_set_client = utf8mb4 */;
-CREATE TABLE `parent_platform` (
-                                   `id` int NOT NULL AUTO_INCREMENT,
-                                   `enable` int DEFAULT NULL,
-                                   `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
-                                   `serverGBId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
-                                   `serverGBDomain` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
-                                   `serverIP` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
-                                   `serverPort` int DEFAULT NULL,
-                                   `deviceGBId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
-                                   `deviceIp` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
-                                   `devicePort` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
-                                   `username` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
-                                   `password` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
-                                   `expires` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
-                                   `keepTimeout` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
-                                   `transport` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
-                                   `characterSet` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
-                                   `catalogId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
-                                   `ptz` int DEFAULT NULL,
-                                   `rtcp` int DEFAULT NULL,
-                                   `asMessageChannel` int DEFAULT '0',
-                                   `status` bit(1) DEFAULT NULL,
-                                   `startOfflinePush` int DEFAULT '0',
-                                   `administrativeDivision` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
-                                   `catalogGroup` int DEFAULT '1',
-                                   `createTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
-                                   `updateTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
-                                   `treeType` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
-                                   PRIMARY KEY (`id`),
-                                   UNIQUE KEY `parent_platform_id_uindex` (`id`),
-                                   UNIQUE KEY `parent_platform_pk` (`serverGBId`)
-) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
---
-
-LOCK TABLES `parent_platform` WRITE;
-/*!40000 ALTER TABLE `parent_platform` DISABLE KEYS */;
-/*!40000 ALTER TABLE `parent_platform` ENABLE KEYS */;
-UNLOCK TABLES;
-
---
---
-
-DROP TABLE IF EXISTS `platform_catalog`;
-/*!40101 SET @saved_cs_client     = @@character_set_client */;
-/*!50503 SET character_set_client = utf8mb4 */;
-CREATE TABLE `platform_catalog` (
-                                    `id` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
-                                    `platformId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
-                                    `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
-                                    `parentId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
-                                    `civilCode` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
-                                    `businessGroupId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
-                                    PRIMARY KEY (`id`) USING BTREE
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
---
-
-LOCK TABLES `platform_catalog` WRITE;
-/*!40000 ALTER TABLE `platform_catalog` DISABLE KEYS */;
-/*!40000 ALTER TABLE `platform_catalog` ENABLE KEYS */;
-UNLOCK TABLES;
-
---
---
-
-DROP TABLE IF EXISTS `platform_gb_channel`;
-/*!40101 SET @saved_cs_client     = @@character_set_client */;
-/*!50503 SET character_set_client = utf8mb4 */;
-CREATE TABLE `platform_gb_channel` (
-                                       `id` int NOT NULL AUTO_INCREMENT,
-                                       `platformId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
-                                       `catalogId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
-                                       `deviceChannelId` int NOT NULL,
-                                       PRIMARY KEY (`id`)
-) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
---
-
-LOCK TABLES `platform_gb_channel` WRITE;
-/*!40000 ALTER TABLE `platform_gb_channel` DISABLE KEYS */;
-/*!40000 ALTER TABLE `platform_gb_channel` ENABLE KEYS */;
-UNLOCK TABLES;
-
---
---
-
-DROP TABLE IF EXISTS `platform_gb_stream`;
-/*!40101 SET @saved_cs_client     = @@character_set_client */;
-/*!50503 SET character_set_client = utf8mb4 */;
-CREATE TABLE `platform_gb_stream` (
-                                      `id` int NOT NULL AUTO_INCREMENT,
-                                      `platformId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
-                                      `catalogId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
-                                      `gbStreamId` int NOT NULL,
-                                      PRIMARY KEY (`id`),
-                                      UNIQUE KEY `platform_gb_stream_pk` (`platformId`,`catalogId`,`gbStreamId`)
-) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
---
-
-LOCK TABLES `platform_gb_stream` WRITE;
-/*!40000 ALTER TABLE `platform_gb_stream` DISABLE KEYS */;
-/*!40000 ALTER TABLE `platform_gb_stream` ENABLE KEYS */;
-UNLOCK TABLES;
-
---
---
-
-DROP TABLE IF EXISTS `stream_proxy`;
-/*!40101 SET @saved_cs_client     = @@character_set_client */;
-/*!50503 SET character_set_client = utf8mb4 */;
-CREATE TABLE `stream_proxy` (
-                                `id` int NOT NULL AUTO_INCREMENT,
-                                `type` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
-                                `app` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
-                                `stream` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
-                                `url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
-                                `src_url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
-                                `dst_url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
-                                `timeout_ms` int DEFAULT NULL,
-                                `ffmpeg_cmd_key` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
-                                `rtp_type` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
-                                `mediaServerId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
-                                `enable_audio` bit(1) DEFAULT NULL,
-                                `enable_mp4` bit(1) DEFAULT NULL,
-                                `enable` bit(1) NOT NULL,
-                                `status` bit(1) NOT NULL,
-                                `enable_remove_none_reader` bit(1) NOT NULL,
-                                `createTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
-                                `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
-                                `updateTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
-                                `enable_disable_none_reader` bit(1) DEFAULT NULL,
-                                PRIMARY KEY (`id`),
-                                UNIQUE KEY `stream_proxy_pk` (`app`,`stream`)
-) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
---
-
-LOCK TABLES `stream_proxy` WRITE;
-/*!40000 ALTER TABLE `stream_proxy` DISABLE KEYS */;
-/*!40000 ALTER TABLE `stream_proxy` ENABLE KEYS */;
-UNLOCK TABLES;
-
---
---
-
-DROP TABLE IF EXISTS `stream_push`;
-/*!40101 SET @saved_cs_client     = @@character_set_client */;
-/*!50503 SET character_set_client = utf8mb4 */;
-CREATE TABLE `stream_push` (
-                               `id` int NOT NULL AUTO_INCREMENT,
-                               `app` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
-                               `stream` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
-                               `totalReaderCount` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
-                               `originType` int DEFAULT NULL,
-                               `originTypeStr` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
-                               `createTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
-                               `aliveSecond` int DEFAULT NULL,
-                               `mediaServerId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
-                               `serverId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
-                               `pushTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
-                               `status` int DEFAULT NULL,
-                               `updateTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
-                               `pushIng` int DEFAULT NULL,
-                               `self` int DEFAULT NULL,
-                               PRIMARY KEY (`id`),
-                               UNIQUE KEY `stream_push_pk` (`app`,`stream`)
-) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
---
-
-LOCK TABLES `stream_push` WRITE;
-/*!40000 ALTER TABLE `stream_push` DISABLE KEYS */;
-/*!40000 ALTER TABLE `stream_push` ENABLE KEYS */;
-UNLOCK TABLES;
-
---
---
-
-DROP TABLE IF EXISTS `user`;
-/*!40101 SET @saved_cs_client     = @@character_set_client */;
-/*!50503 SET character_set_client = utf8mb4 */;
-CREATE TABLE `user` (
-                        `id` int NOT NULL AUTO_INCREMENT,
-                        `username` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
-                        `password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
-                        `roleId` int NOT NULL,
-                        `createTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
-                        `updateTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
-                        `pushKey` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
-                        PRIMARY KEY (`id`) USING BTREE,
-                        UNIQUE KEY `user_username_uindex` (`username`) USING BTREE
-) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
---
-
-LOCK TABLES `user` WRITE;
-/*!40000 ALTER TABLE `user` DISABLE KEYS */;
-INSERT INTO `user` VALUES (1,'admin','21232f297a57a5a743894a0e4a801fc3',1,'2021-04-13 14:14:57','2021-04-13 14:14:57','3e80d1762a324d5b0ff636e0bd16f1e3');
-/*!40000 ALTER TABLE `user` ENABLE KEYS */;
-UNLOCK TABLES;
-
---
---
-
-DROP TABLE IF EXISTS `user_role`;
-/*!40101 SET @saved_cs_client     = @@character_set_client */;
-/*!50503 SET character_set_client = utf8mb4 */;
-CREATE TABLE `user_role` (
-                             `id` int NOT NULL AUTO_INCREMENT,
-                             `name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
-                             `authority` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
-                             `createTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
-                             `updateTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
-                             PRIMARY KEY (`id`) USING BTREE
-) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
---
-
-LOCK TABLES `user_role` WRITE;
-/*!40000 ALTER TABLE `user_role` DISABLE KEYS */;
-INSERT INTO `user_role` VALUES (1,'admin','0','2021-04-13 14:14:57','2021-04-13 14:14:57');
-/*!40000 ALTER TABLE `user_role` ENABLE KEYS */;
-UNLOCK TABLES;
-/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
-
-/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
-/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
-/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
-/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
-/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
-/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
-/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
-

+ 42 - 0
src/main/java/com/genersoft/iot/vmp/common/CivilCodePo.java

@@ -0,0 +1,42 @@
+package com.genersoft.iot.vmp.common;
+
+public class CivilCodePo {
+
+    private String code;
+
+    private String name;
+
+    private String parentCode;
+
+    public static CivilCodePo getInstance(String[] infoArray) {
+        CivilCodePo civilCodePo = new CivilCodePo();
+        civilCodePo.setCode(infoArray[0]);
+        civilCodePo.setName(infoArray[1]);
+        civilCodePo.setParentCode(infoArray[2]);
+        return civilCodePo;
+    }
+
+    public String getCode() {
+        return code;
+    }
+
+    public void setCode(String code) {
+        this.code = code;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getParentCode() {
+        return parentCode;
+    }
+
+    public void setParentCode(String parentCode) {
+        this.parentCode = parentCode;
+    }
+}

+ 5 - 0
src/main/java/com/genersoft/iot/vmp/common/GeneralCallback.java

@@ -0,0 +1,5 @@
+package com.genersoft.iot.vmp.common;
+
+public interface GeneralCallback<T>{
+    void run(int code, String msg, T data);
+}

+ 19 - 1
src/main/java/com/genersoft/iot/vmp/common/InviteInfo.java

@@ -1,6 +1,7 @@
 package com.genersoft.iot.vmp.common;
 
 import com.genersoft.iot.vmp.service.bean.SSRCInfo;
+import io.swagger.v3.oas.annotations.media.Schema;
 
 /**
  * 记录每次发送invite消息的状态
@@ -28,7 +29,7 @@ public class InviteInfo {
     private StreamInfo streamInfo;
 
 
-    public static InviteInfo getinviteInfo(String deviceId, String channelId, String stream, SSRCInfo ssrcInfo,
+    public static InviteInfo getInviteInfo(String deviceId, String channelId, String stream, SSRCInfo ssrcInfo,
                                            String receiveIp, Integer receivePort, String streamMode,
                                            InviteSessionType type, InviteSessionStatus status) {
         InviteInfo inviteInfo = new InviteInfo();
@@ -123,4 +124,21 @@ public class InviteInfo {
     public void setStreamMode(String streamMode) {
         this.streamMode = streamMode;
     }
+
+
+    /*=========================设备主子码流逻辑START====================*/
+    @Schema(description = "是否为子码流(true-是,false-主码流)")
+    private boolean subStream;
+
+    public boolean isSubStream() {
+        return subStream;
+    }
+
+    public void setSubStream(boolean subStream) {
+        this.subStream = subStream;
+    }
+
+
+
+
 }

+ 15 - 0
src/main/java/com/genersoft/iot/vmp/common/StreamInfo.java

@@ -528,4 +528,19 @@ public class StreamInfo implements Serializable, Cloneable{
         }
         return instance;
     }
+
+
+    /*=========================设备主子码流逻辑START====================*/
+    @Schema(description = "是否为子码流(true-是,false-主码流)")
+    private boolean subStream;
+
+    public boolean isSubStream() {
+        return subStream;
+    }
+
+    public void setSubStream(boolean subStream) {
+        this.subStream = subStream;
+    }
+
+
 }

+ 5 - 0
src/main/java/com/genersoft/iot/vmp/common/VideoManagerConstants.java

@@ -107,6 +107,11 @@ public class VideoManagerConstants {
 	 */
 	public static final String VM_MSG_STREAM_PUSH_RESPONSE = "VM_MSG_STREAM_PUSH_RESPONSE";
 
+	/**
+	 * redis 通知平台关闭推流
+	 */
+	public static final String VM_MSG_STREAM_PUSH_CLOSE = "VM_MSG_STREAM_PUSH_CLOSE";
+
 	/**
 	 * redis 消息请求所有的在线通道
 	 */

+ 101 - 0
src/main/java/com/genersoft/iot/vmp/conf/CivilCodeFileConf.java

@@ -0,0 +1,101 @@
+package com.genersoft.iot.vmp.conf;
+
+import com.genersoft.iot.vmp.common.CivilCodePo;
+import org.ehcache.impl.internal.concurrent.ConcurrentHashMap;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.CommandLineRunner;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Lazy;
+import org.springframework.core.annotation.Order;
+import org.springframework.core.io.ClassPathResource;
+import org.springframework.util.ObjectUtils;
+
+import java.io.*;
+import java.nio.file.Files;
+import java.util.Map;
+
+/**
+ * 启动时读取行政区划表
+ */
+@Configuration
+@Order(value=14)
+public class CivilCodeFileConf implements CommandLineRunner {
+
+    private final static Logger logger = LoggerFactory.getLogger(CivilCodeFileConf.class);
+
+    private final Map<String, CivilCodePo> civilCodeMap= new ConcurrentHashMap<>();
+
+    @Autowired
+    @Lazy
+    private UserSetting userSetting;
+
+    @Override
+    public void run(String... args) throws Exception {
+        if (ObjectUtils.isEmpty(userSetting.getCivilCodeFile())) {
+            logger.warn("[行政区划] 文件未设置,可能造成目录刷新结果不完整");
+            return;
+        }
+        InputStream inputStream;
+        if (userSetting.getCivilCodeFile().startsWith("classpath:")){
+            String filePath = userSetting.getCivilCodeFile().substring("classpath:".length());
+            ClassPathResource civilCodeFile = new ClassPathResource(filePath);
+            if (!civilCodeFile.exists()) {
+                logger.warn("[行政区划] 文件<{}>不存在,可能造成目录刷新结果不完整", userSetting.getCivilCodeFile());
+                return;
+            }
+            inputStream = civilCodeFile.getInputStream();
+
+        }else {
+            File civilCodeFile = new File(userSetting.getCivilCodeFile());
+            if (!civilCodeFile.exists()) {
+                logger.warn("[行政区划] 文件<{}>不存在,可能造成目录刷新结果不完整", userSetting.getCivilCodeFile());
+                return;
+            }
+            inputStream = Files.newInputStream(civilCodeFile.toPath());
+        }
+
+        BufferedReader inputStreamReader = new BufferedReader(new InputStreamReader(inputStream));
+        int index = -1;
+        String line;
+        while ((line = inputStreamReader.readLine()) != null) {
+            index ++;
+            if (index == 0) {
+                continue;
+            }
+            String[] infoArray = line.split(",");
+            CivilCodePo civilCodePo = CivilCodePo.getInstance(infoArray);
+            civilCodeMap.put(civilCodePo.getCode(), civilCodePo);
+        }
+        inputStreamReader.close();
+        inputStream.close();
+        if (civilCodeMap.size() == 0) {
+            logger.warn("[行政区划] 文件内容为空,可能造成目录刷新结果不完整");
+        }else {
+            logger.info("[行政区划] 加载成功,共加载数据{}条", civilCodeMap.size());
+        }
+    }
+
+    public CivilCodePo getParentCode(String code) {
+        if (code.length() > 8) {
+            return null;
+        }
+        if (code.length() == 8) {
+            String parentCode = code.substring(0, 6);
+            return civilCodeMap.get(parentCode);
+        }else {
+            CivilCodePo civilCodePo = civilCodeMap.get(code);
+            if (civilCodePo == null){
+                return null;
+            }
+            String parentCode = civilCodePo.getParentCode();
+            if (parentCode == null) {
+                return null;
+            }
+            return civilCodeMap.get(parentCode);
+        }
+
+    }
+
+}

+ 1 - 1
src/main/java/com/genersoft/iot/vmp/conf/MediaConfig.java

@@ -2,11 +2,11 @@ package com.genersoft.iot.vmp.conf;
 
 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
 import com.genersoft.iot.vmp.utils.DateUtil;
-import org.junit.jupiter.api.Order;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.context.annotation.Configuration;
+import org.springframework.core.annotation.Order;
 import org.springframework.util.ObjectUtils;
 
 import java.net.InetAddress;

+ 36 - 0
src/main/java/com/genersoft/iot/vmp/conf/MybatisConfig.java

@@ -0,0 +1,36 @@
+package com.genersoft.iot.vmp.conf;
+
+import org.apache.ibatis.logging.stdout.StdOutImpl;
+import org.apache.ibatis.session.SqlSessionFactory;
+import org.mybatis.spring.SqlSessionFactoryBean;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.annotation.Order;
+
+import javax.sql.DataSource;
+
+/**
+ * 配置mybatis
+ */
+@Configuration
+@Order(value=1)
+public class MybatisConfig {
+
+    @Autowired
+    private UserSetting userSetting;
+
+    @Bean
+    public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
+       final SqlSessionFactoryBean sqlSessionFactory = new SqlSessionFactoryBean();
+        sqlSessionFactory.setDataSource(dataSource);
+        org.apache.ibatis.session.Configuration config = new org.apache.ibatis.session.Configuration();
+        if (userSetting.getSqlLog()){
+            config.setLogImpl(StdOutImpl.class);
+        }
+        config.setMapUnderscoreToCamelCase(true);
+        sqlSessionFactory.setConfiguration(config);
+        return sqlSessionFactory.getObject();
+    }
+
+}

+ 1 - 1
src/main/java/com/genersoft/iot/vmp/conf/ProxyServletConfig.java

@@ -5,7 +5,7 @@ import com.genersoft.iot.vmp.service.IMediaServerService;
 import org.apache.http.HttpHost;
 import org.apache.http.HttpRequest;
 import org.apache.http.HttpResponse;
-import org.junit.jupiter.api.Order;
+import org.springframework.core.annotation.Order;
 import org.mitre.dsmiley.httpproxy.ProxyServlet;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;

+ 1 - 1
src/main/java/com/genersoft/iot/vmp/conf/SipConfig.java

@@ -1,7 +1,7 @@
 package com.genersoft.iot.vmp.conf;
 
 
-import org.junit.jupiter.api.Order;
+import org.springframework.core.annotation.Order;
 import org.springframework.boot.context.properties.ConfigurationProperties;
 import org.springframework.stereotype.Component;
 

+ 1 - 1
src/main/java/com/genersoft/iot/vmp/conf/SipPlatformRunner.java

@@ -56,7 +56,7 @@ public class SipPlatformRunner implements CommandLineRunner {
             }
 
             // 设置所有平台离线
-            platformService.offline(parentPlatform, true);
+            platformService.offline(parentPlatform, false);
         }
     }
 }

+ 1 - 1
src/main/java/com/genersoft/iot/vmp/conf/SpringDocConfig.java

@@ -4,7 +4,7 @@ import io.swagger.v3.oas.models.OpenAPI;
 import io.swagger.v3.oas.models.info.Contact;
 import io.swagger.v3.oas.models.info.Info;
 import io.swagger.v3.oas.models.info.License;
-import org.junit.jupiter.api.Order;
+import org.springframework.core.annotation.Order;
 import org.springdoc.core.GroupedOpenApi;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.context.annotation.Bean;

+ 1 - 1
src/main/java/com/genersoft/iot/vmp/conf/ThreadPoolTaskConfig.java

@@ -1,8 +1,8 @@
 package com.genersoft.iot.vmp.conf;
 
-import org.junit.jupiter.api.Order;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
+import org.springframework.core.annotation.Order;
 import org.springframework.scheduling.annotation.EnableAsync;
 import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
 

+ 40 - 1
src/main/java/com/genersoft/iot/vmp/conf/UserSetting.java

@@ -1,7 +1,7 @@
 package com.genersoft.iot.vmp.conf;
 
-import org.junit.jupiter.api.Order;
 import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.core.annotation.Order;
 import org.springframework.stereotype.Component;
 
 import java.util.ArrayList;
@@ -50,6 +50,7 @@ public class UserSetting {
     private Boolean pushStreamAfterAck = Boolean.FALSE;
 
     private Boolean sipLog = Boolean.FALSE;
+    private Boolean sqlLog = Boolean.FALSE;
     private Boolean sendToPlatformsWhenIdLost = Boolean.FALSE;
 
     private Boolean refuseChannelStatusChannelFormNotify = Boolean.FALSE;
@@ -65,12 +66,18 @@ public class UserSetting {
 
     private String broadcastForPlatform = "UDP";
 
+    private String civilCodeFile = "classpath:civilCode.csv";
+
     private List<String> interfaceAuthenticationExcludes = new ArrayList<>();
 
     private List<String> allowedOrigins = new ArrayList<>();
 
     private int maxNotifyCountQueue = 10000;
 
+    private int registerAgainAfterTime = 60;
+
+    private boolean registerKeepIntDialog = false;
+
     public Boolean getSavePositionHistory() {
         return savePositionHistory;
     }
@@ -306,4 +313,36 @@ public class UserSetting {
     public void setUseCustomSsrcForParentInvite(Boolean useCustomSsrcForParentInvite) {
         this.useCustomSsrcForParentInvite = useCustomSsrcForParentInvite;
     }
+
+    public Boolean getSqlLog() {
+        return sqlLog;
+    }
+
+    public void setSqlLog(Boolean sqlLog) {
+        this.sqlLog = sqlLog;
+    }
+
+    public String getCivilCodeFile() {
+        return civilCodeFile;
+    }
+
+    public void setCivilCodeFile(String civilCodeFile) {
+        this.civilCodeFile = civilCodeFile;
+    }
+
+    public int getRegisterAgainAfterTime() {
+        return registerAgainAfterTime;
+    }
+
+    public void setRegisterAgainAfterTime(int registerAgainAfterTime) {
+        this.registerAgainAfterTime = registerAgainAfterTime;
+    }
+
+    public boolean isRegisterKeepIntDialog() {
+        return registerKeepIntDialog;
+    }
+
+    public void setRegisterKeepIntDialog(boolean registerKeepIntDialog) {
+        this.registerKeepIntDialog = registerKeepIntDialog;
+    }
 }

+ 1 - 1
src/main/java/com/genersoft/iot/vmp/conf/VersionConfig.java

@@ -1,6 +1,6 @@
 package com.genersoft.iot.vmp.conf;
 
-import org.junit.jupiter.api.Order;
+import org.springframework.core.annotation.Order;
 import org.springframework.boot.context.properties.ConfigurationProperties;
 import org.springframework.stereotype.Component;
 

+ 4 - 0
src/main/java/com/genersoft/iot/vmp/conf/redis/RedisMsgListenConfig.java

@@ -43,6 +43,9 @@ public class RedisMsgListenConfig {
 	@Autowired
 	private RedisPushStreamResponseListener redisPushStreamResponseListener;
 
+	@Autowired
+	private RedisCloseStreamMsgListener redisCloseStreamMsgListener;
+
 
 	/**
 	 * redis消息监听器容器 可以添加多个监听不同话题的redis监听器,只需要把消息监听器和相应的消息订阅处理器绑定,该消息监听器
@@ -63,6 +66,7 @@ public class RedisMsgListenConfig {
 		container.addMessageListener(redisPushStreamStatusMsgListener, new PatternTopic(VideoManagerConstants.VM_MSG_PUSH_STREAM_STATUS_CHANGE));
 		container.addMessageListener(redisPushStreamListMsgListener, new PatternTopic(VideoManagerConstants.VM_MSG_PUSH_STREAM_LIST_CHANGE));
 		container.addMessageListener(redisPushStreamResponseListener, new PatternTopic(VideoManagerConstants.VM_MSG_STREAM_PUSH_RESPONSE));
+		container.addMessageListener(redisCloseStreamMsgListener, new PatternTopic(VideoManagerConstants.VM_MSG_STREAM_PUSH_CLOSE));
         return container;
     }
 }

+ 4 - 0
src/main/java/com/genersoft/iot/vmp/conf/security/AnonymousAuthenticationEntryPoint.java

@@ -3,6 +3,7 @@ package com.genersoft.iot.vmp.conf.security;
 import com.alibaba.fastjson2.JSONObject;
 import com.genersoft.iot.vmp.conf.security.dto.JwtUser;
 import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
+import org.springframework.http.MediaType;
 import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
 import org.springframework.security.core.AuthenticationException;
 import org.springframework.security.core.context.SecurityContextHolder;
@@ -12,6 +13,7 @@ import org.springframework.stereotype.Component;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import java.io.IOException;
+import java.nio.charset.StandardCharsets;
 
 /**
  * 处理匿名用户访问逻辑
@@ -35,6 +37,8 @@ public class    AnonymousAuthenticationEntryPoint implements AuthenticationEntry
             jsonObject.put("msg", e.getMessage());
         }
         response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
+        response.setContentType(MediaType.APPLICATION_JSON_VALUE);
+        response.setCharacterEncoding(StandardCharsets.UTF_8.name());
         try {
             response.getWriter().print(jsonObject.toJSONString());
         } catch (IOException ioException) {

+ 1 - 1
src/main/java/com/genersoft/iot/vmp/conf/security/WebSecurityConfig.java

@@ -1,7 +1,7 @@
 package com.genersoft.iot.vmp.conf.security;
 
 import com.genersoft.iot.vmp.conf.UserSetting;
-import org.junit.jupiter.api.Order;
+import org.springframework.core.annotation.Order;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;

+ 25 - 22
src/main/java/com/genersoft/iot/vmp/gb28181/bean/Device.java

@@ -77,8 +77,8 @@ public class Device {
 	/**
 	 * 在线
 	 */
-	@Schema(description = "是否在线,1为在线,0为离线")
-	private int online;
+	@Schema(description = "是否在线,true为在线,false为离线")
+	private boolean onLine;
 
 
 	/**
@@ -140,7 +140,7 @@ public class Device {
 	/**
 	 * 目录订阅周期,0为不订阅
 	 */
-	@Schema(description = "目录订阅周期,0为不订阅")
+	@Schema(description = "目录订阅周期,o为不订阅")
 	private int subscribeCycleForCatalog;
 
 	/**
@@ -173,12 +173,6 @@ public class Device {
 	@Schema(description = "地理坐标系, 目前支持 WGS84,GCJ02")
 	private String geoCoordSys;
 
-	/**
-	 * 树类型 国标规定了两种树的展现方式 行政区划:CivilCode 和业务分组:BusinessGroup
-	 */
-	@Schema(description = "树类型 国标规定了两种树的展现方式 行政区划:CivilCode 和业务分组:BusinessGroup")
-	private String treeType;
-
 	@Schema(description = "密码")
 	private String password;
 
@@ -195,6 +189,8 @@ public class Device {
 	private SipTransactionInfo sipTransactionInfo;
 
 
+
+
 	public String getDeviceId() {
 		return deviceId;
 	}
@@ -286,12 +282,12 @@ public class Device {
 		this.hostAddress = hostAddress;
 	}
 
-	public int getOnline() {
-		return online;
+	public boolean isOnLine() {
+		return onLine;
 	}
 
-	public void setOnline(int online) {
-		this.online = online;
+	public void setOnLine(boolean onLine) {
+		this.onLine = onLine;
 	}
 
 	public int getChannelCount() {
@@ -406,15 +402,6 @@ public class Device {
 		this.geoCoordSys = geoCoordSys;
 	}
 
-
-	public String getTreeType() {
-		return treeType;
-	}
-
-	public void setTreeType(String treeType) {
-		this.treeType = treeType;
-	}
-
 	public String getPassword() {
 		return password;
 	}
@@ -462,4 +449,20 @@ public class Device {
 	public void setSipTransactionInfo(SipTransactionInfo sipTransactionInfo) {
 		this.sipTransactionInfo = sipTransactionInfo;
 	}
+
+	/*======================设备主子码流逻辑START=========================*/
+	@Schema(description = "开启主子码流切换的开关(false-不开启,true-开启)")
+	private boolean switchPrimarySubStream;
+
+	public boolean isSwitchPrimarySubStream() {
+		return switchPrimarySubStream;
+	}
+
+	public void setSwitchPrimarySubStream(boolean switchPrimarySubStream) {
+		this.switchPrimarySubStream = switchPrimarySubStream;
+	}
+
+	/*======================设备主子码流逻辑END=========================*/
+
+
 }

+ 3 - 3
src/main/java/com/genersoft/iot/vmp/gb28181/bean/DeviceChannel.java

@@ -172,7 +172,7 @@ public class DeviceChannel {
 	 * 遇到过NVR下的IPC下发信令可以推流, 但是 Status 响应 OFF
 	 */
 	@Schema(description = "在线/离线, 1在线,0离线")
-	private int status;
+	private boolean status;
 
 	/**
 	 * 经度
@@ -455,11 +455,11 @@ public class DeviceChannel {
 		this.PTZTypeText = PTZTypeText;
 	}
 
-	public int getStatus() {
+	public boolean isStatus() {
 		return status;
 	}
 
-	public void setStatus(int status) {
+	public void setStatus(boolean status) {
 		this.status = status;
 	}
 

+ 46 - 0
src/main/java/com/genersoft/iot/vmp/gb28181/bean/Gb28181Sdp.java

@@ -0,0 +1,46 @@
+package com.genersoft.iot.vmp.gb28181.bean;
+
+import javax.sdp.SessionDescription;
+
+/**
+ * 28181 的SDP解析器
+ */
+public class Gb28181Sdp  {
+    private SessionDescription baseSdb;
+    private String ssrc;
+
+    private String mediaDescription;
+
+    public static Gb28181Sdp getInstance(SessionDescription baseSdb, String ssrc, String mediaDescription) {
+        Gb28181Sdp gb28181Sdp = new Gb28181Sdp();
+        gb28181Sdp.setBaseSdb(baseSdb);
+        gb28181Sdp.setSsrc(ssrc);
+        gb28181Sdp.setMediaDescription(mediaDescription);
+        return gb28181Sdp;
+    }
+
+
+    public SessionDescription getBaseSdb() {
+        return baseSdb;
+    }
+
+    public void setBaseSdb(SessionDescription baseSdb) {
+        this.baseSdb = baseSdb;
+    }
+
+    public String getSsrc() {
+        return ssrc;
+    }
+
+    public void setSsrc(String ssrc) {
+        this.ssrc = ssrc;
+    }
+
+    public String getMediaDescription() {
+        return mediaDescription;
+    }
+
+    public void setMediaDescription(String mediaDescription) {
+        this.mediaDescription = mediaDescription;
+    }
+}

+ 1 - 1
src/main/java/com/genersoft/iot/vmp/gb28181/bean/GbStream.java

@@ -10,7 +10,7 @@ import io.swagger.v3.oas.annotations.media.Schema;
 public class GbStream extends PlatformGbStream{
 
     @Schema(description = "ID")
-    private Integer gbStreamId;
+    private int gbStreamId;
     @Schema(description = "应用名")
     private String app;
     @Schema(description = "流ID")

+ 0 - 14
src/main/java/com/genersoft/iot/vmp/gb28181/bean/ParentPlatform.java

@@ -183,12 +183,6 @@ public class ParentPlatform {
     @Schema(description = "创建时间")
     private String createTime;
 
-    /**
-     * 树类型 国标规定了两种树的展现方式 行政区划 CivilCode 和业务分组:BusinessGroup
-     */
-    @Schema(description = "树类型 国标规定了两种树的展现方式 行政区划 CivilCode 和业务分组:BusinessGrou")
-    private String treeType;
-
     @Schema(description = "是否作为消息通道")
     private boolean asMessageChannel;
 
@@ -424,14 +418,6 @@ public class ParentPlatform {
         this.createTime = createTime;
     }
 
-    public String getTreeType() {
-        return treeType;
-    }
-
-    public void setTreeType(String treeType) {
-        this.treeType = treeType;
-    }
-
     public boolean isAsMessageChannel() {
         return asMessageChannel;
     }

+ 1 - 1
src/main/java/com/genersoft/iot/vmp/gb28181/bean/PlatformGbStream.java

@@ -5,7 +5,7 @@ import io.swagger.v3.oas.annotations.media.Schema;
 public class PlatformGbStream {
 
     @Schema(description = "ID")
-    private Integer gbStreamId;
+    private int gbStreamId;
 
     @Schema(description = "平台ID")
     private String platformId;

+ 0 - 10
src/main/java/com/genersoft/iot/vmp/gb28181/bean/TreeType.java

@@ -1,10 +0,0 @@
-package com.genersoft.iot.vmp.gb28181.bean;
-
-/**
- * 目录结构类型
- * @author lin
- */
-public class TreeType {
-    public static final String BUSINESS_GROUP = "BusinessGroup";
-    public static final String CIVIL_CODE = "CivilCode";
-}

+ 8 - 16
src/main/java/com/genersoft/iot/vmp/gb28181/session/SSRCFactory.java

@@ -1,6 +1,7 @@
 package com.genersoft.iot.vmp.gb28181.session;
 
 import com.genersoft.iot.vmp.conf.SipConfig;
+import com.genersoft.iot.vmp.conf.UserSetting;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.data.redis.core.StringRedisTemplate;
 import org.springframework.stereotype.Component;
@@ -31,10 +32,13 @@ public class SSRCFactory {
     @Autowired
     private SipConfig sipConfig;
 
+    @Autowired
+    private UserSetting userSetting;
+
 
     public void initMediaServerSSRC(String mediaServerId, Set<String> usedSet) {
         String ssrcPrefix = sipConfig.getDomain().substring(3, 8);
-        String redisKey = SSRC_INFO_KEY + mediaServerId;
+        String redisKey = SSRC_INFO_KEY + userSetting.getServerId() + "_" + mediaServerId;
         List<String> ssrcList = new ArrayList<>();
         for (int i = 1; i < MAX_STREAM_COUNT; i++) {
             String ssrc = String.format("%s%04d", ssrcPrefix, i);
@@ -77,7 +81,7 @@ public class SSRCFactory {
             return;
         }
         String sn = ssrc.substring(1);
-        String redisKey = SSRC_INFO_KEY + mediaServerId;
+        String redisKey = SSRC_INFO_KEY + userSetting.getServerId() + "_" + mediaServerId;
         redisTemplate.opsForSet().add(redisKey, sn);
     }
 
@@ -86,7 +90,7 @@ public class SSRCFactory {
      */
     private String getSN(String mediaServerId) {
         String sn = null;
-        String redisKey = SSRC_INFO_KEY + mediaServerId;
+        String redisKey = SSRC_INFO_KEY + userSetting.getServerId() + "_" + mediaServerId;
         Long size = redisTemplate.opsForSet().size(redisKey);
         if (size == null || size == 0) {
             throw new RuntimeException("ssrc已经用完");
@@ -113,20 +117,8 @@ public class SSRCFactory {
      * @param mediaServerId 流媒体服务ID
      */
     public boolean hasMediaServerSSRC(String mediaServerId) {
-        String redisKey = SSRC_INFO_KEY + mediaServerId;
+        String redisKey = SSRC_INFO_KEY + userSetting.getServerId() + "_" + mediaServerId;
         return redisTemplate.opsForSet().members(redisKey) != null;
     }
 
-    /**
-     * 查询ssrc是否可用
-     *
-     * @param mediaServerId
-     * @param ssrc
-     * @return
-     */
-    public boolean checkSsrc(String mediaServerId, String ssrc) {
-        String sn = ssrc.substring(1);
-        String redisKey = SSRC_INFO_KEY + mediaServerId;
-        return redisTemplate.opsForSet().isMember(redisKey, sn) != null;
-    }
 }

+ 9 - 1
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/callback/DeferredResultHolder.java

@@ -39,16 +39,22 @@ public class DeferredResultHolder {
 
 	public static final String CALLBACK_CMD_DOWNLOAD = "CALLBACK_DOWNLOAD";
 
+	public static final String CALLBACK_CMD_PROXY = "CALLBACK_PROXY";
+
 	public static final String CALLBACK_CMD_STOP = "CALLBACK_STOP";
 
 	public static final String UPLOAD_FILE_CHANNEL = "UPLOAD_FILE_CHANNEL";
 
-	public static final String CALLBACK_CMD_MOBILEPOSITION = "CALLBACK_MOBILEPOSITION";
+	public static final String CALLBACK_CMD_MOBILE_POSITION = "CALLBACK_CMD_MOBILE_POSITION";
 
 	public static final String CALLBACK_CMD_PRESETQUERY = "CALLBACK_PRESETQUERY";
 
 	public static final String CALLBACK_CMD_ALARM = "CALLBACK_ALARM";
 
+	public static final String CALLBACK_CMD_BROADCAST = "CALLBACK_BROADCAST";
+
+	public static final String CALLBACK_CMD_SNAP= "CALLBACK_SNAP";
+
 	private Map<String, Map<String, DeferredResultEx>> map = new ConcurrentHashMap<>();
 
 
@@ -149,4 +155,6 @@ public class DeferredResultHolder {
 			map.remove(msg.getKey());
 		}
 	}
+
+
 }

+ 1 - 1
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommanderForPlatform.java

@@ -80,7 +80,7 @@ public interface ISIPCommanderForPlatform {
      * @param fromTag
      * @return
      */
-    void deviceStatusResponse(ParentPlatform parentPlatform,String channelId, String sn, String fromTag,int status) throws SipException, InvalidArgumentException, ParseException ;
+    void deviceStatusResponse(ParentPlatform parentPlatform,String channelId, String sn, String fromTag,boolean status) throws SipException, InvalidArgumentException, ParseException;
 
     /**
      * 向上级回复移动位置订阅消息

+ 2 - 2
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderPlarformProvider.java

@@ -55,8 +55,8 @@ public class SIPRequestHeaderPlarformProvider {
 				parentPlatform.getServerIP() + ":" + parentPlatform.getServerPort());
 		//via
 		ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();
-		ViaHeader viaHeader = SipFactory.getInstance().createHeaderFactory().createViaHeader(parentPlatform.getServerIP(),
-				parentPlatform.getServerPort(), parentPlatform.getTransport(), SipUtils.getNewViaTag());
+		ViaHeader viaHeader = SipFactory.getInstance().createHeaderFactory().createViaHeader(parentPlatform.getDeviceIp(),
+				Integer.parseInt(parentPlatform.getDevicePort()), parentPlatform.getTransport(), SipUtils.getNewViaTag());
 		viaHeader.setRPort();
 		viaHeaders.add(viaHeader);
 		//from

+ 37 - 17
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java

@@ -1,13 +1,14 @@
 package com.genersoft.iot.vmp.gb28181.transmit.cmd.impl;
 
-import com.alibaba.fastjson2.JSONObject;
 import com.genersoft.iot.vmp.common.InviteSessionType;
 import com.genersoft.iot.vmp.common.StreamInfo;
 import com.genersoft.iot.vmp.conf.SipConfig;
 import com.genersoft.iot.vmp.conf.UserSetting;
 import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException;
 import com.genersoft.iot.vmp.gb28181.SipLayer;
-import com.genersoft.iot.vmp.gb28181.bean.*;
+import com.genersoft.iot.vmp.gb28181.bean.Device;
+import com.genersoft.iot.vmp.gb28181.bean.DeviceAlarm;
+import com.genersoft.iot.vmp.gb28181.bean.SsrcTransaction;
 import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
 import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
 import com.genersoft.iot.vmp.gb28181.transmit.SIPSender;
@@ -21,6 +22,7 @@ import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeFactory;
 import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForStreamChange;
 import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForStreamPush;
 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
+import com.genersoft.iot.vmp.media.zlm.dto.hook.HookParam;
 import com.genersoft.iot.vmp.service.IMediaServerService;
 import com.genersoft.iot.vmp.service.bean.SSRCInfo;
 import com.genersoft.iot.vmp.utils.DateUtil;
@@ -155,6 +157,11 @@ public class SIPCommander implements ISIPCommander {
         builder.append(strTmp, 0, 2);
         strTmp = String.format("%02X", parameter2);
         builder.append(strTmp, 0, 2);
+        //优化zoom变倍速率
+        if ((combineCode2 > 0) && (combineCode2 <16))
+        {
+            combineCode2 = 16;
+        }
         strTmp = String.format("%X", combineCode2);
         builder.append(strTmp, 0, 1).append("0");
         //计算校验码
@@ -280,9 +287,9 @@ public class SIPCommander implements ISIPCommander {
 
         logger.info("{} 分配的ZLM为: {} [{}:{}]", stream, mediaServerItem.getId(), mediaServerItem.getSdpIp(), ssrcInfo.getPort());
         HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", stream, true, "rtsp", mediaServerItem.getId());
-        subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, JSONObject json) -> {
+        subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, HookParam hookParam) -> {
             if (event != null) {
-                event.response(mediaServerItemInUse, json);
+                event.response(mediaServerItemInUse, hookParam);
                 subscribe.removeSubscribe(hookSubscribe);
             }
         });
@@ -345,6 +352,22 @@ public class SIPCommander implements ISIPCommander {
             }
         }
 
+        if( device.isSwitchPrimarySubStream() ){
+            if("TP-LINK".equals(device.getManufacturer())){
+                if (device.isSwitchPrimarySubStream()){
+                    content.append("a=streamMode:sub\r\n");
+                }else {
+                    content.append("a=streamMode:main\r\n");
+                }
+            }else {
+                if (device.isSwitchPrimarySubStream()){
+                    content.append("a=streamprofile:1\r\n");
+                }else {
+                    content.append("a=streamprofile:0\r\n");
+                }
+            }
+        }
+
         content.append("y=" + ssrcInfo.getSsrc() + "\r\n");//ssrc
         // f字段:f= v/编码格式/分辨率/帧率/码率类型/码率大小a/编码格式/码率大小/采样率
 //			content.append("f=v/2/5/25/1/4000a/1/8/1" + "\r\n"); // 未发现支持此特性的设备
@@ -360,7 +383,8 @@ public class SIPCommander implements ISIPCommander {
             // 这里为例避免一个通道的点播只有一个callID这个参数使用一个固定值
             ResponseEvent responseEvent = (ResponseEvent) e.event;
             SIPResponse response = (SIPResponse) responseEvent.getResponse();
-            streamSession.put(device.getDeviceId(), channelId, "play", stream, ssrcInfo.getSsrc(), mediaServerItem.getId(), response, InviteSessionType.PLAY);
+            streamSession.put(device.getDeviceId(), channelId, "play", stream, ssrcInfo.getSsrc(), mediaServerItem.getId(), response,
+                    InviteSessionType.PLAY);
             okEvent.response(e);
         });
     }
@@ -450,13 +474,13 @@ public class SIPCommander implements ISIPCommander {
 
         HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", ssrcInfo.getStream(), true, "rtsp", mediaServerItem.getId());
         // 添加订阅
-        subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, JSONObject json) -> {
+        subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, HookParam hookParam) -> {
             if (hookEvent != null) {
-                hookEvent.response(mediaServerItemInUse, json);
+                hookEvent.response(mediaServerItemInUse, hookParam);
             }
             subscribe.removeSubscribe(hookSubscribe);
         });
-        Request request = headerProvider.createPlaybackInviteRequest(device, channelId, content.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()), ssrcInfo.getSsrc());
+        Request request = headerProvider.createPlaybackInviteRequest(device, channelId, content.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()), ssrcInfo.getSsrc());
 
         sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent, event -> {
             ResponseEvent responseEvent = (ResponseEvent) event.event;
@@ -553,15 +577,15 @@ public class SIPCommander implements ISIPCommander {
         // 添加订阅
         CallIdHeader newCallIdHeader = sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()), device.getTransport());
         String callId= newCallIdHeader.getCallId();
-        subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, JSONObject json) -> {
+        subscribe.addSubscribe(hookSubscribe, (mediaServerItemInUse, hookParam) -> {
             logger.debug("sipc 添加订阅===callId {}",callId);
-            hookEvent.response(mediaServerItemInUse, json);
+            hookEvent.response(mediaServerItemInUse, hookParam);
             subscribe.removeSubscribe(hookSubscribe);
             hookSubscribe.getContent().put("regist", false);
             hookSubscribe.getContent().put("schema", "rtsp");
             // 添加流注销的订阅,注销了后向设备发送bye
             subscribe.addSubscribe(hookSubscribe,
-                    (MediaServerItem mediaServerItemForEnd, JSONObject jsonForEnd) -> {
+                    (mediaServerItemForEnd, hookParam1) -> {
                         logger.info("[录像]下载结束, 发送BYE");
                         try {
                             streamByeCmd(device, channelId, ssrcInfo.getStream(), callId);
@@ -572,17 +596,13 @@ public class SIPCommander implements ISIPCommander {
                     });
         });
 
-        Request request = headerProvider.createPlaybackInviteRequest(device, channelId, content.toString(), null, SipUtils.getNewFromTag(), null,newCallIdHeader, ssrcInfo.getSsrc());
+        Request request = headerProvider.createPlaybackInviteRequest(device, channelId, content.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,newCallIdHeader, ssrcInfo.getSsrc());
 
         sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent, event -> {
             ResponseEvent responseEvent = (ResponseEvent) event.event;
             SIPResponse response = (SIPResponse) responseEvent.getResponse();
             String contentString =new String(response.getRawContent());
-            int ssrcIndex = contentString.indexOf("y=");
-            String ssrc=ssrcInfo.getSsrc();
-            if (ssrcIndex >= 0) {
-                ssrc = contentString.substring(ssrcIndex + 2, ssrcIndex + 12);
-            }
+            String ssrc = SipUtils.getSsrcFromSdp(contentString);
             streamSession.put(device.getDeviceId(), channelId, response.getCallIdHeader().getCallId(), ssrcInfo.getStream(), ssrc, mediaServerItem.getId(), response, InviteSessionType.DOWNLOAD);
             okEvent.response(event);
         });

+ 143 - 52
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java

@@ -230,59 +230,150 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform {
                 // 行政区划分组只需要这两项就可以
                 catalogXml.append("<DeviceID>" + channel.getChannelId() + "</DeviceID>\r\n");
                 catalogXml.append("<Name>" + channel.getName() + "</Name>\r\n");
-                if (channel.getParentId() != null) {
-                    // 业务分组加上这一项即可,提高兼容性,
-                    catalogXml.append("<ParentID>" + channel.getParentId() + "</ParentID>\r\n");
-//                    catalogXml.append("<ParentID>" + parentPlatform.getDeviceGBId() + "/" + channel.getParentId() + "</ParentID>\r\n");
-                }
-                if (channel.getChannelId().length() == 20 && Integer.parseInt(channel.getChannelId().substring(10, 13)) == 216) {
-                    // 虚拟组织增加BusinessGroupID字段
-                    catalogXml.append("<BusinessGroupID>" + channel.getParentId() + "</BusinessGroupID>\r\n");
-                }
-                if (!channel.getChannelId().equals(parentPlatform.getDeviceGBId())) {
-                    catalogXml.append("<Parental>" + channel.getParental() + "</Parental>\r\n");
-                    if (channel.getParental() == 0) {
-                        catalogXml.append("<Status>" + (channel.getStatus() == 0 ? "OFF" : "ON") + "</Status>\r\n");
+                if (channel.getChannelId().length() <= 8) {
+                    catalogXml.append("</Item>\r\n");
+                    continue;
+                }else {
+                    if (channel.getChannelId().length() != 20) {
+                        catalogXml.append("</Item>\r\n");
+                        continue;
                     }
-                }
-                if (channel.getParental() == 0) {
-                    // 通道项
-                    catalogXml.append("<Manufacturer>" + channel.getManufacture() + "</Manufacturer>\r\n");
-                    catalogXml.append("<Secrecy>" + channel.getSecrecy() + "</Secrecy>\r\n");
-                    catalogXml.append("<RegisterWay>" + channel.getRegisterWay() + "</RegisterWay>\r\n");
-                    String civilCode = channel.getCivilCode() == null?parentPlatform.getAdministrativeDivision() : channel.getCivilCode();
-                    if (channel.getChannelType() != 2) {  // 业务分组/虚拟组织/行政区划 不设置以下属性
-                        catalogXml.append("<Model>" + channel.getModel() + "</Model>\r\n");
-                        catalogXml.append("<Owner>" + parentPlatform.getDeviceGBId()+ "</Owner>\r\n");
-                        catalogXml.append("<CivilCode>" + civilCode + "</CivilCode>\r\n");
-                        if (channel.getAddress() == null) {
-                            catalogXml.append("<Address></Address>\r\n");
-                        }else {
-                            catalogXml.append("<Address>" + channel.getAddress() + "</Address>\r\n");
-                        }
-                        catalogXml.append("<Block>" + channel.getBlock() + "</Block>\r\n");
-                        catalogXml.append("<SafetyWay>" + channel.getSafetyWay() + "</SafetyWay>\r\n");
-                        catalogXml.append("<CertNum>" + channel.getCertNum() + "</CertNum>\r\n");
-                        catalogXml.append("<Certifiable>" + channel.getCertifiable() + "</Certifiable>\r\n");
-                        catalogXml.append("<ErrCode>" + channel.getErrCode() + "</ErrCode>\r\n");
-                        catalogXml.append("<EndTime>" + channel.getEndTime() + "</EndTime>\r\n");
-                        catalogXml.append("<Secrecy>" + channel.getSecrecy() + "</Secrecy>\r\n");
-                        catalogXml.append("<IPAddress>" + channel.getIpAddress() + "</IPAddress>\r\n");
-                        catalogXml.append("<Port>" + channel.getPort() + "</Port>\r\n");
-                        catalogXml.append("<Password>" + channel.getPort() + "</Password>\r\n");
-                        catalogXml.append("<PTZType>" + channel.getPTZType() + "</PTZType>\r\n");
-                        catalogXml.append("<Status>" + (channel.getStatus() == 1?"ON":"OFF") + "</Status>\r\n");
-                        catalogXml.append("<Longitude>" +
-                                (channel.getLongitudeWgs84() != 0? channel.getLongitudeWgs84():channel.getLongitude())
-                                + "</Longitude>\r\n");
-                        catalogXml.append("<Latitude>" +
-                                (channel.getLatitudeWgs84() != 0? channel.getLatitudeWgs84():channel.getLatitude())
-                                + "</Latitude>\r\n");
-
+                    switch (Integer.parseInt(channel.getChannelId().substring(10, 13))){
+                        case 200:
+//                            catalogXml.append("<Manufacturer>三永华通</Manufacturer>\r\n");
+//                            GitUtil gitUtil = SpringBeanFactory.getBean("gitUtil");
+//                            String model = (gitUtil == null || gitUtil.getBuildVersion() == null)?"1.0": gitUtil.getBuildVersion();
+//                            catalogXml.append("<Model>" + model + "</Manufacturer>\r\n");
+//                            catalogXml.append("<Owner>三永华通</Owner>\r\n");
+                             if (channel.getCivilCode() != null) {
+                                 catalogXml.append("<CivilCode>"+channel.getCivilCode()+"</CivilCode>\r\n");
+                             }else {
+                                 catalogXml.append("<CivilCode></CivilCode>\r\n");
+                             }
+
+                            catalogXml.append("<RegisterWay>1</RegisterWay>\r\n");
+                            catalogXml.append("<Secrecy>0</Secrecy>\r\n");
+                            break;
+                        case 215:
+                            if (!ObjectUtils.isEmpty(channel.getParentId())) {
+                                catalogXml.append("<ParentID>" + channel.getParentId() + "</ParentID>\r\n");
+                            }
+
+                            break;
+                        case 216:
+                            if (!ObjectUtils.isEmpty(channel.getParentId())) {
+                                catalogXml.append("<ParentID>" + channel.getParentId() + "</ParentID>\r\n");
+                            }else {
+                                catalogXml.append("<ParentID></ParentID>\r\n");
+                            }
+                            if (!ObjectUtils.isEmpty(channel.getBusinessGroupId())) {
+                                catalogXml.append("<BusinessGroupID>" + channel.getBusinessGroupId() + "</BusinessGroupID>\r\n");
+                            }else {
+                                catalogXml.append("<BusinessGroupID></BusinessGroupID>\r\n");
+                            }
+                            break;
+                        default:
+                            // 通道项
+                            if (channel.getManufacture() != null) {
+                                catalogXml.append("<Manufacturer>" + channel.getManufacture() + "</Manufacturer>\r\n");
+                            }else {
+                                catalogXml.append("<Manufacturer></Manufacturer>\r\n");
+                            }
+                            if (channel.getSecrecy() != null) {
+                                catalogXml.append("<Secrecy>" + channel.getSecrecy() + "</Secrecy>\r\n");
+                            }else {
+                                catalogXml.append("<Secrecy></Secrecy>\r\n");
+                            }
+                            catalogXml.append("<RegisterWay>" + channel.getRegisterWay() + "</RegisterWay>\r\n");
+                            if (channel.getModel() != null) {
+                                catalogXml.append("<Model>" + channel.getModel() + "</Model>\r\n");
+                            }else {
+                                catalogXml.append("<Model></Model>\r\n");
+                            }
+                            if (channel.getOwner() != null) {
+                                catalogXml.append("<Owner>" + channel.getOwner()+ "</Owner>\r\n");
+                            }else {
+                                catalogXml.append("<Owner></Owner>\r\n");
+                            }
+                            if (channel.getCivilCode() != null) {
+                                catalogXml.append("<CivilCode>" + channel.getCivilCode() + "</CivilCode>\r\n");
+                            }else {
+                                catalogXml.append("<CivilCode></CivilCode>\r\n");
+                            }
+                            if (channel.getAddress() == null) {
+                                catalogXml.append("<Address></Address>\r\n");
+                            }else {
+                                catalogXml.append("<Address>" + channel.getAddress() + "</Address>\r\n");
+                            }
+                            if (!ObjectUtils.isEmpty(channel.getParentId())) {
+                                catalogXml.append("<ParentID>" + channel.getParentId() + "</ParentID>\r\n");
+                            }else {
+                                catalogXml.append("<ParentID></ParentID>\r\n");
+                            }
+                            if (!ObjectUtils.isEmpty(channel.getBlock())) {
+                                catalogXml.append("<Block>" + channel.getBlock() + "</Block>\r\n");
+                            }else {
+                                catalogXml.append("<Block></Block>\r\n");
+                            }
+                            if (!ObjectUtils.isEmpty(channel.getSafetyWay())) {
+                                catalogXml.append("<SafetyWay>" + channel.getSafetyWay() + "</SafetyWay>\r\n");
+                            }else {
+                                catalogXml.append("<SafetyWay></SafetyWay>\r\n");
+                            }
+                            if (!ObjectUtils.isEmpty(channel.getCertNum())) {
+                                catalogXml.append("<CertNum>" + channel.getCertNum() + "</CertNum>\r\n");
+                            }else {
+                                catalogXml.append("<CertNum></CertNum>\r\n");
+                            }
+                            if (!ObjectUtils.isEmpty(channel.getCertifiable())) {
+                                catalogXml.append("<Certifiable>" + channel.getCertifiable() + "</Certifiable>\r\n");
+                            }else {
+                                catalogXml.append("<Certifiable></Certifiable>\r\n");
+                            }
+                            if (!ObjectUtils.isEmpty(channel.getErrCode())) {
+                                catalogXml.append("<ErrCode>" + channel.getErrCode() + "</ErrCode>\r\n");
+                            }else {
+                                catalogXml.append("<ErrCode></ErrCode>\r\n");
+                            }
+                            if (!ObjectUtils.isEmpty(channel.getEndTime())) {
+                                catalogXml.append("<EndTime>" + channel.getEndTime() + "</EndTime>\r\n");
+                            }else {
+                                catalogXml.append("<EndTime></EndTime>\r\n");
+                            }
+                            if (!ObjectUtils.isEmpty(channel.getSecrecy())) {
+                                catalogXml.append("<Secrecy>" + channel.getSecrecy() + "</Secrecy>\r\n");
+                            }else {
+                                catalogXml.append("<Secrecy></Secrecy>\r\n");
+                            }
+                            if (!ObjectUtils.isEmpty(channel.getIpAddress())) {
+                                catalogXml.append("<IPAddress>" + channel.getIpAddress() + "</IPAddress>\r\n");
+                            }else {
+                                catalogXml.append("<IPAddress></IPAddress>\r\n");
+                            }
+                            catalogXml.append("<Port>" + channel.getPort() + "</Port>\r\n");
+                            if (!ObjectUtils.isEmpty(channel.getPassword())) {
+                                catalogXml.append("<Password>" + channel.getPassword() + "</Password>\r\n");
+                            }else {
+                                catalogXml.append("<Password></Password>\r\n");
+                            }
+                            if (!ObjectUtils.isEmpty(channel.getPTZType())) {
+                                catalogXml.append("<PTZType>" + channel.getPTZType() + "</PTZType>\r\n");
+                            }else {
+                                catalogXml.append("<PTZType></PTZType>\r\n");
+                            }
+                            catalogXml.append("<Status>" + (channel.isStatus() ?"ON":"OFF") + "</Status>\r\n");
+
+                            catalogXml.append("<Longitude>" +
+                                    (channel.getLongitudeWgs84() != 0? channel.getLongitudeWgs84():channel.getLongitude())
+                                    + "</Longitude>\r\n");
+                            catalogXml.append("<Latitude>" +
+                                    (channel.getLatitudeWgs84() != 0? channel.getLatitudeWgs84():channel.getLatitude())
+                                    + "</Latitude>\r\n");
+                            break;
 
                     }
+                    catalogXml.append("</Item>\r\n");
                 }
-                catalogXml.append("</Item>\r\n");
             }
         }
 
@@ -399,11 +490,11 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform {
      * @return
      */
     @Override
-    public void deviceStatusResponse(ParentPlatform parentPlatform,String channelId, String sn, String fromTag,int status) throws SipException, InvalidArgumentException, ParseException {
+    public void deviceStatusResponse(ParentPlatform parentPlatform,String channelId, String sn, String fromTag,boolean status) throws SipException, InvalidArgumentException, ParseException {
         if (parentPlatform == null) {
             return ;
         }
-        String statusStr = (status==1)?"ONLINE":"OFFLINE";
+        String statusStr = (status)?"ONLINE":"OFFLINE";
         String characterSet = parentPlatform.getCharacterSet();
         StringBuffer deviceStatusXml = new StringBuffer(600);
         deviceStatusXml.append("<?xml version=\"1.0\" encoding=\"" + characterSet + "\"?>\r\n")
@@ -564,7 +655,7 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform {
                     catalogXml.append("<Manufacturer>" + channel.getManufacture() + "</Manufacturer>\r\n")
                             .append("<Secrecy>" + channel.getSecrecy() + "</Secrecy>\r\n")
                             .append("<RegisterWay>" + channel.getRegisterWay() + "</RegisterWay>\r\n")
-                            .append("<Status>" + (channel.getStatus() == 0 ? "OFF" : "ON") + "</Status>\r\n");
+                            .append("<Status>" + (channel.isStatus() ? "ON" : "OFF") + "</Status>\r\n");
 
                     if (channel.getChannelType() != 2) {  // 业务分组/虚拟组织/行政区划 不设置以下属性
                         catalogXml.append("<Model>" + channel.getModel() + "</Model>\r\n")

+ 1 - 2
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/ByeRequestProcessor.java

@@ -166,9 +166,8 @@ public class ByeRequestProcessor extends SIPRequestProcessorParent implements In
 						streamSession.remove(device.getDeviceId(), channelId, ssrcTransactionForPlay.getStream());
 					}
 					InviteInfo inviteInfo = inviteStreamService.getInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, device.getDeviceId(), channelId);
-
+					inviteStreamService.removeInviteInfo(inviteInfo);
 					if (inviteInfo != null) {
-						inviteStreamService.removeInviteInfo(inviteInfo);
 						if (inviteInfo.getStreamInfo() != null) {
 							mediaServerService.closeRTPServer(inviteInfo.getStreamInfo().getMediaServerId(), inviteInfo.getStream());
 						}

+ 21 - 38
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java

@@ -22,11 +22,12 @@ import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
 import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
 import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe;
 import com.genersoft.iot.vmp.media.zlm.dto.*;
+import com.genersoft.iot.vmp.media.zlm.dto.hook.OnStreamChangedHookParam;
 import com.genersoft.iot.vmp.service.IMediaServerService;
 import com.genersoft.iot.vmp.service.IPlayService;
 import com.genersoft.iot.vmp.service.IStreamProxyService;
 import com.genersoft.iot.vmp.service.IStreamPushService;
-import com.genersoft.iot.vmp.service.bean.InviteErrorCallback;
+import com.genersoft.iot.vmp.service.bean.ErrorCallback;
 import com.genersoft.iot.vmp.service.bean.InviteErrorCode;
 import com.genersoft.iot.vmp.service.bean.MessageForPushChannel;
 import com.genersoft.iot.vmp.service.bean.SSRCInfo;
@@ -217,6 +218,8 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
                                     logger.error("[命令发送失败] invite GONE: {}", e.getMessage());
                                 }
                                 return;
+                            }else {
+                                 // TODO 可能漏回复消息
                             }
                         }
                     } else {
@@ -270,18 +273,8 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
                 // 解析sdp消息, 使用jainsip 自带的sdp解析方式
                 String contentString = new String(request.getRawContent());
 
-                // jainSip不支持y=字段, 移除以解析。
-                // 检查是否有y字段
-                int ssrcIndex = contentString.indexOf("y=");
-
-                SessionDescription sdp;
-                if (ssrcIndex >= 0) {
-                    //ssrc规定长度为10个字节,不取余下长度以避免后续还有“f=”字段
-                    String substring = contentString.substring(0, ssrcIndex);
-                    sdp = SdpFactory.getInstance().createSessionDescription(substring);
-                } else {
-                    sdp = SdpFactory.getInstance().createSessionDescription(contentString);
-                }
+                Gb28181Sdp gb28181Sdp = SipUtils.parseSDP(contentString);
+                SessionDescription sdp = gb28181Sdp.getBaseSdb();
                 String sessionName = sdp.getSessionName().getValue();
 
                 Long startTime = null;
@@ -369,11 +362,11 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
                     }
 
                     String ssrc;
-                    if (userSetting.getUseCustomSsrcForParentInvite() || ssrcIndex < 0) {
+                    if (userSetting.getUseCustomSsrcForParentInvite() || gb28181Sdp.getSsrc() == null) {
                         // 上级平台点播时不使用上级平台指定的ssrc,使用自定义的ssrc,参考国标文档-点播外域设备媒体流SSRC处理方式
                         ssrc = "Play".equalsIgnoreCase(sessionName) ? ssrcFactory.getPlaySsrc(mediaServerItem.getId()) : ssrcFactory.getPlayBackSsrc(mediaServerItem.getId());
-                    } else {
-                        ssrc = contentString.substring(ssrcIndex + 2, ssrcIndex + 12);
+                    }else {
+                        ssrc = gb28181Sdp.getSsrc();
                     }
                     String streamTypeStr = null;
                     if (mediaTransmissionTCP) {
@@ -406,8 +399,8 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
 
                     Long finalStartTime = startTime;
                     Long finalStopTime = stopTime;
-                    InviteErrorCallback<Object> hookEvent = (code, msg, data) -> {
-                        StreamInfo streamInfo = (StreamInfo) data;
+                    ErrorCallback<Object> hookEvent = (code, msg, data) -> {
+                        StreamInfo streamInfo = (StreamInfo)data;
                         MediaServerItem mediaServerItemInUSe = mediaServerService.getOne(streamInfo.getMediaServerId());
                         logger.info("[上级Invite]下级已经开始推流。 回复200OK(SDP), {}/{}", streamInfo.getApp(), streamInfo.getStream());
                         //     * 0 等待设备推流上来
@@ -460,7 +453,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
                             logger.error("[命令发送失败] 国标级联 回复SdpAck", e);
                         }
                     };
-                    InviteErrorCallback<Object> errorEvent = ((statusCode, msg, data) -> {
+                    ErrorCallback<Object> errorEvent = ((statusCode, msg, data) -> {
                         // 未知错误。直接转发设备点播的错误
                         try {
                             if (statusCode > 0) {
@@ -547,11 +540,11 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
                 } else if (gbStream != null) {
 
                     String ssrc;
-                    if (userSetting.getUseCustomSsrcForParentInvite() || ssrcIndex < 0) {
+                    if (userSetting.getUseCustomSsrcForParentInvite() || gb28181Sdp.getSsrc() == null) {
                         // 上级平台点播时不使用上级平台指定的ssrc,使用自定义的ssrc,参考国标文档-点播外域设备媒体流SSRC处理方式
                         ssrc = "Play".equalsIgnoreCase(sessionName) ? ssrcFactory.getPlaySsrc(mediaServerItem.getId()) : ssrcFactory.getPlayBackSsrc(mediaServerItem.getId());
-                    } else {
-                        ssrc = contentString.substring(ssrcIndex + 2, ssrcIndex + 12);
+                    }else {
+                        ssrc = gb28181Sdp.getSsrc();
                     }
 
                     if ("push".equals(gbStream.getStreamType())) {
@@ -690,10 +683,9 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
             logger.info("[ app={}, stream={} ]通道未推流,启用流后开始推流", gbStream.getApp(), gbStream.getStream());
             // 监听流上线
             HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed(gbStream.getApp(), gbStream.getStream(), true, "rtsp", mediaServerItem.getId());
-            zlmHttpHookSubscribe.addSubscribe(hookSubscribe, (mediaServerItemInUSe, responseJSON) -> {
-                String app = responseJSON.getString("app");
-                String stream = responseJSON.getString("stream");
-                logger.info("[上级点播]拉流代理已经就绪, {}/{}", app, stream);
+            zlmHttpHookSubscribe.addSubscribe(hookSubscribe, (mediaServerItemInUSe, hookParam) -> {
+                OnStreamChangedHookParam streamChangedHookParam = (OnStreamChangedHookParam)hookParam;
+                logger.info("[上级点播]拉流代理已经就绪, {}/{}", streamChangedHookParam.getApp(), streamChangedHookParam.getStream());
                 dynamicTask.stop(callIdHeader.getCallId());
                 pushProxyStream(evt, request, gbStream, platform, callIdHeader, mediaServerItem, port, tcpActive,
                         mediaTransmissionTCP, channelId, addressStr, ssrc, requesterId);
@@ -971,20 +963,11 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
             }
             String contentString = new String(request.getRawContent());
             // jainSip不支持y=字段, 移除移除以解析。
-            String substring = contentString;
             String ssrc = "0000000404";
-            int ssrcIndex = contentString.indexOf("y=");
-            if (ssrcIndex > 0) {
-                substring = contentString.substring(0, ssrcIndex);
-                ssrc = contentString.substring(ssrcIndex + 2, ssrcIndex + 12).trim();
-            }
-            ssrcIndex = substring.indexOf("f=");
-            if (ssrcIndex > 0) {
-                substring = contentString.substring(0, ssrcIndex);
-            }
-            try {
-                SessionDescription sdp = SdpFactory.getInstance().createSessionDescription(substring);
 
+            try {
+                Gb28181Sdp gb28181Sdp = SipUtils.parseSDP(contentString);
+                SessionDescription sdp = gb28181Sdp.getBaseSdb();
                 //  获取支持的格式
                 Vector mediaDescriptions = sdp.getMediaDescriptions(true);
 

+ 23 - 4
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/NotifyRequestForCatalogProcessor.java

@@ -1,5 +1,6 @@
 package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl;
 
+import com.genersoft.iot.vmp.conf.CivilCodeFileConf;
 import com.genersoft.iot.vmp.conf.DynamicTask;
 import com.genersoft.iot.vmp.conf.UserSetting;
 import com.genersoft.iot.vmp.gb28181.bean.Device;
@@ -20,7 +21,10 @@ import org.springframework.stereotype.Component;
 
 import javax.sip.RequestEvent;
 import javax.sip.header.FromHeader;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.CopyOnWriteArrayList;
 
@@ -56,6 +60,9 @@ public class NotifyRequestForCatalogProcessor extends SIPRequestProcessorParent
 	@Autowired
 	private DynamicTask dynamicTask;
 
+	@Autowired
+	private CivilCodeFileConf civilCodeFileConf;
+
 	private final static String talkKey = "notify-request-for-catalog-task";
 
 	public void process(RequestEvent evt) {
@@ -65,7 +72,7 @@ public class NotifyRequestForCatalogProcessor extends SIPRequestProcessorParent
 			String deviceId = SipUtils.getUserIdFromFromHeader(fromHeader);
 
 			Device device = redisCatchStorage.getDevice(deviceId);
-			if (device == null || device.getOnline() == 0) {
+			if (device == null || !device.isOnLine()) {
 				logger.warn("[收到目录订阅]:{}, 但是设备已经离线", (device != null ? device.getDeviceId():"" ));
 				return;
 			}
@@ -96,7 +103,7 @@ public class NotifyRequestForCatalogProcessor extends SIPRequestProcessorParent
 					}else {
 						event = eventElement.getText().toUpperCase();
 					}
-					DeviceChannel channel = XmlUtil.channelContentHander(itemDevice, device, event);
+					DeviceChannel channel = XmlUtil.channelContentHandler(itemDevice, device, event, civilCodeFileConf);
 
 					channel.setDeviceId(device.getDeviceId());
 					logger.info("[收到目录订阅]:{}/{}", device.getDeviceId(), channel.getChannelId());
@@ -175,6 +182,11 @@ public class NotifyRequestForCatalogProcessor extends SIPRequestProcessorParent
 								}
 							}else {
 								addChannelMap.put(channel.getChannelId(), channel);
+								if (userSetting.getDeviceStatusNotify()) {
+									// 发送redis消息
+									redisCatchStorage.sendChannelAddOrDelete(device.getDeviceId(), channel.getChannelId(), true);
+								}
+
 								if (addChannelMap.keySet().size() > 300) {
 									executeSaveForAdd();
 								}
@@ -185,6 +197,10 @@ public class NotifyRequestForCatalogProcessor extends SIPRequestProcessorParent
 							// 删除
 							logger.info("[收到删除通道通知] 来自设备: {}, 通道 {}", device.getDeviceId(), channel.getChannelId());
 							deleteChannelList.add(channel);
+							if (userSetting.getDeviceStatusNotify()) {
+								// 发送redis消息
+								redisCatchStorage.sendChannelAddOrDelete(device.getDeviceId(), channel.getChannelId(), false);
+							}
 							if (deleteChannelList.size() > 300) {
 								executeSaveForDelete();
 							}
@@ -205,6 +221,10 @@ public class NotifyRequestForCatalogProcessor extends SIPRequestProcessorParent
 								if (addChannelMap.keySet().size() > 300) {
 									executeSaveForAdd();
 								}
+								if (userSetting.getDeviceStatusNotify()) {
+									// 发送redis消息
+									redisCatchStorage.sendChannelAddOrDelete(device.getDeviceId(), channel.getChannelId(), true);
+								}
 							}
 							break;
 						default:
@@ -232,7 +252,6 @@ public class NotifyRequestForCatalogProcessor extends SIPRequestProcessorParent
 	}
 
 	private void executeSave(){
-		System.out.println("定时存储数据");
 		executeSaveForUpdate();
 		executeSaveForDelete();
 		executeSaveForOnline();

+ 14 - 5
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/NotifyRequestProcessor.java

@@ -1,6 +1,7 @@
 package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl;
 
 import com.alibaba.fastjson2.JSONObject;
+import com.genersoft.iot.vmp.conf.CivilCodeFileConf;
 import com.genersoft.iot.vmp.conf.SipConfig;
 import com.genersoft.iot.vmp.conf.UserSetting;
 import com.genersoft.iot.vmp.gb28181.bean.*;
@@ -79,6 +80,9 @@ public class NotifyRequestProcessor extends SIPRequestProcessorParent implements
 	@Autowired
 	private NotifyRequestForCatalogProcessor notifyRequestForCatalogProcessor;
 
+	@Autowired
+	private CivilCodeFileConf civilCodeFileConf;
+
 	private ConcurrentLinkedQueue<HandlerCatchData> taskQueue = new ConcurrentLinkedQueue<>();
 
 	@Qualifier("taskExecutor")
@@ -192,7 +196,12 @@ public class NotifyRequestProcessor extends SIPRequestProcessorParent implements
 			mobilePosition.setDeviceId(device.getDeviceId());
 			mobilePosition.setChannelId(channelId);
 			String time = XmlUtil.getText(rootElement, "Time");
-			mobilePosition.setTime(time);
+			if (ObjectUtils.isEmpty(time)){
+				mobilePosition.setTime(DateUtil.getNow());
+			}else {
+				mobilePosition.setTime(SipUtils.parseTime(time));
+			}
+
 			mobilePosition.setLongitude(Double.parseDouble(XmlUtil.getText(rootElement, "Longitude")));
 			mobilePosition.setLatitude(Double.parseDouble(XmlUtil.getText(rootElement, "Latitude")));
 			if (NumericUtil.isDouble(XmlUtil.getText(rootElement, "Speed"))) {
@@ -237,7 +246,7 @@ public class NotifyRequestProcessor extends SIPRequestProcessorParent implements
 
 			// 发送redis消息。 通知位置信息的变化
 			JSONObject jsonObject = new JSONObject();
-			jsonObject.put("time", time);
+			jsonObject.put("time", DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(mobilePosition.getTime()));
 			jsonObject.put("serial", deviceId);
 			jsonObject.put("code", channelId);
 			jsonObject.put("longitude", mobilePosition.getLongitude());
@@ -339,7 +348,7 @@ public class NotifyRequestProcessor extends SIPRequestProcessorParent implements
 				storager.updateChannelPosition(deviceChannel);
 				// 发送redis消息。 通知位置信息的变化
 				JSONObject jsonObject = new JSONObject();
-				jsonObject.put("time", mobilePosition.getTime());
+				jsonObject.put("time", DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(mobilePosition.getTime()));
 				jsonObject.put("serial", deviceChannel.getDeviceId());
 				jsonObject.put("code", deviceChannel.getChannelId());
 				jsonObject.put("longitude", mobilePosition.getLongitude());
@@ -372,7 +381,7 @@ public class NotifyRequestProcessor extends SIPRequestProcessorParent implements
 			String deviceId = SipUtils.getUserIdFromFromHeader(fromHeader);
 
 			Device device = redisCatchStorage.getDevice(deviceId);
-			if (device == null || device.getOnline() == 0) {
+			if (device == null || !device.isOnLine()) {
 				logger.warn("[收到目录订阅]:{}, 但是设备已经离线", (device != null ? device.getDeviceId():"" ));
 				return;
 			}
@@ -403,7 +412,7 @@ public class NotifyRequestProcessor extends SIPRequestProcessorParent implements
 					}else {
 						event = eventElement.getText().toUpperCase();
 					}
-					DeviceChannel channel = XmlUtil.channelContentHander(itemDevice, device, event);
+					DeviceChannel channel = XmlUtil.channelContentHandler(itemDevice, device, event, civilCodeFileConf);
 					channel.setDeviceId(device.getDeviceId());
 					logger.info("[收到目录订阅]:{}/{}", device.getDeviceId(), channel.getChannelId());
 					switch (event) {

+ 1 - 2
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/RegisterRequestProcessor.java

@@ -167,9 +167,8 @@ public class RegisterRequestProcessor extends SIPRequestProcessorParent implemen
                 device.setStreamMode("UDP");
                 device.setCharset("GB2312");
                 device.setGeoCoordSys("WGS84");
-                device.setTreeType("CivilCode");
                 device.setDeviceId(deviceId);
-                device.setOnline(0);
+                device.setOnLine(false);
             }
             device.setIp(remoteAddressInfo.getIp());
             device.setPort(remoteAddressInfo.getPort());

+ 1 - 1
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/AlarmNotifyMessageHandler.java

@@ -164,7 +164,7 @@ public class AlarmNotifyMessageHandler extends SIPRequestProcessorParent impleme
 
                                 // 发送redis消息。 通知位置信息的变化
                                 JSONObject jsonObject = new JSONObject();
-                                jsonObject.put("time", mobilePosition.getTime());
+                                jsonObject.put("time", DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(mobilePosition.getTime()));
                                 jsonObject.put("serial", deviceChannel.getDeviceId());
                                 jsonObject.put("code", deviceChannel.getChannelId());
                                 jsonObject.put("longitude", mobilePosition.getLongitude());

+ 2 - 2
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/KeepaliveNotifyMessageHandler.java

@@ -83,12 +83,12 @@ public class KeepaliveNotifyMessageHandler extends SIPRequestProcessorParent imp
 
         device.setKeepaliveTime(DateUtil.getNow());
 
-        if (device.getOnline() == 1) {
+        if (device.isOnLine()) {
             deviceService.updateDevice(device);
         }else {
             // 对于已经离线的设备判断他的注册是否已经过期
             if (!deviceService.expire(device)){
-                device.setOnline(0);
+                device.setOnLine(false);
                 deviceService.online(device, null);
             }
         }

+ 8 - 2
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/MobilePositionNotifyMessageHandler.java

@@ -7,6 +7,7 @@ import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorP
 import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler;
 import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.notify.NotifyMessageHandler;
 import com.genersoft.iot.vmp.gb28181.utils.NumericUtil;
+import com.genersoft.iot.vmp.gb28181.utils.SipUtils;
 import com.genersoft.iot.vmp.service.IDeviceChannelService;
 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
 import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
@@ -95,7 +96,12 @@ public class MobilePositionNotifyMessageHandler extends SIPRequestProcessorParen
                         }
                         mobilePosition.setDeviceId(sipMsgInfo.getDevice().getDeviceId());
                         mobilePosition.setChannelId(getText(rootElementAfterCharset, "DeviceID"));
-                        mobilePosition.setTime(getText(rootElementAfterCharset, "Time"));
+                        String time = getText(rootElementAfterCharset, "Time");
+                        if (ObjectUtils.isEmpty(time)){
+                            mobilePosition.setTime(DateUtil.getNow());
+                        }else {
+                            mobilePosition.setTime(SipUtils.parseTime(time));
+                        }
                         mobilePosition.setLongitude(Double.parseDouble(getText(rootElementAfterCharset, "Longitude")));
                         mobilePosition.setLatitude(Double.parseDouble(getText(rootElementAfterCharset, "Latitude")));
                         if (NumericUtil.isDouble(getText(rootElementAfterCharset, "Speed"))) {
@@ -138,7 +144,7 @@ public class MobilePositionNotifyMessageHandler extends SIPRequestProcessorParen
 
                         // 发送redis消息。 通知位置信息的变化
                         JSONObject jsonObject = new JSONObject();
-                        jsonObject.put("time", mobilePosition.getTime());
+                        jsonObject.put("time", DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(mobilePosition.getTime()));
                         jsonObject.put("serial", deviceChannel.getDeviceId());
                         jsonObject.put("code", deviceChannel.getChannelId());
                         jsonObject.put("longitude", mobilePosition.getLongitude());

+ 1 - 1
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/DeviceStatusQueryMessageHandler.java

@@ -77,7 +77,7 @@ public class DeviceStatusQueryMessageHandler extends SIPRequestProcessorParent i
             return;
         }
         try {
-            cmderFroPlatform.deviceStatusResponse(parentPlatform,channelId, sn, fromHeader.getTag(),deviceChannel.getStatus());
+            cmderFroPlatform.deviceStatusResponse(parentPlatform,channelId, sn, fromHeader.getTag(),deviceChannel.isStatus());
         } catch (SipException | InvalidArgumentException | ParseException e) {
             logger.error("[命令发送失败] 国标级联 DeviceStatus查询回复: {}", e.getMessage());
         }

+ 6 - 1
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/CatalogResponseMessageHandler.java

@@ -1,5 +1,6 @@
 package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.cmd;
 
+import com.genersoft.iot.vmp.conf.CivilCodeFileConf;
 import com.genersoft.iot.vmp.gb28181.bean.*;
 import com.genersoft.iot.vmp.gb28181.session.CatalogDataCatch;
 import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
@@ -54,6 +55,9 @@ public class CatalogResponseMessageHandler extends SIPRequestProcessorParent imp
     @Autowired
     private ThreadPoolTaskExecutor taskExecutor;
 
+    @Autowired
+    private CivilCodeFileConf civilCodeFileConf;
+
     @Override
     public void afterPropertiesSet() throws Exception {
         responseMessageHandler.addHandler(cmdType, this);
@@ -101,6 +105,7 @@ public class CatalogResponseMessageHandler extends SIPRequestProcessorParent imp
                             Iterator<Element> deviceListIterator = deviceListElement.elementIterator();
                             if (deviceListIterator != null) {
                                 List<DeviceChannel> channelList = new ArrayList<>();
+                                List<String> parentChannelIds = new ArrayList<>();
                                 // 遍历DeviceList
                                 while (deviceListIterator.hasNext()) {
                                     Element itemDevice = deviceListIterator.next();
@@ -108,7 +113,7 @@ public class CatalogResponseMessageHandler extends SIPRequestProcessorParent imp
                                     if (channelDeviceElement == null) {
                                         continue;
                                     }
-                                    DeviceChannel deviceChannel = XmlUtil.channelContentHander(itemDevice, device, null);
+                                    DeviceChannel deviceChannel = XmlUtil.channelContentHandler(itemDevice, device, null, civilCodeFileConf);
                                     deviceChannel = SipUtils.updateGps(deviceChannel, device.getGeoCoordSys());
                                     deviceChannel.setDeviceId(take.getDevice().getDeviceId());
 

+ 1 - 6
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/DeviceInfoResponseMessageHandler.java

@@ -1,18 +1,13 @@
 package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.cmd;
 
-import com.genersoft.iot.vmp.common.VideoManagerConstants;
-import com.genersoft.iot.vmp.conf.SipConfig;
 import com.genersoft.iot.vmp.gb28181.bean.Device;
 import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
-import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
 import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
 import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
 import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
 import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler;
 import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.ResponseMessageHandler;
 import com.genersoft.iot.vmp.service.IDeviceService;
-import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
-import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
 import gov.nist.javax.sip.message.SIPRequest;
 import org.dom4j.DocumentException;
 import org.dom4j.Element;
@@ -59,7 +54,7 @@ public class DeviceInfoResponseMessageHandler extends SIPRequestProcessorParent
     public void handForDevice(RequestEvent evt, Device device, Element rootElement) {
         logger.debug("接收到DeviceInfo应答消息");
         // 检查设备是否存在, 不存在则不回复
-        if (device == null || device.getOnline() == 0) {
+        if (device == null || !device.isOnLine()) {
             logger.warn("[接收到DeviceInfo应答消息,但是设备已经离线]:" + (device != null ? device.getDeviceId():"" ));
             return;
         }

+ 25 - 5
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/MobilePositionResponseMessageHandler.java

@@ -2,17 +2,21 @@ package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.respon
 
 import com.alibaba.fastjson2.JSONObject;
 import com.genersoft.iot.vmp.conf.UserSetting;
-import com.genersoft.iot.vmp.gb28181.bean.*;
+import com.genersoft.iot.vmp.gb28181.bean.Device;
+import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
+import com.genersoft.iot.vmp.gb28181.bean.MobilePosition;
+import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
+import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
+import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
 import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
 import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler;
 import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.ResponseMessageHandler;
-import com.genersoft.iot.vmp.gb28181.utils.Coordtransform;
 import com.genersoft.iot.vmp.gb28181.utils.NumericUtil;
+import com.genersoft.iot.vmp.gb28181.utils.SipUtils;
 import com.genersoft.iot.vmp.service.IDeviceChannelService;
 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
 import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
 import com.genersoft.iot.vmp.utils.DateUtil;
-import com.genersoft.iot.vmp.utils.GpsUtil;
 import gov.nist.javax.sip.message.SIPRequest;
 import org.dom4j.DocumentException;
 import org.dom4j.Element;
@@ -56,6 +60,9 @@ public class MobilePositionResponseMessageHandler extends SIPRequestProcessorPar
     @Autowired
     private IDeviceChannelService deviceChannelService;
 
+    @Autowired
+    private DeferredResultHolder resultHolder;
+
     @Override
     public void afterPropertiesSet() throws Exception {
         responseMessageHandler.addHandler(cmdType, this);
@@ -83,7 +90,13 @@ public class MobilePositionResponseMessageHandler extends SIPRequestProcessorPar
             }
             mobilePosition.setDeviceId(device.getDeviceId());
             mobilePosition.setChannelId(getText(rootElement, "DeviceID"));
-            mobilePosition.setTime(getText(rootElement, "Time"));
+            //兼容ISO 8601格式时间
+            String time = getText(rootElement, "Time");
+            if (ObjectUtils.isEmpty(time)){
+                mobilePosition.setTime(DateUtil.getNow());
+            }else {
+                mobilePosition.setTime(SipUtils.parseTime(time));
+            }
             mobilePosition.setLongitude(Double.parseDouble(getText(rootElement, "Longitude")));
             mobilePosition.setLatitude(Double.parseDouble(getText(rootElement, "Latitude")));
             if (NumericUtil.isDouble(getText(rootElement, "Speed"))) {
@@ -121,11 +134,18 @@ public class MobilePositionResponseMessageHandler extends SIPRequestProcessorPar
             if (userSetting.getSavePositionHistory()) {
                 storager.insertMobilePosition(mobilePosition);
             }
+
             storager.updateChannelPosition(deviceChannel);
 
+            String key = DeferredResultHolder.CALLBACK_CMD_MOBILE_POSITION + device.getDeviceId();
+            RequestMessage msg = new RequestMessage();
+            msg.setKey(key);
+            msg.setData(mobilePosition);
+            resultHolder.invokeAllResult(msg);
+
             // 发送redis消息。 通知位置信息的变化
             JSONObject jsonObject = new JSONObject();
-            jsonObject.put("time", mobilePosition.getTime());
+            jsonObject.put("time", DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(mobilePosition.getTime()));
             jsonObject.put("serial", deviceChannel.getDeviceId());
             jsonObject.put("code", deviceChannel.getChannelId());
             jsonObject.put("longitude", mobilePosition.getLongitude());

+ 4 - 14
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/response/impl/InviteResponseProcessor.java

@@ -1,10 +1,12 @@
 package com.genersoft.iot.vmp.gb28181.transmit.event.response.impl;
 
 import com.genersoft.iot.vmp.gb28181.SipLayer;
+import com.genersoft.iot.vmp.gb28181.bean.Gb28181Sdp;
 import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver;
 import com.genersoft.iot.vmp.gb28181.transmit.SIPSender;
 import com.genersoft.iot.vmp.gb28181.transmit.cmd.SIPRequestHeaderProvider;
 import com.genersoft.iot.vmp.gb28181.transmit.event.response.SIPResponseProcessorAbstract;
+import com.genersoft.iot.vmp.gb28181.utils.SipUtils;
 import gov.nist.javax.sip.ResponseEventExt;
 import gov.nist.javax.sip.message.SIPResponse;
 import org.slf4j.Logger;
@@ -12,7 +14,6 @@ import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
 
-import javax.sdp.SdpFactory;
 import javax.sdp.SdpParseException;
 import javax.sdp.SessionDescription;
 import javax.sip.InvalidArgumentException;
@@ -82,19 +83,8 @@ public class InviteResponseProcessor extends SIPResponseProcessorAbstract {
 				ResponseEventExt event = (ResponseEventExt)evt;
 
 				String contentString = new String(response.getRawContent());
-				// jainSip不支持y=字段, 移除以解析。
-				int ssrcIndex = contentString.indexOf("y=");
-				// 检查是否有y字段
-				SessionDescription sdp;
-				if (ssrcIndex >= 0) {
-					//ssrc规定长度为10字节,不取余下长度以避免后续还有“f=”字段
-					String substring = contentString.substring(0, contentString.indexOf("y="));
-					sdp = SdpFactory.getInstance().createSessionDescription(substring);
-				} else {
-					sdp = SdpFactory.getInstance().createSessionDescription(contentString);
-				}
-				// 查看是否是来自设备的,此是回复
-
+				Gb28181Sdp gb28181Sdp = SipUtils.parseSDP(contentString);
+				SessionDescription sdp = gb28181Sdp.getBaseSdb();
 				SipURI requestUri = SipFactory.getInstance().createAddressFactory().createSipURI(sdp.getOrigin().getUsername(), event.getRemoteIpAddress() + ":" + event.getRemotePort());
 				Request reqAck = headerProvider.createAckRequest(response.getLocalAddress().getHostAddress(), requestUri, response);
 

+ 1 - 1
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/response/impl/RegisterResponseProcessor.java

@@ -102,7 +102,7 @@ public class RegisterResponseProcessor extends SIPResponseProcessorAbstract {
 				SipTransactionInfo sipTransactionInfo = new SipTransactionInfo(response);
 				platformService.online(parentPlatform, sipTransactionInfo);
 			}else {
-				platformService.offline(parentPlatform, false);
+				platformService.offline(parentPlatform, true);
 			}
 
 			// 注册/注销成功移除缓存的信息

+ 81 - 1
src/main/java/com/genersoft/iot/vmp/gb28181/utils/SipUtils.java

@@ -1,14 +1,22 @@
 package com.genersoft.iot.vmp.gb28181.utils;
 
 import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
+import com.genersoft.iot.vmp.gb28181.bean.Gb28181Sdp;
 import com.genersoft.iot.vmp.gb28181.bean.RemoteAddressInfo;
+import com.genersoft.iot.vmp.utils.DateUtil;
 import com.genersoft.iot.vmp.utils.GitUtil;
 import gov.nist.javax.sip.address.AddressImpl;
 import gov.nist.javax.sip.address.SipUri;
 import gov.nist.javax.sip.header.Subject;
 import gov.nist.javax.sip.message.SIPRequest;
+import org.apache.commons.lang3.RandomStringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.springframework.util.ObjectUtils;
 
+import javax.sdp.SdpFactory;
+import javax.sdp.SdpParseException;
+import javax.sdp.SessionDescription;
 import javax.sip.PeerUnavailableException;
 import javax.sip.SipFactory;
 import javax.sip.header.FromHeader;
@@ -16,6 +24,8 @@ import javax.sip.header.Header;
 import javax.sip.header.UserAgentHeader;
 import javax.sip.message.Request;
 import java.text.ParseException;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeParseException;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.UUID;
@@ -28,6 +38,8 @@ import java.util.UUID;
  */
 public class SipUtils {
 
+    private final static Logger logger = LoggerFactory.getLogger(SipUtils.class);
+
     public static String getUserIdFromFromHeader(Request request) {
         FromHeader fromHeader = (FromHeader)request.getHeader(FromHeader.NAME);
         return getUserIdFromFromHeader(fromHeader);
@@ -51,7 +63,7 @@ public class SipUtils {
     }
 
     public static  String getNewViaTag() {
-        return "z9hG4bK" + System.currentTimeMillis();
+        return "z9hG4bK" + RandomStringUtils.randomNumeric(10);
     }
 
     public static UserAgentHeader createUserAgentHeader(GitUtil gitUtil) throws PeerUnavailableException, ParseException {
@@ -113,6 +125,12 @@ public class SipUtils {
         strTmp = String.format("%02X", moveSpeed);
         builder.append(strTmp, 0, 2);
         builder.append(strTmp, 0, 2);
+        
+        //优化zoom低倍速下的变倍速率
+        if ((zoomSpeed > 0) && (zoomSpeed <16))
+        {
+            zoomSpeed = 16;
+        }
         strTmp = String.format("%X", zoomSpeed);
         builder.append(strTmp, 0, 1).append("0");
         //计算校验码
@@ -203,4 +221,66 @@ public class SipUtils {
         }
         return deviceChannel;
     }
+
+    public static Gb28181Sdp parseSDP(String sdpStr) throws SdpParseException {
+
+        // jainSip不支持y= f=字段, 移除以解析。
+        int ssrcIndex = sdpStr.indexOf("y=");
+        int mediaDescriptionIndex = sdpStr.indexOf("f=");
+        // 检查是否有y字段
+        SessionDescription sdp;
+        String ssrc = null;
+        String mediaDescription = null;
+        if (mediaDescriptionIndex == 0 && ssrcIndex == 0) {
+            sdp = SdpFactory.getInstance().createSessionDescription(sdpStr);
+        }else {
+            String lines[] = sdpStr.split("\\r?\\n");
+            StringBuilder sdpBuffer = new StringBuilder();
+            for (String line : lines) {
+                if (line.trim().startsWith("y=")) {
+                    ssrc = line.substring(2);
+                }else if (line.trim().startsWith("f=")) {
+                    mediaDescription = line.substring(2);
+                }else {
+                    sdpBuffer.append(line.trim()).append("\r\n");
+                }
+            }
+            sdp = SdpFactory.getInstance().createSessionDescription(sdpBuffer.toString());
+        }
+        return Gb28181Sdp.getInstance(sdp, ssrc, mediaDescription);
+    }
+
+    public static String getSsrcFromSdp(String sdpStr) {
+
+        // jainSip不支持y= f=字段, 移除以解析。
+        int ssrcIndex = sdpStr.indexOf("y=");
+        if (ssrcIndex == 0) {
+            return null;
+        }
+        String lines[] = sdpStr.split("\\r?\\n");
+        for (String line : lines) {
+            if (line.trim().startsWith("y=")) {
+                return line.substring(2);
+            }
+        }
+        return null;
+    }
+
+    public static String parseTime(String timeStr) {
+        if (ObjectUtils.isEmpty(timeStr)){
+            return null;
+        }
+        LocalDateTime localDateTime;
+        try {
+            localDateTime = LocalDateTime.parse(timeStr);
+        }catch (DateTimeParseException e) {
+            try {
+                localDateTime = LocalDateTime.parse(timeStr, DateUtil.formatterISO8601);
+            }catch (DateTimeParseException e2) {
+                logger.error("[格式化时间] 无法格式化时间: {}", timeStr);
+                return null;
+            }
+        }
+        return localDateTime.format(DateUtil.formatterISO8601);
+    }
 }

+ 328 - 181
src/main/java/com/genersoft/iot/vmp/gb28181/utils/XmlUtil.java

@@ -2,6 +2,8 @@ package com.genersoft.iot.vmp.gb28181.utils;
 
 import com.alibaba.fastjson2.JSONArray;
 import com.alibaba.fastjson2.JSONObject;
+import com.genersoft.iot.vmp.common.CivilCodePo;
+import com.genersoft.iot.vmp.conf.CivilCodeFileConf;
 import com.genersoft.iot.vmp.gb28181.bean.Device;
 import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
 import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent;
@@ -192,7 +194,7 @@ public class XmlUtil {
         CivilCode, BusinessGroup,VirtualOrganization,Other
     }
 
-    public static DeviceChannel channelContentHander(Element itemDevice, Device device, String event){
+    public static DeviceChannel channelContentHandler(Element itemDevice, Device device, String event, CivilCodeFileConf civilCodeFileConf){
         DeviceChannel deviceChannel = new DeviceChannel();
         deviceChannel.setDeviceId(device.getDeviceId());
         Element channdelIdElement = itemDevice.element("DeviceID");
@@ -210,208 +212,353 @@ public class XmlUtil {
             // 除了ADD和update情况下需要识别全部内容,
             return deviceChannel;
         }
-
-        ChannelType channelType = ChannelType.Other;
-        if (channelId.length() <= 8) {
-            channelType = ChannelType.CivilCode;
+        Element nameElement = itemDevice.element("Name");
+        if (nameElement != null) {
+            deviceChannel.setName(nameElement.getText());
+        }
+        if(channelId.length() <= 8) {
             deviceChannel.setHasAudio(false);
+            CivilCodePo parentCode = civilCodeFileConf.getParentCode(channelId);
+            if (parentCode != null) {
+                deviceChannel.setParentId(parentCode.getCode());
+                deviceChannel.setCivilCode(parentCode.getCode());
+            }else {
+                logger.warn("[xml解析] 无法确定行政区划{}的上级行政区划", channelId);
+            }
+            deviceChannel.setStatus(true);
+            return deviceChannel;
         }else {
-            if (channelId.length() == 20) {
-                int code = Integer.parseInt(channelId.substring(10, 13));
-                switch (code){
-                    case 215:
-                        channelType = ChannelType.BusinessGroup;
-                        deviceChannel.setHasAudio(false);
-                        break;
-                    case 216:
-                        channelType = ChannelType.VirtualOrganization;
-                        deviceChannel.setHasAudio(false);
-                        break;
-                    case 136:
-                    case 137:
-                    case 138:
-                        deviceChannel.setHasAudio(true);
-                        break;
-                    default:
-                        deviceChannel.setHasAudio(false);
-                        break;
-
-                }
+            if(channelId.length() != 20) {
+                logger.warn("[xml解析] 失败,编号不符合国标28181定义: {}", channelId);
+                return null;
             }
-        }
 
-        Element channdelNameElement = itemDevice.element("Name");
-        String channelName = channdelNameElement != null ? channdelNameElement.getTextTrim() : "";
-        deviceChannel.setName(channelName);
-
-        String civilCode = XmlUtil.getText(itemDevice, "CivilCode");
-        deviceChannel.setCivilCode(civilCode);
-        if (channelType == ChannelType.CivilCode && civilCode == null) {
-            deviceChannel.setParental(1);
-            // 行政区划如果没有传递具体值,则推测一个
-            if (channelId.length() > 2) {
-                deviceChannel.setCivilCode(channelId.substring(0, channelId.length() - 2));
-            }
-        }
-        if (channelType.equals(ChannelType.CivilCode)) {
-            // 行政区划其他字段没必要识别了,默认在线即可
-            deviceChannel.setStatus(1);
-            deviceChannel.setParental(1);
-            deviceChannel.setCreateTime(DateUtil.getNow());
-            deviceChannel.setUpdateTime(DateUtil.getNow());
-            return deviceChannel;
-        }
-        /**
-         * 行政区划展示设备树与业务分组展示设备树是两种不同的模式
-         * 行政区划展示设备树 各个目录之间主要靠deviceId做关联,摄像头通过CivilCode指定其属于那个行政区划;都是不超过十位的编号; 结构如下:
-         * 河北省
-         *    --> 石家庄市
-         *          --> 摄像头
-         *String parentId = XmlUtil.getText(itemDevice, "ParentID");
-         if (parentId != null) {
-         if (parentId.contains("/")) {
-         String lastParentId = parentId.substring(parentId.lastIndexOf("/") + 1);
-         String businessGroup = parentId.substring(0, parentId.indexOf("/"));
-         deviceChannel.setParentId(lastParentId);
-         }else {
-         deviceChannel.setParentId(parentId);
-         }
-         }
-         deviceCh          --> 正定县
-         *                  --> 摄像头
-         *                  --> 摄像头
-         *
-         * 业务分组展示设备树是顶级是业务分组,其下的虚拟组织靠BusinessGroupID指定其所属的业务分组;摄像头通过ParentId来指定其所属于的虚拟组织:
-         * 业务分组
-         *    --> 虚拟组织
-         *         --> 摄像头
-         *         --> 虚拟组织
-         *             --> 摄像头
-         *             --> 摄像头
-         */
-        String parentId = XmlUtil.getText(itemDevice, "ParentID");
-        String businessGroupID = XmlUtil.getText(itemDevice, "BusinessGroupID");
-        if (parentId != null) {
-            if (parentId.contains("/")) {
-                String lastParentId = parentId.substring(parentId.lastIndexOf("/") + 1);
-                if (businessGroupID == null) {
-                    businessGroupID = parentId.substring(0, parentId.indexOf("/"));
-                }
-                deviceChannel.setParentId(lastParentId);
+            int code = Integer.parseInt(channelId.substring(10, 13));
+            if (code == 136 || code == 137 || code == 138) {
+                deviceChannel.setHasAudio(true);
             }else {
-                deviceChannel.setParentId(parentId);
+                deviceChannel.setHasAudio(false);
             }
-            // 兼容设备通道信息中自己为自己父节点的情况
-            if (deviceChannel.getParentId().equals(deviceChannel.getChannelId())) {
-                deviceChannel.setParentId(null);
+            // 设备厂商
+            String manufacturer = getText(itemDevice, "Manufacturer");
+            // 设备型号
+            String model = getText(itemDevice, "Model");
+            // 设备归属
+            String owner = getText(itemDevice, "Owner");
+            // 行政区域
+            String civilCode = getText(itemDevice, "CivilCode");
+            // 虚拟组织所属的业务分组ID,业务分组根据特定的业务需求制定,一个业务分组包含一组特定的虚拟组织
+            String businessGroupID = getText(itemDevice, "BusinessGroupID");
+            // 父设备/区域/系统ID
+            String parentID = getText(itemDevice, "ParentID");
+            if (parentID != null && parentID.equalsIgnoreCase("null")) {
+                parentID = null;
             }
-        }
-        deviceChannel.setBusinessGroupId(businessGroupID);
-        if (channelType.equals(ChannelType.BusinessGroup) || channelType.equals(ChannelType.VirtualOrganization)) {
-            // 业务分组和虚拟组织 其他字段没必要识别了,默认在线即可
-            deviceChannel.setStatus(1);
-            deviceChannel.setParental(1);
-            deviceChannel.setCreateTime(DateUtil.getNow());
-            deviceChannel.setUpdateTime(DateUtil.getNow());
-            return deviceChannel;
-        }
+            // 注册方式(必选)缺省为1;1:符合IETFRFC3261标准的认证注册模式;2:基于口令的双向认证注册模式;3:基于数字证书的双向认证注册模式
+            String registerWay = getText(itemDevice, "RegisterWay");
+            // 保密属性(必选)缺省为0;0:不涉密,1:涉密
+            String secrecy = getText(itemDevice, "Secrecy");
+            // 安装地址
+            String address = getText(itemDevice, "Address");
+
+            switch (code){
+                case 200:
+                    // 系统目录
+                    if (!ObjectUtils.isEmpty(manufacturer)) {
+                        deviceChannel.setManufacture(manufacturer);
+                    }
+                    if (!ObjectUtils.isEmpty(model)) {
+                        deviceChannel.setModel(model);
+                    }
+                    if (!ObjectUtils.isEmpty(owner)) {
+                        deviceChannel.setOwner(owner);
+                    }
+                    if (!ObjectUtils.isEmpty(civilCode)) {
+                        deviceChannel.setCivilCode(civilCode);
+                        deviceChannel.setParentId(civilCode);
+                    }else {
+                        if (!ObjectUtils.isEmpty(parentID)) {
+                            deviceChannel.setParentId(parentID);
+                        }
+                    }
+                    if (!ObjectUtils.isEmpty(address)) {
+                        deviceChannel.setAddress(address);
+                    }
+                    deviceChannel.setStatus(true);
+                    if (!ObjectUtils.isEmpty(registerWay)) {
+                        try {
+                            deviceChannel.setRegisterWay(Integer.parseInt(registerWay));
+                        }catch (NumberFormatException exception) {
+                            logger.warn("[xml解析] 从通道数据获取registerWay失败: {}", registerWay);
+                        }
+                    }
+                    if (!ObjectUtils.isEmpty(secrecy)) {
+                        deviceChannel.setSecrecy(secrecy);
+                    }
+                    return deviceChannel;
+                case 215:
+                    // 业务分组
+                    deviceChannel.setStatus(true);
+                    if (!ObjectUtils.isEmpty(parentID)) {
+                        if (!parentID.trim().equalsIgnoreCase(device.getDeviceId())) {
+                            deviceChannel.setParentId(parentID);
+                        }
+                    }else {
+                        logger.warn("[xml解析] 业务分组数据中缺少关键信息->ParentId");
+                        if (!ObjectUtils.isEmpty(civilCode)) {
+                            deviceChannel.setCivilCode(civilCode);
+                        }
+                    }
+                    break;
+                case 216:
+                    // 虚拟组织
+                    deviceChannel.setStatus(true);
+                    if (!ObjectUtils.isEmpty(businessGroupID)) {
+                        deviceChannel.setBusinessGroupId(businessGroupID);
+                    }
 
-        Element statusElement = itemDevice.element("Status");
 
-        if (statusElement != null) {
-            String status = statusElement.getTextTrim().trim();
-            // ONLINE OFFLINE HIKVISION DS-7716N-E4 NVR的兼容性处理
-            if (status.equals("ON") || status.equals("On") || status.equals("ONLINE") || status.equals("OK")) {
-                deviceChannel.setStatus(1);
-            }
-            if (status.equals("OFF") || status.equals("Off") || status.equals("OFFLINE")) {
-                deviceChannel.setStatus(0);
-            }
-        }else {
-            deviceChannel.setStatus(1);
-        }
-        // 识别自带的目录标识
-        String parental = XmlUtil.getText(itemDevice, "Parental");
-        // 由于海康会错误的发送65535作为这里的取值,所以这里除非是0否则认为是1
-        if (!ObjectUtils.isEmpty(parental) && parental.length() == 1 && Integer.parseInt(parental) == 0) {
-            deviceChannel.setParental(0);
-        }else {
-            deviceChannel.setParental(1);
-        }
+                    if (!ObjectUtils.isEmpty(parentID)) {
+                        if (parentID.contains("/")) {
+                            String[] parentIdArray = parentID.split("/");
+                            parentID = parentIdArray[parentIdArray.length - 1];
+                        }
+                        deviceChannel.setParentId(parentID);
+                    }else {
+                        if (!ObjectUtils.isEmpty(businessGroupID)) {
+                            deviceChannel.setParentId(businessGroupID);
+                        }
+                    }
+                    break;
+                default:
+                    // 设备目录
+                    if (!ObjectUtils.isEmpty(manufacturer)) {
+                        deviceChannel.setManufacture(manufacturer);
+                    }
+                    if (!ObjectUtils.isEmpty(model)) {
+                        deviceChannel.setModel(model);
+                    }
+                    if (!ObjectUtils.isEmpty(owner)) {
+                        deviceChannel.setOwner(owner);
+                    }
+                    if (!ObjectUtils.isEmpty(civilCode)) {
+                        deviceChannel.setCivilCode(civilCode);
+                    }
+                    if (!ObjectUtils.isEmpty(businessGroupID)) {
+                        deviceChannel.setBusinessGroupId(businessGroupID);
+                    }
 
+                    // 警区
+                    String block = getText(itemDevice, "Block");
+                    if (!ObjectUtils.isEmpty(block)) {
+                        deviceChannel.setBlock(block);
+                    }
+                    if (!ObjectUtils.isEmpty(address)) {
+                        deviceChannel.setAddress(address);
+                    }
 
-        deviceChannel.setManufacture(XmlUtil.getText(itemDevice, "Manufacturer"));
-        deviceChannel.setModel(XmlUtil.getText(itemDevice, "Model"));
-        deviceChannel.setOwner(XmlUtil.getText(itemDevice, "Owner"));
-        deviceChannel.setCertNum(XmlUtil.getText(itemDevice, "CertNum"));
-        deviceChannel.setBlock(XmlUtil.getText(itemDevice, "Block"));
-        deviceChannel.setAddress(XmlUtil.getText(itemDevice, "Address"));
-        deviceChannel.setPassword(XmlUtil.getText(itemDevice, "Password"));
+                    if (!ObjectUtils.isEmpty(secrecy)) {
+                        deviceChannel.setSecrecy(secrecy);
+                    }
 
-        String safetyWay = XmlUtil.getText(itemDevice, "SafetyWay");
-        if (ObjectUtils.isEmpty(safetyWay)) {
-            deviceChannel.setSafetyWay(0);
-        } else {
-            deviceChannel.setSafetyWay(Integer.parseInt(safetyWay));
-        }
+                    // 当为设备时,是否有子设备(必选)1有,0没有
+                    String parental = getText(itemDevice, "Parental");
+                    if (!ObjectUtils.isEmpty(parental)) {
+                        try {
+                            // 由于海康会错误的发送65535作为这里的取值,所以这里除非是0否则认为是1
+                            if (!ObjectUtils.isEmpty(parental) && parental.length() == 1 && Integer.parseInt(parental) == 0) {
+                                deviceChannel.setParental(0);
+                            }else {
+                                deviceChannel.setParental(1);
+                            }
+                        }catch (NumberFormatException e) {
+                            logger.warn("[xml解析] 从通道数据获取 parental失败: {}", parental);
+                        }
+                    }
+                    // 父设备/区域/系统ID
+                    String realParentId = parentID;
+                    if (!ObjectUtils.isEmpty(parentID)) {
+                        if (parentID.contains("/")) {
+                            String[] parentIdArray = parentID.split("/");
+                            realParentId = parentIdArray[parentIdArray.length - 1];
+                        }
+                        deviceChannel.setParentId(realParentId);
+                    }else {
+                        if (!ObjectUtils.isEmpty(businessGroupID)) {
+                            deviceChannel.setParentId(businessGroupID);
+                        }else {
+                            if (!ObjectUtils.isEmpty(civilCode)) {
+                                deviceChannel.setParentId(civilCode);
+                            }
+                        }
+                    }
+                    // 注册方式
+                    if (!ObjectUtils.isEmpty(registerWay)) {
+                        try {
+                            int registerWayInt = Integer.parseInt(registerWay);
+                            deviceChannel.setRegisterWay(registerWayInt);
+                        }catch (NumberFormatException exception) {
+                            logger.warn("[xml解析] 从通道数据获取registerWay失败: {}", registerWay);
+                            deviceChannel.setRegisterWay(1);
+                        }
+                    }else {
+                        deviceChannel.setRegisterWay(1);
+                    }
 
-        String registerWay = XmlUtil.getText(itemDevice, "RegisterWay");
-        if (ObjectUtils.isEmpty(registerWay)) {
-            deviceChannel.setRegisterWay(1);
-        } else {
-            deviceChannel.setRegisterWay(Integer.parseInt(registerWay));
-        }
+                    // 信令安全模式(可选)缺省为0; 0:不采用;2:S/MIME 签名方式;3:S/MIME加密签名同时采用方式;4:数字摘要方式
+                    String safetyWay = getText(itemDevice, "SafetyWay");
+                    if (!ObjectUtils.isEmpty(safetyWay)) {
+                        try {
+                            deviceChannel.setSafetyWay(Integer.parseInt(safetyWay));
+                        }catch (NumberFormatException e) {
+                            logger.warn("[xml解析] 从通道数据获取 safetyWay失败: {}", safetyWay);
+                        }
+                    }
 
-        if (XmlUtil.getText(itemDevice, "Certifiable") == null
-                || XmlUtil.getText(itemDevice, "Certifiable") == "") {
-            deviceChannel.setCertifiable(0);
-        } else {
-            deviceChannel.setCertifiable(Integer.parseInt(XmlUtil.getText(itemDevice, "Certifiable")));
-        }
+                    // 证书序列号(有证书的设备必选)
+                    String certNum = getText(itemDevice, "CertNum");
+                    if (!ObjectUtils.isEmpty(certNum)) {
+                        deviceChannel.setCertNum(certNum);
+                    }
 
-        if (XmlUtil.getText(itemDevice, "ErrCode") == null
-                || XmlUtil.getText(itemDevice, "ErrCode") == "") {
-            deviceChannel.setErrCode(0);
-        } else {
-            deviceChannel.setErrCode(Integer.parseInt(XmlUtil.getText(itemDevice, "ErrCode")));
-        }
+                    // 证书有效标识(有证书的设备必选)缺省为0;证书有效标识:0:无效 1:有效
+                    String certifiable = getText(itemDevice, "Certifiable");
+                    if (!ObjectUtils.isEmpty(certifiable)) {
+                        try {
+                            deviceChannel.setCertifiable(Integer.parseInt(certifiable));
+                        }catch (NumberFormatException e) {
+                            logger.warn("[xml解析] 从通道数据获取 Certifiable失败: {}", certifiable);
+                        }
+                    }
 
-        deviceChannel.setEndTime(XmlUtil.getText(itemDevice, "EndTime"));
-        deviceChannel.setSecrecy(XmlUtil.getText(itemDevice, "Secrecy"));
-        deviceChannel.setIpAddress(XmlUtil.getText(itemDevice, "IPAddress"));
-        if (XmlUtil.getText(itemDevice, "Port") == null || XmlUtil.getText(itemDevice, "Port") == "") {
-            deviceChannel.setPort(0);
-        } else {
-            deviceChannel.setPort(Integer.parseInt(XmlUtil.getText(itemDevice, "Port")));
-        }
+                    // 无效原因码(有证书且证书无效的设备必选)
+                    String errCode = getText(itemDevice, "ErrCode");
+                    if (!ObjectUtils.isEmpty(errCode)) {
+                        try {
+                            deviceChannel.setErrCode(Integer.parseInt(errCode));
+                        }catch (NumberFormatException e) {
+                            logger.warn("[xml解析] 从通道数据获取 ErrCode失败: {}", errCode);
+                        }
+                    }
 
+                    // 证书终止有效期(有证书的设备必选)
+                    String endTime = getText(itemDevice, "EndTime");
+                    if (!ObjectUtils.isEmpty(endTime)) {
+                        deviceChannel.setEndTime(endTime);
+                    }
 
-        String longitude = XmlUtil.getText(itemDevice, "Longitude");
-        if (NumericUtil.isDouble(longitude)) {
-            deviceChannel.setLongitude(Double.parseDouble(longitude));
-        } else {
-            deviceChannel.setLongitude(0.00);
-        }
-        String latitude = XmlUtil.getText(itemDevice, "Latitude");
-        if (NumericUtil.isDouble(latitude)) {
-            deviceChannel.setLatitude(Double.parseDouble(latitude));
-        } else {
-            deviceChannel.setLatitude(0.00);
-        }
 
-        deviceChannel.setGpsTime(DateUtil.getNow());
+                    // 设备/区域/系统IP地址
+                    String ipAddress = getText(itemDevice, "IPAddress");
+                    if (!ObjectUtils.isEmpty(ipAddress)) {
+                        deviceChannel.setIpAddress(ipAddress);
+                    }
+
+                    // 设备/区域/系统端口
+                    String port = getText(itemDevice, "Port");
+                    if (!ObjectUtils.isEmpty(port)) {
+                        try {
+                            deviceChannel.setPort(Integer.parseInt(port));
+                        }catch (NumberFormatException e) {
+                            logger.warn("[xml解析] 从通道数据获取 Port失败: {}", port);
+                        }
+                    }
+
+                    // 设备口令
+                    String password = getText(itemDevice, "Password");
+                    if (!ObjectUtils.isEmpty(password)) {
+                        deviceChannel.setPassword(password);
+                    }
 
 
-        if (XmlUtil.getText(itemDevice, "PTZType") == null || "".equals(XmlUtil.getText(itemDevice, "PTZType"))) {
-            //兼容INFO中的信息
-            Element info = itemDevice.element("Info");
-            if(XmlUtil.getText(info, "PTZType") == null || "".equals(XmlUtil.getText(info, "PTZType"))){
-                deviceChannel.setPTZType(0);
-            }else{
-                deviceChannel.setPTZType(Integer.parseInt(XmlUtil.getText(info, "PTZType")));
+                    // 设备状态
+                    String status = getText(itemDevice, "Status");
+                    if (status != null) {
+                        // ONLINE OFFLINE HIKVISION DS-7716N-E4 NVR的兼容性处理
+                        if (status.equals("ON") || status.equals("On") || status.equals("ONLINE") || status.equals("OK")) {
+                            deviceChannel.setStatus(true);
+                        }
+                        if (status.equals("OFF") || status.equals("Off") || status.equals("OFFLINE")) {
+                            deviceChannel.setStatus(false);
+                        }
+                    }else {
+                        deviceChannel.setStatus(true);
+                    }
+
+                    // 经度
+                    String longitude = getText(itemDevice, "Longitude");
+                    if (NumericUtil.isDouble(longitude)) {
+                        deviceChannel.setLongitude(Double.parseDouble(longitude));
+                    } else {
+                        deviceChannel.setLongitude(0.00);
+                    }
+
+                    // 纬度
+                    String latitude = getText(itemDevice, "Latitude");
+                    if (NumericUtil.isDouble(latitude)) {
+                        deviceChannel.setLatitude(Double.parseDouble(latitude));
+                    } else {
+                        deviceChannel.setLatitude(0.00);
+                    }
+
+                    deviceChannel.setGpsTime(DateUtil.getNow());
+
+                    // -摄像机类型扩展,标识摄像机类型:1-球机;2-半球;3-固定枪机;4-遥控枪机。当目录项为摄像机时可选
+                    String ptzType = getText(itemDevice, "PTZType");
+                    if (ObjectUtils.isEmpty(ptzType)) {
+                        //兼容INFO中的信息
+                        Element info = itemDevice.element("Info");
+                        String ptzTypeFromInfo = XmlUtil.getText(info, "PTZType");
+                        if(!ObjectUtils.isEmpty(ptzTypeFromInfo)){
+                            try {
+                                deviceChannel.setPTZType(Integer.parseInt(ptzTypeFromInfo));
+                            }catch (NumberFormatException e){
+                                logger.warn("[xml解析] 从通道数据info中获取PTZType失败: {}", ptzTypeFromInfo);
+                            }
+                        }
+                    } else {
+                        try {
+                            deviceChannel.setPTZType(Integer.parseInt(ptzType));
+                        }catch (NumberFormatException e){
+                            logger.warn("[xml解析] 从通道数据中获取PTZType失败: {}", ptzType);
+                        }
+                    }
+
+                    // TODO 摄像机位置类型扩展。
+                    // 1-省际检查站、
+                    // 2-党政机关、
+                    // 3-车站码头、
+                    // 4-中心广场、
+                    // 5-体育场馆、
+                    // 6-商业中心、
+                    // 7-宗教场所、
+                    // 8-校园周边、
+                    // 9-治安复杂区域、
+                    // 10-交通干线。
+                    // String positionType = getText(itemDevice, "PositionType");
+
+                    // TODO 摄像机安装位置室外、室内属性。1-室外、2-室内。
+                    // String roomType = getText(itemDevice, "RoomType");
+                    // TODO 摄像机用途属性
+                    // String useType = getText(itemDevice, "UseType");
+                    // TODO 摄像机补光属性。1-无补光、2-红外补光、3-白光补光
+                    // String supplyLightType = getText(itemDevice, "SupplyLightType");
+                    // TODO 摄像机监视方位属性。1-东、2-西、3-南、4-北、5-东南、6-东北、7-西南、8-西北。
+                    // String directionType = getText(itemDevice, "DirectionType");
+                    // TODO 摄像机支持的分辨率,可有多个分辨率值,各个取值间以“/”分隔。分辨率取值参见附录 F中SDPf字段规定
+                    // String resolution = getText(itemDevice, "Resolution");
+
+                    // TODO 下载倍速范围(可选),各可选参数以“/”分隔,如设备支持1,2,4倍速下载则应写为“1/2/4
+                    // String downloadSpeed = getText(itemDevice, "DownloadSpeed");
+                    // TODO 空域编码能力,取值0:不支持;1:1级增强(1个增强层);2:2级增强(2个增强层);3:3级增强(3个增强层)
+                    // String svcSpaceSupportMode = getText(itemDevice, "SVCSpaceSupportMode");
+                    // TODO 时域编码能力,取值0:不支持;1:1级增强;2:2级增强;3:3级增强
+                    // String svcTimeSupportMode = getText(itemDevice, "SVCTimeSupportMode");
+
+
+                    deviceChannel.setSecrecy(secrecy);
+                    break;
             }
-        } else {
-            deviceChannel.setPTZType(Integer.parseInt(XmlUtil.getText(itemDevice, "PTZType")));
         }
 
         return deviceChannel;

+ 15 - 15
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java

@@ -131,14 +131,12 @@ public class ZLMHttpHookListener {
     @PostMapping(value = "/on_server_keepalive", produces = "application/json;charset=UTF-8")
     public HookResult onServerKeepalive(@RequestBody OnServerKeepaliveHookParam param) {
 
-//        logger.info("[ZLM HOOK] 收到zlm心跳:" + param.getMediaServerId());
 
         taskExecutor.execute(() -> {
             List<ZlmHttpHookSubscribe.Event> subscribes = this.subscribe.getSubscribes(HookType.on_server_keepalive);
-            JSONObject json = (JSONObject) JSON.toJSON(param);
             if (subscribes != null && subscribes.size() > 0) {
                 for (ZlmHttpHookSubscribe.Event subscribe : subscribes) {
-                    subscribe.response(null, json);
+                    subscribe.response(null, param);
                 }
             }
         });
@@ -165,7 +163,7 @@ public class ZLMHttpHookListener {
             if (subscribe != null) {
                 MediaServerItem mediaInfo = mediaServerService.getOne(mediaServerId);
                 if (mediaInfo != null) {
-                    subscribe.response(mediaInfo, json);
+                    subscribe.response(mediaInfo, param);
                 }
             }
         });
@@ -198,13 +196,13 @@ public class ZLMHttpHookListener {
             if (userSetting.getPushAuthority()) {
                 // 推流鉴权
                 if (param.getParams() == null) {
-                    logger.info("推流鉴权失败: 缺少要参数:sign=md5(user表的pushKey)");
+                    logger.info("推流鉴权失败: 缺少要参数:sign=md5(user表的pushKey)");
                     return new HookResultForOnPublish(401, "Unauthorized");
                 }
                 Map<String, String> paramMap = urlParamToMap(param.getParams());
                 String sign = paramMap.get("sign");
                 if (sign == null) {
-                    logger.info("推流鉴权失败: 缺少要参数:sign=md5(user表的pushKey)");
+                    logger.info("推流鉴权失败: 缺少要参数:sign=md5(user表的pushKey)");
                     return new HookResultForOnPublish(401, "Unauthorized");
                 }
                 // 推流自定义播放鉴权码
@@ -241,7 +239,7 @@ public class ZLMHttpHookListener {
             ZlmHttpHookSubscribe.Event subscribe = this.subscribe.sendNotify(HookType.on_publish, json);
             if (subscribe != null) {
                 if (mediaInfo != null) {
-                    subscribe.response(mediaInfo, json);
+                    subscribe.response(mediaInfo, param);
                 } else {
                     new HookResultForOnPublish(1, "zlm not register");
                 }
@@ -321,7 +319,7 @@ public class ZLMHttpHookListener {
                 return;
             }
             if (subscribe != null) {
-                subscribe.response(mediaInfo, json);
+                subscribe.response(mediaInfo, param);
             }
 
             List<OnStreamChangedHookParam.MediaTrack> tracks = param.getTracks();
@@ -551,7 +549,9 @@ public class ZLMHttpHookListener {
                 Device device = deviceService.getDevice(inviteInfo.getDeviceId());
                 if (device != null) {
                     try {
-                        if (inviteStreamService.getInviteInfo(inviteInfo.getType(), inviteInfo.getDeviceId(), inviteInfo.getChannelId(), inviteInfo.getStream()) != null) {
+                        InviteInfo info = inviteStreamService.getInviteInfo(inviteInfo.getType(),
+                                inviteInfo.getDeviceId(), inviteInfo.getChannelId(), inviteInfo.getStream());
+                        if (info != null) {
                             cmder.streamByeCmd(device, inviteInfo.getChannelId(),
                                     inviteInfo.getStream(), null);
                         }
@@ -578,13 +578,13 @@ public class ZLMHttpHookListener {
             // 拉流代理
             StreamProxyItem streamProxyItem = streamProxyService.getStreamProxyByAppAndStream(param.getApp(), param.getStream());
             if (streamProxyItem != null) {
-                if (streamProxyItem.isEnable_remove_none_reader()) {
+                if (streamProxyItem.isEnableDisableNoneReader()) {
                     // 无人观看自动移除
                     ret.put("close", true);
                     streamProxyService.del(param.getApp(), param.getStream());
-                    String url = streamProxyItem.getUrl() != null ? streamProxyItem.getUrl() : streamProxyItem.getSrc_url();
+                    String url = streamProxyItem.getUrl() != null ? streamProxyItem.getUrl() : streamProxyItem.getSrcUrl();
                     logger.info("[{}/{}]<-[{}] 拉流代理无人观看已经移除", param.getApp(), param.getStream(), url);
-                } else if (streamProxyItem.isEnable_disable_none_reader()) {
+                } else if (streamProxyItem.isEnableDisableNoneReader()) {
                     // 无人观看停用
                     ret.put("close", true);
                     // 修改数据
@@ -669,7 +669,7 @@ public class ZLMHttpHookListener {
         } else {
             // 拉流代理
             StreamProxyItem streamProxyByAppAndStream = streamProxyService.getStreamProxyByAppAndStream(param.getApp(), param.getStream());
-            if (streamProxyByAppAndStream != null && streamProxyByAppAndStream.isEnable_disable_none_reader()) {
+            if (streamProxyByAppAndStream != null && streamProxyByAppAndStream.isEnableDisableNoneReader()) {
                 streamProxyService.start(param.getApp(), param.getStream());
             }
             DeferredResult<HookResult> result = new DeferredResult<>();
@@ -693,7 +693,7 @@ public class ZLMHttpHookListener {
             List<ZlmHttpHookSubscribe.Event> subscribes = this.subscribe.getSubscribes(HookType.on_server_started);
             if (subscribes != null && subscribes.size() > 0) {
                 for (ZlmHttpHookSubscribe.Event subscribe : subscribes) {
-                    subscribe.response(null, jsonObject);
+                    subscribe.response(null, zlmServerConfig);
                 }
             }
             mediaServerService.zlmServerOnline(zlmServerConfig);
@@ -749,7 +749,7 @@ public class ZLMHttpHookListener {
             List<ZlmHttpHookSubscribe.Event> subscribes = this.subscribe.getSubscribes(HookType.on_rtp_server_timeout);
             if (subscribes != null && subscribes.size() > 0) {
                 for (ZlmHttpHookSubscribe.Event subscribe : subscribes) {
-                    subscribe.response(null, json);
+                    subscribe.response(null, param);
                 }
             }
         });

+ 0 - 1
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRESTfulUtils.java

@@ -157,7 +157,6 @@ public class ZLMRESTfulUtils {
 
     public void sendGetForImg(MediaServerItem mediaServerItem, String api, Map<String, Object> params, String targetPath, String fileName) {
         String url = String.format("http://%s:%s/index/api/%s", mediaServerItem.getIp(), mediaServerItem.getHttpPort(), api);
-        logger.debug(url);
         HttpUrl parseUrl = HttpUrl.parse(url);
         if (parseUrl == null) {
             return;

+ 21 - 17
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRTPServerFactory.java

@@ -9,6 +9,11 @@ import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
 import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeFactory;
 import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForRtpServerTimeout;
 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
+import com.genersoft.iot.vmp.media.zlm.dto.hook.HookParam;
+import com.genersoft.iot.vmp.media.zlm.dto.hook.OnRtpServerTimeoutHookParam;
+import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeFactory;
+import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForRtpServerTimeout;
+import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -228,7 +233,7 @@ public class ZLMRTPServerFactory {
         int localPort = 0;
         if (userSetting.getGbSendStreamStrict()) {
             if (userSetting.getGbSendStreamStrict()) {
-                localPort = keepPort(serverItem, ssrc, null);
+                localPort = keepPort(serverItem, ssrc, localPort);
                 if (localPort == 0) {
                     return null;
                 }
@@ -264,7 +269,7 @@ public class ZLMRTPServerFactory {
         // 默认为随机端口
         int localPort = 0;
         if (userSetting.getGbSendStreamStrict()) {
-            localPort = keepPort(serverItem, ssrc, null);
+            localPort = keepPort(serverItem, ssrc, localPort);
             if (localPort == 0) {
                 return null;
             }
@@ -290,9 +295,6 @@ public class ZLMRTPServerFactory {
      */
     public int keepPort(MediaServerItem serverItem, String ssrc, Integer localPort) {
         Map<String, Object> param = new HashMap<>(3);
-        if (localPort == null) {
-            localPort = 0;
-        }
         param.put("port", localPort);
         param.put("enable_tcp", 1);
         param.put("stream_id", ssrc);
@@ -302,22 +304,24 @@ public class ZLMRTPServerFactory {
             HookSubscribeForRtpServerTimeout hookSubscribeForRtpServerTimeout = HookSubscribeFactory.on_rtp_server_timeout(ssrc, null, serverItem.getId());
             Integer finalLocalPort = localPort;
             hookSubscribe.addSubscribe(hookSubscribeForRtpServerTimeout,
-                    (MediaServerItem mediaServerItem, JSONObject response)->{
-                        if (ssrc.equals(response.getString("ssrc"))) {
-                            logger.info("[上级点播] {}->监听端口到期继续保持监听", ssrc);
-                            int port = keepPort(serverItem, ssrc, finalLocalPort);
-                            if (port == 0) {
-                                logger.info("[上级点播] {}->监听端口失败,移除监听", ssrc);
-                                hookSubscribe.removeSubscribe(hookSubscribeForRtpServerTimeout);
-                            }
+                    (MediaServerItem mediaServerItem, HookParam hookParam)->{
+                        logger.info("[上级点播] {}->监听端口到期继续保持监听: {}", ssrc, finalLocalPort);
+                        OnRtpServerTimeoutHookParam rtpServerTimeoutHookParam = (OnRtpServerTimeoutHookParam) hookParam;
+                        if (!ssrc.equals(rtpServerTimeoutHookParam.getSsrc())) {
+                            return;
+                        }
+                        int port = keepPort(serverItem, ssrc, finalLocalPort);
+                        if (port == 0) {
+                            logger.info("[上级点播] {}->监听端口失败,移除监听", ssrc);
+                            hookSubscribe.removeSubscribe(hookSubscribeForRtpServerTimeout);
                         }
                     });
-        logger.info("[保持端口] {}->监听端口: {}", ssrc, localPort);
-            logger.info("[保持端口] {}->监听端口: {}", ssrc, localPort);
+            logger.info("[上级点播] {}->监听端口: {}", ssrc, localPort);
+            return localPort;
         }else {
-            logger.info("[保持端口] 监听端口失败: {}", ssrc);
+            logger.info("[上级点播] 监听端口失败: {}->{}", ssrc, localPort);
+            return 0;
         }
-        return localPort;
     }
 
     /**

+ 2 - 2
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRunner.java

@@ -65,8 +65,8 @@ public class ZLMRunner implements CommandLineRunner {
         HookSubscribeForServerStarted hookSubscribeForServerStarted = HookSubscribeFactory.on_server_started();
         // 订阅 zlm启动事件, 新的zlm也会从这里进入系统
         hookSubscribe.addSubscribe(hookSubscribeForServerStarted,
-                (MediaServerItem mediaServerItem, JSONObject response)->{
-            ZLMServerConfig zlmServerConfig = response.to(ZLMServerConfig.class);
+                (mediaServerItem, hookParam)->{
+            ZLMServerConfig zlmServerConfig = (ZLMServerConfig)hookParam;
             if (zlmServerConfig !=null ) {
                 if (startGetMedia != null) {
                     startGetMedia.remove(zlmServerConfig.getGeneralMediaServerId());

+ 2 - 1
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMServerConfig.java

@@ -1,8 +1,9 @@
 package com.genersoft.iot.vmp.media.zlm;
 
 import com.alibaba.fastjson2.annotation.JSONField;
+import com.genersoft.iot.vmp.media.zlm.dto.hook.HookParam;
 
-public class ZLMServerConfig {
+public class ZLMServerConfig extends HookParam {
 
     @JSONField(name = "api.apiDebug")
     private String apiDebug;

+ 2 - 1
src/main/java/com/genersoft/iot/vmp/media/zlm/ZlmHttpHookSubscribe.java

@@ -4,6 +4,7 @@ import com.alibaba.fastjson2.JSONObject;
 import com.genersoft.iot.vmp.media.zlm.dto.HookType;
 import com.genersoft.iot.vmp.media.zlm.dto.IHookSubscribe;
 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
+import com.genersoft.iot.vmp.media.zlm.dto.hook.HookParam;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.scheduling.annotation.Scheduled;
@@ -26,7 +27,7 @@ public class ZlmHttpHookSubscribe {
 
     @FunctionalInterface
     public interface Event{
-        void response(MediaServerItem mediaServerItem, JSONObject response);
+        void response(MediaServerItem mediaServerItem, HookParam hookParam);
     }
 
     private Map<HookType, Map<IHookSubscribe, ZlmHttpHookSubscribe.Event>> allSubscribes = new ConcurrentHashMap<>();

+ 45 - 55
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/StreamProxyItem.java

@@ -20,28 +20,26 @@ public class StreamProxyItem extends GbStream {
     @Schema(description = "拉流地址")
     private String url;
     @Schema(description = "拉流地址")
-    private String src_url;
+    private String srcUrl;
     @Schema(description = "目标地址")
-    private String dst_url;
+    private String dstUrl;
     @Schema(description = "超时时间")
-    private int timeout_ms;
+    private int timeoutMs;
     @Schema(description = "ffmpeg模板KEY")
-    private String ffmpeg_cmd_key;
+    private String ffmpegCmdKey;
     @Schema(description = "rtsp拉流时,拉流方式,0:tcp,1:udp,2:组播")
-    private String rtp_type;
+    private String rtpType;
     @Schema(description = "是否启用")
     private boolean enable;
     @Schema(description = "是否启用音频")
-    private boolean enable_audio;
+    private boolean enableAudio;
     @Schema(description = "是否启用MP4")
-    private boolean enable_mp4;
+    private boolean enableMp4;
     @Schema(description = "是否 无人观看时删除")
-    private boolean enable_remove_none_reader;
+    private boolean enableRemoveNoneReader;
 
     @Schema(description = "是否 无人观看时自动停用")
-    private boolean enable_disable_none_reader;
-    @Schema(description = "创建时间")
-    private String createTime;
+    private boolean enableDisableNoneReader;
 
     public String getType() {
         return type;
@@ -89,44 +87,44 @@ public class StreamProxyItem extends GbStream {
         this.url = url;
     }
 
-    public String getSrc_url() {
-        return src_url;
+    public String getSrcUrl() {
+        return srcUrl;
     }
 
-    public void setSrc_url(String src_url) {
-        this.src_url = src_url;
+    public void setSrcUrl(String src_url) {
+        this.srcUrl = src_url;
     }
 
-    public String getDst_url() {
-        return dst_url;
+    public String getDstUrl() {
+        return dstUrl;
     }
 
-    public void setDst_url(String dst_url) {
-        this.dst_url = dst_url;
+    public void setDstUrl(String dst_url) {
+        this.dstUrl = dst_url;
     }
 
-    public int getTimeout_ms() {
-        return timeout_ms;
+    public int getTimeoutMs() {
+        return timeoutMs;
     }
 
-    public void setTimeout_ms(int timeout_ms) {
-        this.timeout_ms = timeout_ms;
+    public void setTimeoutMs(int timeout_ms) {
+        this.timeoutMs = timeout_ms;
     }
 
-    public String getFfmpeg_cmd_key() {
-        return ffmpeg_cmd_key;
+    public String getFfmpegCmdKey() {
+        return ffmpegCmdKey;
     }
 
-    public void setFfmpeg_cmd_key(String ffmpeg_cmd_key) {
-        this.ffmpeg_cmd_key = ffmpeg_cmd_key;
+    public void setFfmpegCmdKey(String ffmpeg_cmd_key) {
+        this.ffmpegCmdKey = ffmpeg_cmd_key;
     }
 
-    public String getRtp_type() {
-        return rtp_type;
+    public String getRtpType() {
+        return rtpType;
     }
 
-    public void setRtp_type(String rtp_type) {
-        this.rtp_type = rtp_type;
+    public void setRtpType(String rtp_type) {
+        this.rtpType = rtp_type;
     }
 
     public boolean isEnable() {
@@ -137,45 +135,37 @@ public class StreamProxyItem extends GbStream {
         this.enable = enable;
     }
 
-    public boolean isEnable_mp4() {
-        return enable_mp4;
+    public boolean isEnableMp4() {
+        return enableMp4;
     }
 
-    public void setEnable_mp4(boolean enable_mp4) {
-        this.enable_mp4 = enable_mp4;
+    public void setEnableMp4(boolean enable_mp4) {
+        this.enableMp4 = enable_mp4;
     }
 
-    @Override
-    public String getCreateTime() {
-        return createTime;
+    public boolean isEnableRemoveNoneReader() {
+        return enableRemoveNoneReader;
     }
 
-    @Override
-    public void setCreateTime(String createTime) {
-        this.createTime = createTime;
+    public void setEnableRemoveNoneReader(boolean enable_remove_none_reader) {
+        this.enableRemoveNoneReader = enable_remove_none_reader;
     }
 
-    public boolean isEnable_remove_none_reader() {
-        return enable_remove_none_reader;
+    public boolean isEnableDisableNoneReader() {
+        return enableDisableNoneReader;
     }
 
-    public void setEnable_remove_none_reader(boolean enable_remove_none_reader) {
-        this.enable_remove_none_reader = enable_remove_none_reader;
+    public void setEnableDisableNoneReader(boolean enable_disable_none_reader) {
+        this.enableDisableNoneReader = enable_disable_none_reader;
     }
 
-    public boolean isEnable_disable_none_reader() {
-        return enable_disable_none_reader;
+    public boolean isEnableAudio() {
+        return enableAudio;
     }
 
-    public void setEnable_disable_none_reader(boolean enable_disable_none_reader) {
-        this.enable_disable_none_reader = enable_disable_none_reader;
+    public void setEnableAudio(boolean enable_audio) {
+        this.enableAudio = enable_audio;
     }
 
-    public boolean isEnable_audio() {
-        return enable_audio;
-    }
 
-    public void setEnable_audio(boolean enable_audio) {
-        this.enable_audio = enable_audio;
-    }
 }

+ 60 - 0
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/StreamPushItem.java

@@ -325,5 +325,65 @@ public class StreamPushItem extends GbStream implements Comparable<StreamPushIte
     public void setSelf(boolean self) {
         this.self = self;
     }
+
+//    @Override
+//    public Integer getGbStreamId() {
+//        return super.getGbStreamId();
+//    }
+//
+//    @Override
+//    public void setGbStreamId(Integer gbStreamId) {
+//        super.setGbStreamId(gbStreamId);
+//    }
+//
+//
+//    public String getGbId() {
+//        return super.getGbId();
+//    }
+//
+//    public void setGbId(String gbId) {
+//       super.setGbId(gbId);
+//    }
+//
+//    public String getName() {
+//        return super.getName();
+//    }
+//
+//    public void setName(String name) {
+//        super.setName(name);
+//    }
+//
+//    public double getLongitude() {
+//        return super.getLongitude();
+//    }
+//
+//    public void setLongitude(double longitude) {
+//        super.setLongitude(longitude);
+//    }
+//
+//    public double getLatitude() {
+//        return super.getLatitude();
+//    }
+//
+//    public void setLatitude(double latitude) {
+//        super.setLatitude(latitude);
+//    }
+//
+//    public String getStreamType() {
+//        return super.getStreamType();
+//    }
+//
+//    public void setStreamType(String streamType) {
+//        super.setStreamType(streamType);
+//    }
+//
+//    public boolean isStatus() {
+//        return super.isStatus();
+//    }
+//
+//    public void setStatus(boolean status) {
+//        super.setStatus(status);
+//    }
+
 }
 

+ 2 - 0
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/HookResultForOnPublish.java

@@ -50,4 +50,6 @@ public class HookResultForOnPublish extends HookResult{
     public void setMp4_save_path(String mp4_save_path) {
         this.mp4_save_path = mp4_save_path;
     }
+
+
 }

+ 10 - 1
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnPlayHookParam.java

@@ -81,6 +81,15 @@ public class OnPlayHookParam extends HookParam{
 
     @Override
     public String toString() {
-        return String.format("%s://%s:%s/%s/%s?%s", schema, ip, port, app, stream, params);
+        return "OnPlayHookParam{" +
+                "id='" + id + '\'' +
+                ", app='" + app + '\'' +
+                ", stream='" + stream + '\'' +
+                ", ip='" + ip + '\'' +
+                ", params='" + params + '\'' +
+                ", port=" + port +
+                ", schema='" + schema + '\'' +
+                ", vhost='" + vhost + '\'' +
+                '}';
     }
 }

+ 10 - 1
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnPublishHookParam.java

@@ -81,6 +81,15 @@ public class OnPublishHookParam extends HookParam{
 
     @Override
     public String toString() {
-        return String.format("%s://%s:%s/%s/%s?%s", schema, ip, port, app, stream, params);
+        return "OnPublishHookParam{" +
+                "id='" + id + '\'' +
+                ", app='" + app + '\'' +
+                ", stream='" + stream + '\'' +
+                ", ip='" + ip + '\'' +
+                ", params='" + params + '\'' +
+                ", port=" + port +
+                ", schema='" + schema + '\'' +
+                ", vhost='" + vhost + '\'' +
+                '}';
     }
 }

+ 11 - 0
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnRtpServerTimeoutHookParam.java

@@ -50,4 +50,15 @@ public class OnRtpServerTimeoutHookParam extends HookParam{
     public void setSsrc(String ssrc) {
         this.ssrc = ssrc;
     }
+
+    @Override
+    public String toString() {
+        return "OnRtpServerTimeoutHookParam{" +
+                "local_port=" + local_port +
+                ", stream_id='" + stream_id + '\'' +
+                ", tcpMode=" + tcpMode +
+                ", re_use_port=" + re_use_port +
+                ", ssrc='" + ssrc + '\'' +
+                '}';
+    }
 }

+ 8 - 0
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnSendRtpStoppedHookParam.java

@@ -24,4 +24,12 @@ public class OnSendRtpStoppedHookParam extends HookParam{
     public void setStream(String stream) {
         this.stream = stream;
     }
+
+    @Override
+    public String toString() {
+        return "OnSendRtpStoppedHookParam{" +
+                "app='" + app + '\'' +
+                ", stream='" + stream + '\'' +
+                '}';
+    }
 }

+ 7 - 0
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnServerKeepaliveHookParam.java

@@ -17,4 +17,11 @@ public class OnServerKeepaliveHookParam extends HookParam{
     public void setData(ServerKeepaliveData data) {
         this.data = data;
     }
+
+    @Override
+    public String toString() {
+        return "OnServerKeepaliveHookParam{" +
+                "data=" + data +
+                '}';
+    }
 }

+ 10 - 0
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnStreamChangedHookParam.java

@@ -430,4 +430,14 @@ public class OnStreamChangedHookParam extends HookParam{
     public void setCallId(String callId) {
         this.callId = callId;
     }
+
+    @Override
+    public String toString() {
+        return "OnStreamChangedHookParam{" +
+                "regist=" + regist +
+                ", app='" + app + '\'' +
+                ", stream='" + stream + '\'' +
+                ", severId='" + severId + '\'' +
+                '}';
+    }
 }

+ 10 - 0
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnStreamNoneReaderHookParam.java

@@ -38,4 +38,14 @@ public class OnStreamNoneReaderHookParam extends HookParam{
     public void setVhost(String vhost) {
         this.vhost = vhost;
     }
+
+    @Override
+    public String toString() {
+        return "OnStreamNoneReaderHookParam{" +
+                "schema='" + schema + '\'' +
+                ", app='" + app + '\'' +
+                ", stream='" + stream + '\'' +
+                ", vhost='" + vhost + '\'' +
+                '}';
+    }
 }

+ 10 - 1
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnStreamNotFoundHookParam.java

@@ -81,6 +81,15 @@ public class OnStreamNotFoundHookParam extends HookParam{
 
     @Override
     public String toString() {
-        return String.format("%s://%s:%s/%s/%s?%s", schema, ip, port, app, stream, params);
+        return "OnStreamNotFoundHookParam{" +
+                "id='" + id + '\'' +
+                ", app='" + app + '\'' +
+                ", stream='" + stream + '\'' +
+                ", ip='" + ip + '\'' +
+                ", params='" + params + '\'' +
+                ", port=" + port +
+                ", schema='" + schema + '\'' +
+                ", vhost='" + vhost + '\'' +
+                '}';
     }
 }

+ 2 - 2
src/main/java/com/genersoft/iot/vmp/service/IDeviceChannelService.java

@@ -2,7 +2,7 @@ package com.genersoft.iot.vmp.service;
 
 import com.genersoft.iot.vmp.gb28181.bean.Device;
 import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
-import com.genersoft.iot.vmp.vmanager.bean.ResourceBaceInfo;
+import com.genersoft.iot.vmp.vmanager.bean.ResourceBaseInfo;
 import com.genersoft.iot.vmp.vmanager.gb28181.platform.bean.ChannelReduce;
 
 import java.util.List;
@@ -38,7 +38,7 @@ public interface IDeviceChannelService {
      * 获取统计信息
      * @return
      */
-    ResourceBaceInfo getOverview();
+    ResourceBaseInfo getOverview();
 
     /**
      * 查询所有未分配的通道

+ 2 - 2
src/main/java/com/genersoft/iot/vmp/service/IDeviceService.java

@@ -5,7 +5,7 @@ import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
 import com.genersoft.iot.vmp.gb28181.bean.SipTransactionInfo;
 import com.genersoft.iot.vmp.gb28181.bean.SyncStatus;
 import com.genersoft.iot.vmp.vmanager.bean.BaseTree;
-import com.genersoft.iot.vmp.vmanager.bean.ResourceBaceInfo;
+import com.genersoft.iot.vmp.vmanager.bean.ResourceBaseInfo;
 
 import java.util.List;
 
@@ -162,7 +162,7 @@ public interface IDeviceService {
      * 获取统计信息
      * @return
      */
-    ResourceBaceInfo getOverview();
+    ResourceBaseInfo getOverview();
 
     /**
      * 获取所有设备

+ 12 - 2
src/main/java/com/genersoft/iot/vmp/service/IInviteStreamService.java

@@ -2,7 +2,7 @@ package com.genersoft.iot.vmp.service;
 
 import com.genersoft.iot.vmp.common.InviteInfo;
 import com.genersoft.iot.vmp.common.InviteSessionType;
-import com.genersoft.iot.vmp.service.bean.InviteErrorCallback;
+import com.genersoft.iot.vmp.service.bean.ErrorCallback;
 
 /**
  * 记录国标点播的状态,包括实时预览,下载,录像回放
@@ -14,6 +14,8 @@ public interface IInviteStreamService {
      */
     void updateInviteInfo(InviteInfo inviteInfo);
 
+    InviteInfo updateInviteInfoForStream(InviteInfo inviteInfo, String stream);
+
     /**
      * 获取点播的状态信息
      */
@@ -54,7 +56,7 @@ public interface IInviteStreamService {
     /**
      * 添加一个invite回调
      */
-    void once(InviteSessionType type, String deviceId, String channelId, String stream,  InviteErrorCallback<Object> callback);
+    void once(InviteSessionType type, String deviceId, String channelId, String stream,  ErrorCallback<Object> callback);
 
     /**
      * 调用一个invite回调
@@ -65,4 +67,12 @@ public interface IInviteStreamService {
      * 清空一个设备的所有invite信息
      */
     void clearInviteInfo(String deviceId);
+
+    /**
+     * 统计同一个zlm下的国标收流个数
+     */
+    int getStreamInfoCount(String mediaServerId);
+
+
+
 }

+ 9 - 7
src/main/java/com/genersoft/iot/vmp/service/IPlayService.java

@@ -7,7 +7,7 @@ import com.genersoft.iot.vmp.gb28181.bean.Device;
 import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
 import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
-import com.genersoft.iot.vmp.service.bean.InviteErrorCallback;
+import com.genersoft.iot.vmp.service.bean.ErrorCallback;
 import com.genersoft.iot.vmp.service.bean.SSRCInfo;
 import com.genersoft.iot.vmp.vmanager.bean.AudioBroadcastResult;
 import com.genersoft.iot.vmp.vmanager.gb28181.play.bean.AudioBroadcastEvent;
@@ -25,8 +25,8 @@ import java.util.Map;
 public interface IPlayService {
 
     void play(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId,
-              InviteErrorCallback<Object> callback);
-    SSRCInfo play(MediaServerItem mediaServerItem, String deviceId, String channelId, InviteErrorCallback<Object> callback);
+              ErrorCallback<Object> callback);
+    SSRCInfo play(MediaServerItem mediaServerItem, String deviceId, String channelId, ErrorCallback<Object> callback);
 
     StreamInfo onPublishHandlerForPlay(MediaServerItem mediaServerItem, JSONObject response, String deviceId, String channelId);
 
@@ -37,13 +37,13 @@ public interface IPlayService {
      */
     MediaServerItem getNewMediaServerItemHasAssist(Device device);
 
-    void playBack(String deviceId, String channelId, String startTime, String endTime, InviteErrorCallback<Object> callback);
-    void playBack(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, String deviceId, String channelId, String startTime, String endTime, InviteErrorCallback<Object> callback);
+    void playBack(String deviceId, String channelId, String startTime, String endTime, ErrorCallback<Object> callback);
+    void playBack(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, String deviceId, String channelId, String startTime, String endTime, ErrorCallback<Object> callback);
 
     void zlmServerOffline(String mediaServerId);
 
-    void download(String deviceId, String channelId, String startTime, String endTime, int downloadSpeed, InviteErrorCallback<Object> callback);
-    void download(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo,String deviceId,  String channelId, String startTime, String endTime, int downloadSpeed, InviteErrorCallback<Object> callback);
+    void download(String deviceId, String channelId, String startTime, String endTime, int downloadSpeed, ErrorCallback<Object> callback);
+    void download(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo,String deviceId,  String channelId, String startTime, String endTime, int downloadSpeed, ErrorCallback<Object> callback);
 
     StreamInfo getDownLoadInfo(String deviceId, String channelId, String stream);
 
@@ -69,4 +69,6 @@ public interface IPlayService {
     void talkCmd(Device device, String channelId, MediaServerItem mediaServerItem, String stream, AudioBroadcastEvent event);
 
     void stopTalk(Device device, String channelId, Boolean streamIsReady);
+
+    void getSnap(String deviceId, String channelId, String fileName, ErrorCallback errorCallback);
 }

+ 0 - 8
src/main/java/com/genersoft/iot/vmp/service/IRecordInfoServer.java

@@ -1,8 +0,0 @@
-package com.genersoft.iot.vmp.service;
-
-import com.genersoft.iot.vmp.storager.dao.dto.RecordInfo;
-import com.github.pagehelper.PageInfo;
-
-public interface IRecordInfoServer {
-    PageInfo<RecordInfo> getRecordList(int page, int count);
-}

+ 4 - 3
src/main/java/com/genersoft/iot/vmp/service/IStreamProxyService.java

@@ -1,10 +1,11 @@
 package com.genersoft.iot.vmp.service;
 
 import com.alibaba.fastjson2.JSONObject;
+import com.genersoft.iot.vmp.common.GeneralCallback;
 import com.genersoft.iot.vmp.common.StreamInfo;
 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
 import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem;
-import com.genersoft.iot.vmp.vmanager.bean.ResourceBaceInfo;
+import com.genersoft.iot.vmp.vmanager.bean.ResourceBaseInfo;
 import com.github.pagehelper.PageInfo;
 
 public interface IStreamProxyService {
@@ -13,7 +14,7 @@ public interface IStreamProxyService {
      * 保存视频代理
      * @param param
      */
-    StreamInfo save(StreamProxyItem param);
+    void save(StreamProxyItem param, GeneralCallback<StreamInfo> callback);
 
     /**
      * 添加视频代理到zlm
@@ -108,6 +109,6 @@ public interface IStreamProxyService {
      * 获取统计信息
      * @return
      */
-    ResourceBaceInfo getOverview();
+    ResourceBaseInfo getOverview();
 
 }

+ 2 - 2
src/main/java/com/genersoft/iot/vmp/service/IStreamPushService.java

@@ -5,7 +5,7 @@ import com.genersoft.iot.vmp.media.zlm.dto.hook.OnStreamChangedHookParam;
 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
 import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem;
 import com.genersoft.iot.vmp.service.bean.StreamPushItemFromRedis;
-import com.genersoft.iot.vmp.vmanager.bean.ResourceBaceInfo;
+import com.genersoft.iot.vmp.vmanager.bean.ResourceBaseInfo;
 import com.github.pagehelper.PageInfo;
 
 import java.util.List;
@@ -113,5 +113,5 @@ public interface IStreamPushService {
      * 获取统计信息
      * @return
      */
-    ResourceBaceInfo getOverview();
+    ResourceBaseInfo getOverview();
 }

+ 1 - 1
src/main/java/com/genersoft/iot/vmp/service/bean/InviteErrorCallback.java

@@ -1,6 +1,6 @@
 package com.genersoft.iot.vmp.service.bean;
 
-public interface InviteErrorCallback<T> {
+public interface ErrorCallback<T> {
 
     void run(int code, String msg, T data);
 }

+ 1 - 0
src/main/java/com/genersoft/iot/vmp/service/bean/InviteErrorCode.java

@@ -5,6 +5,7 @@ package com.genersoft.iot.vmp.service.bean;
  */
 public enum InviteErrorCode {
     SUCCESS(0, "成功"),
+    FAIL(-100, "失败"),
     ERROR_FOR_SIGNALLING_TIMEOUT(-1, "信令超时"),
     ERROR_FOR_STREAM_TIMEOUT(-2, "收流超时"),
     ERROR_FOR_RESOURCE_EXHAUSTION(-3, "资源耗尽"),

+ 9 - 5
src/main/java/com/genersoft/iot/vmp/service/impl/DeviceChannelServiceImpl.java

@@ -11,7 +11,7 @@ import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
 import com.genersoft.iot.vmp.storager.dao.DeviceChannelMapper;
 import com.genersoft.iot.vmp.storager.dao.DeviceMapper;
 import com.genersoft.iot.vmp.utils.DateUtil;
-import com.genersoft.iot.vmp.vmanager.bean.ResourceBaceInfo;
+import com.genersoft.iot.vmp.vmanager.bean.ResourceBaseInfo;
 import com.genersoft.iot.vmp.vmanager.gb28181.platform.bean.ChannelReduce;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -50,8 +50,6 @@ public class DeviceChannelServiceImpl implements IDeviceChannelService {
                 device = deviceMapper.getDeviceByDeviceId(deviceChannel.getDeviceId());
             }
 
-
-
             if ("WGS84".equals(device.getGeoCoordSys())) {
                 deviceChannel.setLongitudeWgs84(deviceChannel.getLongitude());
                 deviceChannel.setLatitudeWgs84(deviceChannel.getLatitude());
@@ -175,8 +173,12 @@ public class DeviceChannelServiceImpl implements IDeviceChannelService {
     }
 
     @Override
-    public ResourceBaceInfo getOverview() {
-        return channelMapper.getOverview();
+    public ResourceBaseInfo getOverview() {
+
+        int online = channelMapper.getOnlineCount();
+        int total = channelMapper.getAllChannelCount();
+
+        return new ResourceBaseInfo(total, online);
     }
 
 
@@ -258,4 +260,6 @@ public class DeviceChannelServiceImpl implements IDeviceChannelService {
             }
         }
     }
+
+
 }

+ 66 - 158
src/main/java/com/genersoft/iot/vmp/service/impl/DeviceServiceImpl.java

@@ -1,8 +1,10 @@
 package com.genersoft.iot.vmp.service.impl;
 
+import com.genersoft.iot.vmp.common.InviteSessionType;
 import com.genersoft.iot.vmp.common.VideoManagerConstants;
 import com.genersoft.iot.vmp.conf.DynamicTask;
 import com.genersoft.iot.vmp.conf.UserSetting;
+import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException;
 import com.genersoft.iot.vmp.gb28181.bean.*;
 import com.genersoft.iot.vmp.gb28181.session.AudioBroadcastManager;
 import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
@@ -10,6 +12,7 @@ import com.genersoft.iot.vmp.gb28181.task.ISubscribeTask;
 import com.genersoft.iot.vmp.gb28181.task.impl.CatalogSubscribeTask;
 import com.genersoft.iot.vmp.gb28181.task.impl.MobilePositionSubscribeTask;
 import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander;
+import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
 import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.cmd.CatalogResponseMessageHandler;
 import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
@@ -23,7 +26,7 @@ import com.genersoft.iot.vmp.storager.dao.DeviceMapper;
 import com.genersoft.iot.vmp.storager.dao.PlatformChannelMapper;
 import com.genersoft.iot.vmp.utils.DateUtil;
 import com.genersoft.iot.vmp.vmanager.bean.BaseTree;
-import com.genersoft.iot.vmp.vmanager.bean.ResourceBaceInfo;
+import com.genersoft.iot.vmp.vmanager.bean.ResourceBaseInfo;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -48,6 +51,8 @@ public class DeviceServiceImpl implements IDeviceService {
 
     private final static Logger logger = LoggerFactory.getLogger(DeviceServiceImpl.class);
 
+    @Autowired
+    private SIPCommander cmder;
     @Autowired
     private DynamicTask dynamicTask;
 
@@ -124,9 +129,10 @@ public class DeviceServiceImpl implements IDeviceService {
         }
 
         // 第一次上线 或则设备之前是离线状态--进行通道同步和设备信息查询
-        if (device.getCreateTime() == null) {
-            device.setOnline(1);
+        if (deviceInDb == null) {
+            device.setOnLine(true);
             device.setCreateTime(now);
+            device.setUpdateTime(now);
             logger.info("[设备上线,首次注册]: {},查询设备信息以及通道信息", device.getDeviceId());
             deviceMapper.add(device);
             redisCatchStorage.updateDevice(device);
@@ -137,8 +143,12 @@ public class DeviceServiceImpl implements IDeviceService {
             }
             sync(device);
         }else {
-            if(device.getOnline() == 0){
-                device.setOnline(1);
+
+            if (deviceInDb != null) {
+                device.setSwitchPrimarySubStream(deviceInDb.isSwitchPrimarySubStream());
+            }
+            if(!device.isOnLine()){
+                device.setOnLine(true);
                 device.setCreateTime(now);
                 deviceMapper.update(device);
                 redisCatchStorage.updateDevice(device);
@@ -185,14 +195,14 @@ public class DeviceServiceImpl implements IDeviceService {
 
     @Override
     public void offline(String deviceId, String reason) {
-        logger.error("[设备离线],{}, device:{}", reason, deviceId);
+        logger.warn("[设备离线],{}, device:{}", reason, deviceId);
         Device device = deviceMapper.getDeviceByDeviceId(deviceId);
         if (device == null) {
             return;
         }
         String registerExpireTaskKey = VideoManagerConstants.REGISTER_EXPIRE_TASK_KEY_PREFIX + deviceId;
         dynamicTask.stop(registerExpireTaskKey);
-        device.setOnline(0);
+        device.setOnLine(false);
         redisCatchStorage.updateDevice(device);
         deviceMapper.update(device);
         //进行通道离线
@@ -256,7 +266,7 @@ public class DeviceServiceImpl implements IDeviceService {
         }
         logger.info("[移除目录订阅]: {}", device.getDeviceId());
         String taskKey = device.getDeviceId() + "catalog";
-        if (device.getOnline() == 1) {
+        if (device.isOnLine()) {
             Runnable runnable = dynamicTask.get(taskKey);
             if (runnable instanceof ISubscribeTask) {
                 ISubscribeTask subscribeTask = (ISubscribeTask) runnable;
@@ -289,7 +299,7 @@ public class DeviceServiceImpl implements IDeviceService {
         }
         logger.info("[移除移动位置订阅]: {}", device.getDeviceId());
         String taskKey = device.getDeviceId() + "mobile_position";
-        if (device.getOnline() == 1) {
+        if (device.isOnLine()) {
             Runnable runnable = dynamicTask.get(taskKey);
             if (runnable instanceof ISubscribeTask) {
                 ISubscribeTask subscribeTask = (ISubscribeTask) runnable;
@@ -356,7 +366,7 @@ public class DeviceServiceImpl implements IDeviceService {
 
     @Override
     public void checkDeviceStatus(Device device) {
-        if (device == null || device.getOnline() == 0) {
+        if (device == null || !device.isOnLine()) {
             return;
         }
         try {
@@ -405,63 +415,11 @@ public class DeviceServiceImpl implements IDeviceService {
         if (device == null) {
             return null;
         }
-        if (parentId == null || parentId.equals(deviceId)) {
-            // 字根节点开始查询
-            List<DeviceChannel> rootNodes = getRootNodes(deviceId, TreeType.CIVIL_CODE.equals(device.getTreeType()), true, !onlyCatalog);
-            return transportChannelsToTree(rootNodes, "");
-        }
-
-        if (TreeType.CIVIL_CODE.equals(device.getTreeType())) {
-            if (parentId.length()%2 != 0) {
-                return null;
-            }
-            // 使用行政区划展示树
-//            if (parentId.length() > 10) {
-//                // TODO 可能是行政区划与业务分组混杂的情形
-//                return null;
-//            }
-
-            if (parentId.length() == 10 ) {
-                if (onlyCatalog) {
-                    return null;
-                }
-                // parentId为行业编码, 其下不会再有行政区划
-                List<DeviceChannel> channels = deviceChannelMapper.getChannelsByCivilCode(deviceId, parentId);
-                List<BaseTree<DeviceChannel>> trees = transportChannelsToTree(channels, parentId);
-                return trees;
-            }
-            // 查询其下的行政区划和摄像机
-            List<DeviceChannel> channelsForCivilCode = deviceChannelMapper.getChannelsWithCivilCodeAndLength(deviceId, parentId, parentId.length() + 2);
-            if (!onlyCatalog) {
-                List<DeviceChannel> channels = deviceChannelMapper.getChannelsByCivilCode(deviceId, parentId);
-
-                for(DeviceChannel channel : channels) {
-                    boolean flag = false;
-                    for(DeviceChannel deviceChannel : channelsForCivilCode) {
-                        if(channel.getChannelId().equals(deviceChannel.getChannelId())) {
-                            flag = true;
-                        }
-                    }
-                    if(!flag) {
-                        channelsForCivilCode.add(channel);
-                    }
-                }
-            }
-            List<BaseTree<DeviceChannel>> trees = transportChannelsToTree(channelsForCivilCode, parentId);
-            return trees;
-
-        }
-        // 使用业务分组展示树
-        if (TreeType.BUSINESS_GROUP.equals(device.getTreeType())) {
-            if (parentId.length() < 14 ) {
-                return null;
-            }
-            List<DeviceChannel> deviceChannels = deviceChannelMapper.queryChannels(deviceId, parentId, null, null, null,null);
-            List<BaseTree<DeviceChannel>> trees = transportChannelsToTree(deviceChannels, parentId);
-            return trees;
+        if (ObjectUtils.isEmpty(parentId) || parentId.equals(deviceId)) {
+            parentId = null;
         }
-
-        return null;
+        List<DeviceChannel> rootNodes = deviceChannelMapper.getSubChannelsByDeviceId(deviceId, parentId, onlyCatalog);
+        return transportChannelsToTree(rootNodes, "");
     }
 
     @Override
@@ -470,42 +428,11 @@ public class DeviceServiceImpl implements IDeviceService {
         if (device == null) {
             return null;
         }
-        if (parentId == null || parentId.equals(deviceId)) {
-            // 字根节点开始查询
-            List<DeviceChannel> rootNodes = getRootNodes(deviceId, TreeType.CIVIL_CODE.equals(device.getTreeType()), false, true);
-            return rootNodes;
-        }
-
-        if (TreeType.CIVIL_CODE.equals(device.getTreeType())) {
-            if (parentId.length()%2 != 0) {
-                return null;
-            }
-            // 使用行政区划展示树
-            if (parentId.length() > 10) {
-                // TODO 可能是行政区划与业务分组混杂的情形
-                return null;
-            }
-
-            if (parentId.length() == 10 ) {
-                // parentId为行业编码, 其下不会再有行政区划
-                List<DeviceChannel> channels = deviceChannelMapper.getChannelsByCivilCode(deviceId, parentId);
-                return channels;
-            }
-            // 查询其下的行政区划和摄像机
-            List<DeviceChannel> channels = deviceChannelMapper.getChannelsByCivilCode(deviceId, parentId);
-            return channels;
-
-        }
-        // 使用业务分组展示树
-        if (TreeType.BUSINESS_GROUP.equals(device.getTreeType())) {
-            if (parentId.length() < 14 ) {
-                return null;
-            }
-            List<DeviceChannel> deviceChannels = deviceChannelMapper.queryChannels(deviceId, parentId, null, null, null,null);
-            return deviceChannels;
+        if (ObjectUtils.isEmpty(parentId) || parentId.equals(deviceId)) {
+            return deviceChannelMapper.getSubChannelsByDeviceId(deviceId, null, false);
+        }else {
+            return deviceChannelMapper.getSubChannelsByDeviceId(deviceId, parentId, false);
         }
-
-        return null;
     }
 
     private List<BaseTree<DeviceChannel>> transportChannelsToTree(List<DeviceChannel> channels, String parentId) {
@@ -525,65 +452,26 @@ public class DeviceServiceImpl implements IDeviceService {
             node.setPid(parentId);
             node.setBasicData(channel);
             node.setParent(false);
-            if (channel.getChannelId().length() > 8) {
-                if (channel.getChannelId().length() > 13) {
-                    String gbCodeType = channel.getChannelId().substring(10, 13);
-                    node.setParent(gbCodeType.equals(ChannelIdType.BUSINESS_GROUP) || gbCodeType.equals(ChannelIdType.VIRTUAL_ORGANIZATION) );
-                }
-            }else {
+            if (channel.getChannelId().length() <= 8) {
                 node.setParent(true);
-            }
-            treeNotes.add(node);
-        }
-        Collections.sort(treeNotes);
-        return treeNotes;
-    }
-
-    private List<DeviceChannel> getRootNodes(String deviceId, boolean isCivilCode, boolean haveCatalog, boolean haveChannel) {
-        if (!haveCatalog && !haveChannel) {
-            return null;
-        }
-        List<DeviceChannel> result = new ArrayList<>();
-        if (isCivilCode) {
-            // 使用行政区划
-            Integer length= deviceChannelMapper.getChannelMinLength(deviceId);
-            if (length == null) {
-                return null;
-            }
-            if (length <= 10) {
-                if (haveCatalog) {
-                    List<DeviceChannel> provinceNode = deviceChannelMapper.getChannelsWithCivilCodeAndLength(deviceId, null, length);
-                    if (provinceNode != null && provinceNode.size() > 0) {
-                        result.addAll(provinceNode);
-                    }
-                }
-
-                if (haveChannel) {
-                    // 查询那些civilCode不在通道中的不规范通道,放置在根目录
-                    List<DeviceChannel> nonstandardNode = deviceChannelMapper.getChannelWithoutCiviCode(deviceId);
-                    if (nonstandardNode != null && nonstandardNode.size() > 0) {
-                        result.addAll(nonstandardNode);
-                    }
-                }
             }else {
-                if (haveChannel) {
-                    List<DeviceChannel> deviceChannels = deviceChannelMapper.queryChannels(deviceId, null, null, null, null,null);
-                    if (deviceChannels != null && deviceChannels.size() > 0) {
-                        result.addAll(deviceChannels);
+                if (channel.getChannelId().length() != 20) {
+                    node.setParent(channel.getParental() == 1);
+                }else {
+                    try {
+                        int type = Integer.parseInt(channel.getChannelId().substring(10, 13));
+                        if (type == 215 || type == 216 || type == 200) {
+                            node.setParent(true);
+                        }
+                    }catch (NumberFormatException e) {
+                        node.setParent(false);
                     }
                 }
             }
-
-        }else {
-            // 使用业务分组+虚拟组织
-
-            // 只获取业务分组
-            List<DeviceChannel> deviceChannels = deviceChannelMapper.getBusinessGroups(deviceId, ChannelIdType.BUSINESS_GROUP);
-            if (deviceChannels != null && deviceChannels.size() > 0) {
-                result.addAll(deviceChannels);
-            }
+            treeNotes.add(node);
         }
-        return result;
+        Collections.sort(treeNotes);
+        return treeNotes;
     }
 
     @Override
@@ -593,7 +481,7 @@ public class DeviceServiceImpl implements IDeviceService {
 
     @Override
     public void addDevice(Device device) {
-        device.setOnline(0);
+        device.setOnLine(false);
         device.setCreateTime(DateUtil.getNow());
         device.setUpdateTime(DateUtil.getNow());
         deviceMapper.addCustomDevice(device);
@@ -606,6 +494,22 @@ public class DeviceServiceImpl implements IDeviceService {
             logger.warn("更新设备时未找到设备信息");
             return;
         }
+        if(deviceInStore.isSwitchPrimarySubStream() != device.isSwitchPrimarySubStream()){
+            //当修改设备的主子码流开关时,需要校验是否存在流,如果存在流则直接关闭
+            List<SsrcTransaction> ssrcTransactionForAll = streamSession.getSsrcTransactionForAll(device.getDeviceId(), null, null, null);
+            if(ssrcTransactionForAll != null){
+                for (SsrcTransaction ssrcTransaction: ssrcTransactionForAll) {
+                    try {
+                        cmder.streamByeCmd(device, ssrcTransaction.getChannelId(), ssrcTransaction.getStream(), null, null);
+                    } catch (InvalidArgumentException | SsrcTransactionNotFoundException | ParseException | SipException e) {
+                        throw new RuntimeException(e);
+                    }
+                }
+            }
+            deviceChannelMapper.clearPlay(device.getDeviceId());
+            inviteStreamService.clearInviteInfo(device.getDeviceId());
+        }
+
         if (!ObjectUtils.isEmpty(device.getName())) {
             deviceInStore.setName(device.getName());
         }
@@ -617,7 +521,6 @@ public class DeviceServiceImpl implements IDeviceService {
         }
         deviceInStore.setSdpIp(device.getSdpIp());
         deviceInStore.setCharset(device.getCharset());
-        deviceInStore.setTreeType(device.getTreeType());
 
         //  目录订阅相关的信息
         if (device.getSubscribeCycleForCatalog() > 0) {
@@ -673,12 +576,17 @@ public class DeviceServiceImpl implements IDeviceService {
         }catch (Exception e) {
             dataSourceTransactionManager.rollback(transactionStatus);
         }
+        if (result) {
+            redisCatchStorage.removeDevice(deviceId);
+        }
         return result;
     }
 
     @Override
-    public ResourceBaceInfo getOverview() {
-        return deviceMapper.getOverview();
+    public ResourceBaseInfo getOverview() {
+        List<Device> onlineDevices = deviceMapper.getOnlineDevices();
+        List<Device> all = deviceMapper.getAll();
+        return new ResourceBaseInfo(all.size(), onlineDevices.size());
     }
 
     @Override

+ 18 - 29
src/main/java/com/genersoft/iot/vmp/service/impl/GbStreamServiceImpl.java

@@ -110,23 +110,18 @@ public class GbStreamServiceImpl implements IGbStreamService {
         deviceChannel.setLatitude(gbStream.getLatitude());
         deviceChannel.setDeviceId(platform.getDeviceGBId());
         deviceChannel.setManufacture("wvp-pro");
-        deviceChannel.setStatus(gbStream.isStatus()?1:0);
+        deviceChannel.setStatus(gbStream.isStatus());
 
         deviceChannel.setRegisterWay(1);
-        deviceChannel.setCivilCode(platform.getAdministrativeDivision());
-
-        if (platform.getTreeType().equals(TreeType.CIVIL_CODE)){
-            deviceChannel.setCivilCode(catalogId);
-        }else if (platform.getTreeType().equals(TreeType.BUSINESS_GROUP)){
-            PlatformCatalog catalog = catalogMapper.select(catalogId);
-            if (catalog == null) {
-                deviceChannel.setParentId(platform.getDeviceGBId());
-                deviceChannel.setBusinessGroupId(null);
-            }else {
-                deviceChannel.setParentId(catalog.getId());
-                deviceChannel.setBusinessGroupId(catalog.getBusinessGroupId());
-            }
 
+        PlatformCatalog catalog = catalogMapper.select(catalogId);
+        if (catalog != null) {
+            deviceChannel.setCivilCode(catalog.getCivilCode());
+            deviceChannel.setParentId(catalog.getParentId());
+            deviceChannel.setBusinessGroupId(catalog.getBusinessGroupId());
+        }else {
+            deviceChannel.setCivilCode(platform.getAdministrativeDivision());
+            deviceChannel.setParentId(platform.getDeviceGBId());
         }
 
         deviceChannel.setModel("live");
@@ -218,23 +213,17 @@ public class GbStreamServiceImpl implements IGbStreamService {
         }else {
             status = gbStreamMapper.selectStatusForPush(gbStream.getApp(), gbStream.getStream());
         }
-        deviceChannel.setStatus((status != null && status )?1:0);
+        deviceChannel.setStatus(status != null && status);
 
         deviceChannel.setRegisterWay(1);
-        deviceChannel.setCivilCode(platform.getAdministrativeDivision());
-
-        if (platform.getTreeType().equals(TreeType.CIVIL_CODE)){
-            deviceChannel.setCivilCode(catalogId);
-        }else if (platform.getTreeType().equals(TreeType.BUSINESS_GROUP)){
-            PlatformCatalog catalog = catalogMapper.select(catalogId);
-            if (catalog == null) {
-                deviceChannel.setParentId(platform.getDeviceGBId());
-                deviceChannel.setBusinessGroupId(null);
-            }else {
-                deviceChannel.setParentId(catalog.getId());
-                deviceChannel.setBusinessGroupId(catalog.getBusinessGroupId());
-            }
-
+        PlatformCatalog catalog = catalogMapper.select(catalogId);
+        if (catalog != null) {
+            deviceChannel.setCivilCode(catalog.getCivilCode());
+            deviceChannel.setParentId(catalog.getParentId());
+            deviceChannel.setBusinessGroupId(catalog.getBusinessGroupId());
+        }else {
+            deviceChannel.setCivilCode(platform.getAdministrativeDivision());
+            deviceChannel.setParentId(platform.getDeviceGBId());
         }
 
         deviceChannel.setModel("live");

+ 63 - 16
src/main/java/com/genersoft/iot/vmp/service/impl/InviteStreamServiceImpl.java

@@ -6,7 +6,7 @@ import com.genersoft.iot.vmp.common.InviteSessionStatus;
 import com.genersoft.iot.vmp.common.InviteSessionType;
 import com.genersoft.iot.vmp.common.VideoManagerConstants;
 import com.genersoft.iot.vmp.service.IInviteStreamService;
-import com.genersoft.iot.vmp.service.bean.InviteErrorCallback;
+import com.genersoft.iot.vmp.service.bean.ErrorCallback;
 import com.genersoft.iot.vmp.utils.redis.RedisUtil;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -24,7 +24,7 @@ public class InviteStreamServiceImpl implements IInviteStreamService {
 
     private final Logger logger = LoggerFactory.getLogger(InviteStreamServiceImpl.class);
 
-    private final Map<String, List<InviteErrorCallback<Object>>> inviteErrorCallbackMap = new ConcurrentHashMap<>();
+    private final Map<String, List<ErrorCallback<Object>>> inviteErrorCallbackMap = new ConcurrentHashMap<>();
 
     @Autowired
     private RedisTemplate<Object, Object> redisTemplate;
@@ -84,6 +84,24 @@ public class InviteStreamServiceImpl implements IInviteStreamService {
         redisTemplate.opsForValue().set(key, inviteInfoForUpdate);
     }
 
+    @Override
+    public InviteInfo updateInviteInfoForStream(InviteInfo inviteInfo, String stream) {
+
+        InviteInfo inviteInfoInDb = getInviteInfo(inviteInfo.getType(), inviteInfo.getDeviceId(), inviteInfo.getChannelId(), inviteInfo.getStream());
+        if (inviteInfoInDb == null) {
+            return null;
+        }
+        removeInviteInfo(inviteInfoInDb);
+        String key = VideoManagerConstants.INVITE_PREFIX +
+                "_" + inviteInfo.getType() +
+                "_" + inviteInfo.getDeviceId() +
+                "_" + inviteInfo.getChannelId() +
+                "_" + stream;
+        inviteInfoInDb.setStream(stream);
+        redisTemplate.opsForValue().set(key, inviteInfoInDb);
+        return inviteInfoInDb;
+    }
+
     @Override
     public InviteInfo getInviteInfo(InviteSessionType type, String deviceId, String channelId, String stream) {
         String key = VideoManagerConstants.INVITE_PREFIX +
@@ -141,9 +159,9 @@ public class InviteStreamServiceImpl implements IInviteStreamService {
     }
 
     @Override
-    public void once(InviteSessionType type, String deviceId, String channelId, String stream, InviteErrorCallback<Object> callback) {
+    public void once(InviteSessionType type, String deviceId, String channelId, String stream, ErrorCallback<Object> callback) {
         String key = buildKey(type, deviceId, channelId, stream);
-        List<InviteErrorCallback<Object>> callbacks = inviteErrorCallbackMap.get(key);
+        List<ErrorCallback<Object>> callbacks = inviteErrorCallbackMap.get(key);
         if (callbacks == null) {
             callbacks = new CopyOnWriteArrayList<>();
             inviteErrorCallbackMap.put(key, callbacks);
@@ -152,31 +170,60 @@ public class InviteStreamServiceImpl implements IInviteStreamService {
 
     }
 
+    private String buildKey(InviteSessionType type, String deviceId, String channelId, String stream) {
+        String key = type + "_" +  deviceId + "_" + channelId;
+        // 如果ssrc未null那么可以实现一个通道只能一次操作,ssrc不为null则可以支持一个通道多次invite
+        if (stream != null) {
+            key += ("_" + stream);
+        }
+        return key;
+    }
+
+
+    @Override
+    public void clearInviteInfo(String deviceId) {
+        removeInviteInfo(null, deviceId, null, null);
+    }
+
+    @Override
+    public int getStreamInfoCount(String mediaServerId) {
+        int count = 0;
+        String key = VideoManagerConstants.INVITE_PREFIX + "_*_*_*_*";
+        List<Object> scanResult = RedisUtil.scan(redisTemplate, key);
+        if (scanResult.size() == 0) {
+            return 0;
+        }else {
+            for (Object keyObj : scanResult) {
+                String keyStr = (String) keyObj;
+                InviteInfo inviteInfo = (InviteInfo) redisTemplate.opsForValue().get(keyStr);
+                if (inviteInfo != null && inviteInfo.getStreamInfo() != null && inviteInfo.getStreamInfo().getMediaServerId().equals(mediaServerId)) {
+                    count++;
+                }
+            }
+        }
+        return count;
+    }
+
     @Override
     public void call(InviteSessionType type, String deviceId, String channelId, String stream, int code, String msg, Object data) {
-        String key = buildKey(type, deviceId, channelId, stream);
-        List<InviteErrorCallback<Object>> callbacks = inviteErrorCallbackMap.get(key);
+        String key = buildSubStreamKey(type, deviceId, channelId, stream);
+        List<ErrorCallback<Object>> callbacks = inviteErrorCallbackMap.get(key);
         if (callbacks == null) {
             return;
         }
-        for (InviteErrorCallback<Object> callback : callbacks) {
+        for (ErrorCallback<Object> callback : callbacks) {
             callback.run(code, msg, data);
         }
         inviteErrorCallbackMap.remove(key);
     }
 
-    private String buildKey(InviteSessionType type, String deviceId, String channelId, String stream) {
-        String key = type + "_" +  deviceId + "_" + channelId;
-        // 如果ssrc未null那么可以实现一个通道只能一次操作,ssrc不为null则可以支持一个通道多次invite
+
+    private String buildSubStreamKey(InviteSessionType type, String deviceId, String channelId, String stream) {
+        String key = type + "_" + "_" +  deviceId + "_" + channelId;
+        // 如果ssrc为null那么可以实现一个通道只能一次操作,ssrc不为null则可以支持一个通道多次invite
         if (stream != null) {
             key += ("_" + stream);
         }
         return key;
     }
-
-
-    @Override
-    public void clearInviteInfo(String deviceId) {
-        removeInviteInfo(null, deviceId, null, null);
-    }
 }

+ 0 - 0
src/main/java/com/genersoft/iot/vmp/service/impl/MediaServerServiceImpl.java


Vissa filer visades inte eftersom för många filer har ändrats