Browse Source

Merge branch 'wvp-28181-2.0' of https://github.com/648540858/wvp-GB28181-pro into wvp-28181-2.0

pull/359/head
chenjialing 4 years ago
parent
commit
d8fa9d6801
  1. 6
      README.md
  2. 9
      pom.xml
  3. 540
      sql/dump-wvp-202201051515.sql
  4. 12
      sql/mysql.sql
  5. 6
      src/main/java/com/genersoft/iot/vmp/common/VideoManagerConstants.java
  6. 5
      src/main/java/com/genersoft/iot/vmp/conf/DynamicTask.java
  7. 8
      src/main/java/com/genersoft/iot/vmp/conf/RedisConfig.java
  8. 41
      src/main/java/com/genersoft/iot/vmp/conf/RedisKeyExpirationEventMessageListener.java
  9. 14
      src/main/java/com/genersoft/iot/vmp/conf/runner/SipDeviceRunner.java
  10. 2
      src/main/java/com/genersoft/iot/vmp/conf/security/AnonymousAuthenticationEntryPoint.java
  11. 8
      src/main/java/com/genersoft/iot/vmp/gb28181/bean/CmdType.java
  12. 21
      src/main/java/com/genersoft/iot/vmp/gb28181/bean/DeviceNotFoundEvent.java
  13. 13
      src/main/java/com/genersoft/iot/vmp/gb28181/bean/ParentPlatform.java
  14. 71
      src/main/java/com/genersoft/iot/vmp/gb28181/bean/PlatformCatalog.java
  15. 8
      src/main/java/com/genersoft/iot/vmp/gb28181/bean/PlatformGbStream.java
  16. 78
      src/main/java/com/genersoft/iot/vmp/gb28181/bean/SubscribeInfo.java
  17. 54
      src/main/java/com/genersoft/iot/vmp/gb28181/event/EventPublisher.java
  18. 8
      src/main/java/com/genersoft/iot/vmp/gb28181/event/SipSubscribe.java
  19. 30
      src/main/java/com/genersoft/iot/vmp/gb28181/event/offline/KeepaliveTimeoutListenerForPlatform.java
  20. 10
      src/main/java/com/genersoft/iot/vmp/gb28181/event/offline/KeepliveTimeoutListener.java
  21. 10
      src/main/java/com/genersoft/iot/vmp/gb28181/event/offline/OfflineEventListener.java
  22. 22
      src/main/java/com/genersoft/iot/vmp/gb28181/event/online/OnlineEventListener.java
  23. 52
      src/main/java/com/genersoft/iot/vmp/gb28181/event/subscribe/SubscribeListenerForPlatform.java
  24. 58
      src/main/java/com/genersoft/iot/vmp/gb28181/event/subscribe/catalog/CatalogEvent.java
  25. 172
      src/main/java/com/genersoft/iot/vmp/gb28181/event/subscribe/catalog/CatalogEventLister.java
  26. 70
      src/main/java/com/genersoft/iot/vmp/gb28181/task/GPSSubscribeTask.java
  27. 22
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPProcessorObserver.java
  28. 2
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/callback/DeferredResultHolder.java
  29. 9
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java
  30. 26
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommanderForPlatform.java
  31. 49
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderPlarformProvider.java
  32. 33
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java
  33. 153
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java
  34. 28
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/SIPRequestProcessorParent.java
  35. 13
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java
  36. 121
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/NotifyRequestProcessor.java
  37. 9
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/RegisterRequestProcessor.java
  38. 166
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/SubscribeRequestProcessor.java
  39. 14
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/MessageRequestProcessor.java
  40. 43
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/CatalogNotifyMessageHandler.java
  41. 41
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/CatalogQueryMessageHandler.java
  42. 81
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/CatalogResponseMessageHandler.java
  43. 34
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/DeviceControlResponseMessageHandler.java
  44. 86
      src/main/java/com/genersoft/iot/vmp/gb28181/utils/XmlUtil.java
  45. 68
      src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java
  46. 4
      src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMMediaListManager.java
  47. 17
      src/main/java/com/genersoft/iot/vmp/media/zlm/event/ZLMKeepliveTimeoutListener.java
  48. 12
      src/main/java/com/genersoft/iot/vmp/service/IGbStreamService.java
  49. 3
      src/main/java/com/genersoft/iot/vmp/service/IStreamPushService.java
  50. 39
      src/main/java/com/genersoft/iot/vmp/service/StreamGPSSubscribeTask.java
  51. 16
      src/main/java/com/genersoft/iot/vmp/service/bean/CatalogSubscribeTask.java
  52. 106
      src/main/java/com/genersoft/iot/vmp/service/bean/GPSMsgInfo.java
  53. 6
      src/main/java/com/genersoft/iot/vmp/service/impl/DeviceServiceImpl.java
  54. 80
      src/main/java/com/genersoft/iot/vmp/service/impl/GbStreamServiceImpl.java
  55. 22
      src/main/java/com/genersoft/iot/vmp/service/impl/RedisGPSMsgListener.java
  56. 27
      src/main/java/com/genersoft/iot/vmp/service/impl/StreamProxyServiceImpl.java
  57. 96
      src/main/java/com/genersoft/iot/vmp/service/impl/StreamPushServiceImpl.java
  58. 85
      src/main/java/com/genersoft/iot/vmp/service/impl/StreamPushUploadFileHandler.java
  59. 35
      src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java
  60. 43
      src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorager.java
  61. 59
      src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceChannelMapper.java
  62. 39
      src/main/java/com/genersoft/iot/vmp/storager/dao/GbStreamMapper.java
  63. 14
      src/main/java/com/genersoft/iot/vmp/storager/dao/ParentPlatformMapper.java
  64. 44
      src/main/java/com/genersoft/iot/vmp/storager/dao/PlatformCatalogMapper.java
  65. 41
      src/main/java/com/genersoft/iot/vmp/storager/dao/PlatformChannelMapper.java
  66. 58
      src/main/java/com/genersoft/iot/vmp/storager/dao/PlatformGbStreamMapper.java
  67. 6
      src/main/java/com/genersoft/iot/vmp/storager/dao/StreamPushMapper.java
  68. 128
      src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java
  69. 307
      src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStoragerImpl.java
  70. 50
      src/main/java/com/genersoft/iot/vmp/vmanager/bean/StreamPushExcelDto.java
  71. 99
      src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceControl.java
  72. 21
      src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceQuery.java
  73. 13
      src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/gbStream/GbStreamController.java
  74. 10
      src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/gbStream/bean/GbStreamParam.java
  75. 204
      src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/platform/PlatformController.java
  76. 13
      src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/platform/bean/ChannelReduce.java
  77. 9
      src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/platform/bean/UpdateChannelParam.java
  78. 44
      src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/platformGbStream/PlatformGbStreamController.java
  79. 101
      src/main/java/com/genersoft/iot/vmp/vmanager/streamPush/StreamPushController.java
  80. 2
      src/main/resources/all-application.yml
  81. 2
      src/main/resources/application-dev.yml
  82. 2
      src/main/resources/application-docker.yml
  83. BIN
      src/main/resources/wvp.sqlite
  84. 14469
      web_src/package-lock.json
  85. 3
      web_src/package.json
  86. 7
      web_src/src/components/DeviceList.vue
  87. 2
      web_src/src/components/ParentPlatformList.vue
  88. 20
      web_src/src/components/PushVideoList.vue
  89. 101
      web_src/src/components/dialog/catalogEdit.vue
  90. 84
      web_src/src/components/dialog/chooseChannel.vue
  91. 309
      web_src/src/components/dialog/chooseChannelForCatalog.vue
  92. 108
      web_src/src/components/dialog/chooseChannelForGb.vue
  93. 74
      web_src/src/components/dialog/chooseChannelForStream.vue
  94. 6
      web_src/src/components/dialog/deviceEdit.vue
  95. 125
      web_src/src/components/dialog/importChannel.vue
  96. 64
      web_src/src/components/dialog/importChannelShowErrorData.vue
  97. 2
      web_src/src/components/dialog/jessibuca.vue
  98. 1
      web_src/src/components/dialog/platformEdit.vue
  99. 2
      web_src/src/main.js
  100. 26
      web_src/static/css/iconfont.css

6
README.md

@ -95,15 +95,13 @@ https://gitee.com/pan648540858/wvp-GB28181-pro.git
- [X] 平台状态查询 - [X] 平台状态查询
- [X] 平台信息查询 - [X] 平台信息查询
- [X] 平台远程启动 - [X] 平台远程启动
- [X] 每个级联平台可自定义的虚拟目录
- [X] 添加RTSP视频 - [X] 添加RTSP视频
- [X] 添加接口鉴权 - [X] 添加接口鉴权
- [ ] 添加ONVIF探测局域网内的设备
- [X] 添加RTMP视频 - [X] 添加RTMP视频
- [X] 云端录像(需要部署单独服务配合使用) - [X] 云端录像(需要部署单独服务配合使用)
- [X] 多流媒体节点,自动选择负载最低的节点使用。 - [X] 多流媒体节点,自动选择负载最低的节点使用。
- [X] 支持使用mysql作为数据库,默认sqlite3,开箱即用。 - [X] 支持使用mysql作为数据库,默认sqlite3,开箱即用。
- [ ] 添加系统配置
- [ ] 添加用户管理
- [X] WEB端支持播放H264与H265,音频支持G.711A/G.711U/AAC,覆盖国标常用编码格式。 - [X] WEB端支持播放H264与H265,音频支持G.711A/G.711U/AAC,覆盖国标常用编码格式。
# docker快速体验 # docker快速体验
@ -118,7 +116,7 @@ docker使用详情查看:[https://hub.docker.com/r/648540858/wvp_pro](https://
https://gitee.com/pan648540858/wvp-GB28181-pro.git https://gitee.com/pan648540858/wvp-GB28181-pro.git
# 使用帮助 # 使用帮助
QQ群: 901799015, 690854210(ZLM大群) QQ群: 901799015, ZLM使用文档[https://github.com/ZLMediaKit/ZLMediaKit](https://github.com/ZLMediaKit/ZLMediaKit)
QQ私信一般不回, 精力有限.欢迎大家在群里讨论.觉得项目对你有帮助,欢迎star和提交pr。 QQ私信一般不回, 精力有限.欢迎大家在群里讨论.觉得项目对你有帮助,欢迎star和提交pr。

9
pom.xml

@ -161,7 +161,7 @@
<version>2.1.3</version> <version>2.1.3</version>
</dependency> </dependency>
<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson --> <!-- json解析库fastjson -->
<dependency> <dependency>
<groupId>com.alibaba</groupId> <groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId> <artifactId>fastjson</artifactId>
@ -203,6 +203,13 @@
<version>1.12</version> <version>1.12</version>
</dependency> </dependency>
<!--excel解析库-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>3.0.4</version>
</dependency>
<dependency> <dependency>
<groupId>org.springframework.session</groupId> <groupId>org.springframework.session</groupId>
<artifactId>spring-session-core</artifactId> <artifactId>spring-session-core</artifactId>

540
sql/dump-wvp-202201051515.sql

@ -0,0 +1,540 @@
-- 此脚本采用dbeaver导出
-- MySQL dump 10.13 Distrib 8.0.27, for Linux (x86_64)
--
-- Host: localhost Database: wvp
-- ------------------------------------------------------
-- Server version 8.0.27-0ubuntu0.20.04.1
/*!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 */;
--
-- Table structure for table `device`
--
DROP TABLE IF EXISTS `device`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `device` (
`deviceId` varchar(50) NOT NULL,
`name` varchar(255) DEFAULT NULL,
`manufacturer` varchar(255) DEFAULT NULL,
`model` varchar(255) DEFAULT NULL,
`firmware` varchar(255) DEFAULT NULL,
`transport` varchar(50) DEFAULT NULL,
`streamMode` varchar(50) DEFAULT NULL,
`online` varchar(50) DEFAULT NULL,
`registerTime` varchar(50) DEFAULT NULL,
`keepaliveTime` varchar(50) DEFAULT NULL,
`ip` varchar(50) NOT NULL,
`createTime` varchar(50) NOT NULL,
`updateTime` varchar(50) NOT NULL,
`port` int NOT NULL,
`expires` int NOT NULL,
`subscribeCycleForCatalog` int NOT NULL,
`hostAddress` varchar(50) NOT NULL,
`charset` varchar(50) NOT NULL,
PRIMARY KEY (`deviceId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `device`
--
LOCK TABLES `device` WRITE;
/*!40000 ALTER TABLE `device` DISABLE KEYS */;
INSERT INTO `device` VALUES ('34020000001320000005','IPC-HFW4433M-I2','Dahua','IPC-HFW4433M-I2','2.622.0000000.31.R,2017-12-14','UDP','UDP','1','2022-01-05 15:08:26','2022-01-05 15:15:26','192.168.1.100','2022-01-05 15:08:26','2022-01-05 15:15:26',5060,3600,0,'192.168.1.100:5060','gb2312'),('34020000002000000005','DH-NVR5864-I','Dahua','DH-NVR5864-I','4.001.0000000.3,2020-10-22','UDP','UDP','1','2022-01-05 14:07:36','2022-01-05 15:15:25','192.168.1.19','2022-01-05 15:08:25','2022-01-05 15:15:25',5060,3600,0,'192.168.1.19:5060','gb2312'),('44010000001110008008',NULL,'Mercury','MIPC368(P)W-4','1.0.1 Build 210304 Rel.60784n','UDP','UDP','1','2022-01-05 15:08:35','2022-01-05 15:14:35','192.168.1.17','2022-01-05 15:08:35','2022-01-05 15:14:35',5060,36000,0,'192.168.1.17:5060','gb2312');
/*!40000 ALTER TABLE `device` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `device_alarm`
--
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) NOT NULL,
`channelId` varchar(50) NOT NULL,
`alarmPriority` varchar(50) NOT NULL,
`alarmMethod` varchar(50) DEFAULT NULL,
`alarmTime` varchar(50) NOT NULL,
`alarmDescription` varchar(255) DEFAULT NULL,
`longitude` double DEFAULT NULL,
`latitude` double DEFAULT NULL,
`alarmType` varchar(50) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `device_alarm`
--
LOCK TABLES `device_alarm` WRITE;
/*!40000 ALTER TABLE `device_alarm` DISABLE KEYS */;
/*!40000 ALTER TABLE `device_alarm` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `device_channel`
--
DROP TABLE IF EXISTS `device_channel`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `device_channel` (
`channelId` varchar(50) NOT NULL,
`name` varchar(255) DEFAULT NULL,
`manufacture` varchar(50) DEFAULT NULL,
`model` varchar(50) DEFAULT NULL,
`owner` varchar(50) DEFAULT NULL,
`civilCode` varchar(50) DEFAULT NULL,
`block` varchar(50) DEFAULT NULL,
`address` varchar(50) DEFAULT NULL,
`parentId` varchar(50) DEFAULT NULL,
`safetyWay` int DEFAULT NULL,
`registerWay` int DEFAULT NULL,
`certNum` varchar(50) DEFAULT NULL,
`certifiable` int DEFAULT NULL,
`errCode` int DEFAULT NULL,
`endTime` varchar(50) DEFAULT NULL,
`secrecy` varchar(50) DEFAULT NULL,
`ipAddress` varchar(50) DEFAULT NULL,
`port` int DEFAULT NULL,
`password` varchar(255) DEFAULT NULL,
`PTZType` int DEFAULT NULL,
`status` int DEFAULT NULL,
`longitude` double DEFAULT NULL,
`latitude` double DEFAULT NULL,
`streamId` varchar(50) DEFAULT NULL,
`deviceId` varchar(50) NOT NULL,
`parental` varchar(50) DEFAULT NULL,
`hasAudio` bit(1) DEFAULT NULL,
`createTime` varchar(50) NOT NULL,
`updateTime` varchar(50) NOT NULL,
PRIMARY KEY (`channelId`,`deviceId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `device_channel`
--
LOCK TABLES `device_channel` WRITE;
/*!40000 ALTER TABLE `device_channel` DISABLE KEYS */;
INSERT INTO `device_channel` VALUES ('34020000001310000001','IPC','Dahua','IPC-HFW4433M-I2','0','340200','','axy','34020000001320000005',0,1,'',0,0,NULL,'0','',0,'',0,1,0,0,'','34020000001320000005','0',NULL,'2022-01-05 15:11:21','2022-01-05 15:11:21'),('34020000001310000001','通道1','Dahua','DH-NVR5864-I','0','340200','','axy','34020000002000000005',0,1,'',0,0,NULL,'0','192.168.1.17',37777,'',0,1,0,0,'','34020000002000000005','0',NULL,'2022-01-05 15:11:25','2022-01-05 15:11:25'),('34020000001310000065','GB_Chn_065','Dahua','DH-NVR5864-I','0','340200','','axy','34020000002000000005',0,1,'',0,0,NULL,'0','',0,'',0,1,0,0,'','34020000002000000005','0',NULL,'2022-01-05 15:11:25','2022-01-05 15:11:25'),('34020000001320000001','IPCamera 01','Mercury','MIPC368(P)W-4','Owner','CivilCode','','Address','',0,1,'',0,0,NULL,'0','',0,'',0,1,0,0,'','44010000001110008008','0',NULL,'2022-01-05 15:11:26','2022-01-05 15:11:26');
/*!40000 ALTER TABLE `device_channel` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `device_mobile_position`
--
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` (
`deviceId` varchar(50) NOT NULL,
`channelId` varchar(50) NOT NULL,
`deviceName` varchar(255) DEFAULT NULL,
`time` varchar(50) 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) DEFAULT NULL,
`geodeticSystem` varchar(50) DEFAULT NULL,
`cnLng` varchar(50) DEFAULT NULL,
`cnLat` varchar(50) DEFAULT NULL,
PRIMARY KEY (`deviceId`,`time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `device_mobile_position`
--
LOCK TABLES `device_mobile_position` WRITE;
/*!40000 ALTER TABLE `device_mobile_position` DISABLE KEYS */;
/*!40000 ALTER TABLE `device_mobile_position` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `gb_stream`
--
DROP TABLE IF EXISTS `gb_stream`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `gb_stream` (
`app` varchar(255) NOT NULL,
`stream` varchar(255) NOT NULL,
`gbId` varchar(50) NOT NULL,
`name` varchar(255) DEFAULT NULL,
`longitude` double DEFAULT NULL,
`latitude` double DEFAULT NULL,
`streamType` varchar(50) DEFAULT NULL,
`mediaServerId` varchar(50) DEFAULT NULL,
`status` int DEFAULT NULL,
PRIMARY KEY (`app`,`stream`,`gbId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `gb_stream`
--
LOCK TABLES `gb_stream` WRITE;
/*!40000 ALTER TABLE `gb_stream` DISABLE KEYS */;
INSERT INTO `gb_stream` VALUES ('1000','10000001_52869999','77777777777777777777','shoulei1111',0,0,'push','XR1LEpKlfQtSg9Z1',1);
/*!40000 ALTER TABLE `gb_stream` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `log`
--
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) NOT NULL,
`type` varchar(50) NOT NULL,
`uri` varchar(200) NOT NULL,
`address` varchar(50) NOT NULL,
`result` varchar(50) NOT NULL,
`timing` bigint NOT NULL,
`username` varchar(50) NOT NULL,
`createTime` varchar(50) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=21 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `log`
--
LOCK TABLES `log` WRITE;
/*!40000 ALTER TABLE `log` DISABLE KEYS */;
INSERT INTO `log` VALUES (1,'登录','GET','/api/user/login','127.0.0.1','200 OK',245,'admin','2022-01-05 15:09:06'),(2,'添加上级平台','POST','/api/platform/save','127.0.0.1','200 OK',88,'admin','2022-01-05 15:09:24'),(3,'[设备查询] 同步设备通道','POST','/api/device/query/devices/34020000001320000005/sync','127.0.0.1','200 OK',17,'admin','2022-01-05 15:11:21'),(4,'[设备查询] 同步设备通道','POST','/api/device/query/devices/34020000002000000005/sync','127.0.0.1','200 OK',4,'admin','2022-01-05 15:11:25'),(5,'[设备查询] 同步设备通道','POST','/api/device/query/devices/44010000001110008008/sync','127.0.0.1','200 OK',4,'admin','2022-01-05 15:11:26'),(6,'向上级平台添加国标通道','POST','/api/platform/update_channel_for_gb','127.0.0.1','200 OK',52,'admin','2022-01-05 15:11:32'),(7,'从上级平台移除国标通道','DELETE','/api/platform/del_channel_for_gb','127.0.0.1','200 OK',35,'admin','2022-01-05 15:11:34'),(8,'向上级平台添加国标通道','POST','/api/platform/update_channel_for_gb','127.0.0.1','200 OK',39,'admin','2022-01-05 15:11:35'),(9,'从上级平台移除国标通道','DELETE','/api/platform/del_channel_for_gb','127.0.0.1','200 OK',46,'admin','2022-01-05 15:14:00'),(10,'向上级平台添加国标通道','POST','/api/platform/update_channel_for_gb','127.0.0.1','200 OK',59,'admin','2022-01-05 15:14:01'),(11,'添加通道与国标的关联','POST','/api/gbStream/add','127.0.0.1','200 OK',12,'admin','2022-01-05 15:14:16'),(12,'添加通道与国标的关联','POST','/api/gbStream/add','127.0.0.1','200 OK',8,'admin','2022-01-05 15:14:17'),(13,'添加通道与国标的关联','POST','/api/gbStream/add','127.0.0.1','200 OK',6,'admin','2022-01-05 15:14:19'),(14,'添加通道与国标的关联','POST','/api/gbStream/add','127.0.0.1','200 OK',8,'admin','2022-01-05 15:14:19'),(15,'移除通道与国标的关联','DELETE','/api/gbStream/del','127.0.0.1','200 OK',11,'admin','2022-01-05 15:14:21'),(16,'添加通道与国标的关联','POST','/api/gbStream/add','127.0.0.1','200 OK',42,'admin','2022-01-05 15:14:24'),(17,'移除通道与国标的关联','DELETE','/api/gbStream/del','127.0.0.1','200 OK',43,'admin','2022-01-05 15:14:25'),(18,'添加通道与国标的关联','POST','/api/gbStream/add','127.0.0.1','200 OK',9,'admin','2022-01-05 15:14:27'),(19,'添加通道与国标的关联','POST','/api/gbStream/add','127.0.0.1','200 OK',9,'admin','2022-01-05 15:14:37'),(20,'添加通道与国标的关联','POST','/api/gbStream/add','127.0.0.1','200 OK',10,'admin','2022-01-05 15:14:38');
/*!40000 ALTER TABLE `log` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `media_server`
--
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) NOT NULL,
`ip` varchar(50) NOT NULL,
`hookIp` varchar(50) NOT NULL,
`sdpIp` varchar(50) NOT NULL,
`streamIp` varchar(50) 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) NOT NULL,
`streamNoneReaderDelayMS` int NOT NULL,
`rtpEnable` int NOT NULL,
`rtpPortRange` varchar(50) NOT NULL,
`sendRtpPortRange` varchar(50) NOT NULL,
`recordAssistPort` int NOT NULL,
`defaultServer` int NOT NULL,
`createTime` varchar(50) NOT NULL,
`updateTime` varchar(50) NOT NULL,
`hookAliveInterval` int NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `media_server_i` (`ip`,`httpPort`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `media_server`
--
LOCK TABLES `media_server` WRITE;
/*!40000 ALTER TABLE `media_server` DISABLE KEYS */;
INSERT INTO `media_server` VALUES ('XR1LEpKlfQtSg9Z1','192.168.1.3','127.0.0.1','192.168.1.3','192.168.1.3',6080,0,10935,0,10000,10554,0,1,'035c73f7-bb6b-4889-a715-d9eb2d1925cc',100000,1,'30000,30500','30000,30500',18081,1,'2022-01-05 15:08:27','2022-01-05 15:08:27',10);
/*!40000 ALTER TABLE `media_server` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `parent_platform`
--
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) DEFAULT NULL,
`serverGBId` varchar(50) NOT NULL,
`serverGBDomain` varchar(50) DEFAULT NULL,
`serverIP` varchar(50) DEFAULT NULL,
`serverPort` int DEFAULT NULL,
`deviceGBId` varchar(50) NOT NULL,
`deviceIp` varchar(50) DEFAULT NULL,
`devicePort` varchar(50) DEFAULT NULL,
`username` varchar(255) DEFAULT NULL,
`password` varchar(50) DEFAULT NULL,
`expires` varchar(50) DEFAULT NULL,
`keepTimeout` varchar(50) DEFAULT NULL,
`transport` varchar(50) DEFAULT NULL,
`characterSet` varchar(50) DEFAULT NULL,
`catalogId` varchar(50) NOT NULL,
`ptz` int DEFAULT NULL,
`rtcp` int DEFAULT NULL,
`status` bit(1) DEFAULT NULL,
`shareAllLiveStream` int DEFAULT NULL,
PRIMARY KEY (`id`,`serverGBId`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `parent_platform`
--
LOCK TABLES `parent_platform` WRITE;
/*!40000 ALTER TABLE `parent_platform` DISABLE KEYS */;
INSERT INTO `parent_platform` VALUES (1,1,'1112','1111111111111','1111111111','11.11.11.11',111111,'34020000002110000015','192.168.1.3','5060','34020000002110000015','12345678','300','60','UDP','GB2312','1111111111111',1,0,_binary '\0',1);
/*!40000 ALTER TABLE `parent_platform` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `platform_catalog`
--
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) NOT NULL,
`platformId` varchar(50) NOT NULL,
`name` varchar(255) NOT NULL,
`parentId` varchar(50) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `platform_catalog`
--
LOCK TABLES `platform_catalog` WRITE;
/*!40000 ALTER TABLE `platform_catalog` DISABLE KEYS */;
INSERT INTO `platform_catalog` VALUES ('1111111111','1111111111111','11122','1111111111111');
/*!40000 ALTER TABLE `platform_catalog` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `platform_gb_channel`
--
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` (
`channelId` varchar(50) NOT NULL,
`deviceId` varchar(50) NOT NULL,
`platformId` varchar(50) NOT NULL,
`deviceAndChannelId` varchar(50) NOT NULL,
`catalogId` varchar(50) NOT NULL,
PRIMARY KEY (`deviceAndChannelId`,`platformId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `platform_gb_channel`
--
LOCK TABLES `platform_gb_channel` WRITE;
/*!40000 ALTER TABLE `platform_gb_channel` DISABLE KEYS */;
INSERT INTO `platform_gb_channel` VALUES ('34020000001310000001','34020000001320000005','1111111111111','34020000001320000005_34020000001310000001','1111111111'),('34020000001310000001','34020000002000000005','1111111111111','34020000002000000005_34020000001310000001','1111111111'),('34020000001310000065','34020000002000000005','1111111111111','34020000002000000005_34020000001310000065','1111111111'),('34020000001320000001','44010000001110008008','1111111111111','44010000001110008008_34020000001320000001','1111111111');
/*!40000 ALTER TABLE `platform_gb_channel` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `platform_gb_stream`
--
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` (
`platformId` varchar(50) NOT NULL,
`app` varchar(255) NOT NULL,
`stream` varchar(255) NOT NULL,
`catalogId` varchar(50) NOT NULL,
PRIMARY KEY (`platformId`,`app`,`stream`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `platform_gb_stream`
--
LOCK TABLES `platform_gb_stream` WRITE;
/*!40000 ALTER TABLE `platform_gb_stream` DISABLE KEYS */;
INSERT INTO `platform_gb_stream` VALUES ('1111111111111','1000','10000001_52869999','1111111111');
/*!40000 ALTER TABLE `platform_gb_stream` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `role`
--
DROP TABLE IF EXISTS `role`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `role` (
`id` int NOT NULL AUTO_INCREMENT,
`name` text NOT NULL,
`authority` text NOT NULL,
`createTime` varchar(50) NOT NULL,
`updateTime` varchar(50) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `role`
--
LOCK TABLES `role` WRITE;
/*!40000 ALTER TABLE `role` DISABLE KEYS */;
INSERT INTO `role` VALUES (1,'admin','0','2021-04-13 14:14:57','2021-04-13 14:14:57');
/*!40000 ALTER TABLE `role` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `stream_proxy`
--
DROP TABLE IF EXISTS `stream_proxy`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `stream_proxy` (
`type` varchar(50) NOT NULL,
`app` varchar(255) NOT NULL,
`stream` varchar(255) NOT NULL,
`url` varchar(255) DEFAULT NULL,
`src_url` varchar(255) DEFAULT NULL,
`dst_url` varchar(255) DEFAULT NULL,
`timeout_ms` int DEFAULT NULL,
`ffmpeg_cmd_key` varchar(255) DEFAULT NULL,
`rtp_type` varchar(50) DEFAULT NULL,
`mediaServerId` varchar(50) DEFAULT NULL,
`enable_hls` bit(1) DEFAULT NULL,
`enable_mp4` bit(1) DEFAULT NULL,
`enable` bit(1) NOT NULL,
`enable_remove_none_reader` bit(1) NOT NULL,
`createTime` varchar(50) NOT NULL,
PRIMARY KEY (`app`,`stream`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `stream_proxy`
--
LOCK TABLES `stream_proxy` WRITE;
/*!40000 ALTER TABLE `stream_proxy` DISABLE KEYS */;
/*!40000 ALTER TABLE `stream_proxy` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `stream_push`
--
DROP TABLE IF EXISTS `stream_push`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `stream_push` (
`app` varchar(255) NOT NULL,
`stream` varchar(255) NOT NULL,
`totalReaderCount` varchar(50) DEFAULT NULL,
`originType` int DEFAULT NULL,
`originTypeStr` varchar(50) DEFAULT NULL,
`createStamp` int DEFAULT NULL,
`aliveSecond` int DEFAULT NULL,
`mediaServerId` varchar(50) DEFAULT NULL,
PRIMARY KEY (`app`,`stream`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `stream_push`
--
LOCK TABLES `stream_push` WRITE;
/*!40000 ALTER TABLE `stream_push` DISABLE KEYS */;
INSERT INTO `stream_push` VALUES ('1000','10000001_52869999','0',2,'rtsp_push',1641366850,0,'XR1LEpKlfQtSg9Z1');
/*!40000 ALTER TABLE `stream_push` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `user`
--
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) NOT NULL,
`password` varchar(255) NOT NULL,
`roleId` int NOT NULL,
`createTime` varchar(50) NOT NULL,
`updateTime` varchar(50) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `user_username_uindex` (`username`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `user`
--
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');
/*!40000 ALTER TABLE `user` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Dumping routines for database 'wvp'
--
/*!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 */;
-- Dump completed on 2022-01-05 15:15:35

12
sql/mysql.sql

@ -171,6 +171,7 @@ create table parent_platform
keepTimeout varchar(50) null, keepTimeout varchar(50) null,
transport varchar(50) null, transport varchar(50) null,
characterSet varchar(50) null, characterSet varchar(50) null,
catalogId varchar(50) not null,
ptz int null, ptz int null,
rtcp int null, rtcp int null,
status bit null, status bit null,
@ -178,12 +179,22 @@ create table parent_platform
primary key (id, serverGBId) primary key (id, serverGBId)
); );
create table platform_catalog
(
id varchar(50) primary key,
platformId varchar(50) not null,
name varchar(255) not null,
parentId varchar(50)
);
create table platform_gb_channel create table platform_gb_channel
( (
channelId varchar(50) not null, channelId varchar(50) not null,
deviceId varchar(50) not null, deviceId varchar(50) not null,
platformId varchar(50) not null, platformId varchar(50) not null,
deviceAndChannelId varchar(50) not null, deviceAndChannelId varchar(50) not null,
catalogId varchar(50) not null,
primary key (deviceAndChannelId, platformId) primary key (deviceAndChannelId, platformId)
); );
@ -192,6 +203,7 @@ create table platform_gb_stream
platformId varchar(50) not null, platformId varchar(50) not null,
app varchar(255) not null, app varchar(255) not null,
stream varchar(255) not null, stream varchar(255) not null,
catalogId varchar(50) not null,
primary key (platformId, app, stream) primary key (platformId, app, stream)
); );

6
src/main/java/com/genersoft/iot/vmp/common/VideoManagerConstants.java

@ -58,9 +58,15 @@ public class VideoManagerConstants {
public static final String SIP_CSEQ_PREFIX = "VMP_SIP_CSEQ_"; public static final String SIP_CSEQ_PREFIX = "VMP_SIP_CSEQ_";
public static final String SIP_SN_PREFIX = "VMP_SIP_SN_";
public static final String SIP_SUBSCRIBE_PREFIX = "SIP_SUBSCRIBE_";
//************************** redis 消息********************************* //************************** redis 消息*********************************
public static final String WVP_MSG_STREAM_CHANGE_PREFIX = "WVP_MSG_STREAM_CHANGE_"; public static final String WVP_MSG_STREAM_CHANGE_PREFIX = "WVP_MSG_STREAM_CHANGE_";
public static final String WVP_MSG_GPS_PREFIX = "VM_MSG_GPS";
//************************** 第三方 **************************************** //************************** 第三方 ****************************************
public static final String WVP_STREAM_GB_ID_PREFIX = "memberNo_"; public static final String WVP_STREAM_GB_ID_PREFIX = "memberNo_";
public static final String WVP_STREAM_GPS_MSG_PREFIX = "WVP_STREAM_GPS_MSG_";
} }

5
src/main/java/com/genersoft/iot/vmp/conf/DynamicTask.java

@ -3,7 +3,6 @@ package com.genersoft.iot.vmp.conf;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.util.Map; import java.util.Map;
@ -40,4 +39,8 @@ public class DynamicTask {
} }
} }
public boolean contains(String key) {
return futureMap.get(key) != null;
}
} }

8
src/main/java/com/genersoft/iot/vmp/conf/RedisConfig.java

@ -1,12 +1,16 @@
package com.genersoft.iot.vmp.conf; package com.genersoft.iot.vmp.conf;
import com.genersoft.iot.vmp.common.VideoManagerConstants;
import com.genersoft.iot.vmp.service.impl.RedisGPSMsgListener;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.annotation.CachingConfigurerSupport; import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.listener.PatternTopic;
import org.springframework.data.redis.listener.RedisMessageListenerContainer; import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.data.redis.serializer.StringRedisSerializer; import org.springframework.data.redis.serializer.StringRedisSerializer;
@ -41,6 +45,9 @@ public class RedisConfig extends CachingConfigurerSupport {
@Value("${spring.redis.poolMaxWait:5}") @Value("${spring.redis.poolMaxWait:5}")
private int poolMaxWait; private int poolMaxWait;
@Autowired
private RedisGPSMsgListener redisGPSMsgListener;
@Bean @Bean
public JedisPool jedisPool() { public JedisPool jedisPool() {
if (StringUtils.isBlank(password)) { if (StringUtils.isBlank(password)) {
@ -85,6 +92,7 @@ public class RedisConfig extends CachingConfigurerSupport {
RedisMessageListenerContainer container = new RedisMessageListenerContainer(); RedisMessageListenerContainer container = new RedisMessageListenerContainer();
container.setConnectionFactory(connectionFactory); container.setConnectionFactory(connectionFactory);
container.addMessageListener(redisGPSMsgListener, new PatternTopic(VideoManagerConstants.WVP_MSG_GPS_PREFIX));
return container; return container;
} }

41
src/main/java/com/genersoft/iot/vmp/conf/RedisKeyExpirationEventMessageListener.java

@ -0,0 +1,41 @@
package com.genersoft.iot.vmp.conf;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.listener.KeyExpirationEventMessageListener;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.util.StringUtils;
import java.util.Properties;
public class RedisKeyExpirationEventMessageListener extends KeyExpirationEventMessageListener {
private UserSetup userSetup;
private RedisMessageListenerContainer listenerContainer;
private String keyspaceNotificationsConfigParameter = "EA";
public RedisKeyExpirationEventMessageListener(RedisMessageListenerContainer listenerContainer, UserSetup userSetup) {
super(listenerContainer);
this.listenerContainer = listenerContainer;
this.userSetup = userSetup;
}
@Override
public void init() {
if (!userSetup.getRedisConfig()) {
// 配置springboot默认Config为空,即不让应用去修改redis的默认配置,因为Redis服务出于安全会禁用CONFIG命令给远程用户使用
setKeyspaceNotificationsConfigParameter("");
}else {
RedisConnection connection = this.listenerContainer.getConnectionFactory().getConnection();
Properties config = connection.getConfig("notify-keyspace-events");
try {
if (!config.getProperty("notify-keyspace-events").equals(keyspaceNotificationsConfigParameter)) {
connection.setConfig("notify-keyspace-events", keyspaceNotificationsConfigParameter);
}
} finally {
connection.close();
}
}
super.init();
}
}

14
src/main/java/com/genersoft/iot/vmp/conf/runner/SipDeviceRunner.java

@ -1,7 +1,8 @@
package com.genersoft.iot.vmp.conf.runner; package com.genersoft.iot.vmp.conf.runner;
import com.genersoft.iot.vmp.common.VideoManagerConstants;
import com.genersoft.iot.vmp.conf.UserSetup; import com.genersoft.iot.vmp.conf.UserSetup;
import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.service.IDeviceService;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage; import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import com.genersoft.iot.vmp.storager.IVideoManagerStorager; import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@ -28,6 +29,9 @@ public class SipDeviceRunner implements CommandLineRunner {
@Autowired @Autowired
private UserSetup userSetup; private UserSetup userSetup;
@Autowired
private IDeviceService deviceService;
@Override @Override
public void run(String... args) throws Exception { public void run(String... args) throws Exception {
// 读取redis没有心跳信息的则设置为离线,等收到下次心跳设置为在线 // 读取redis没有心跳信息的则设置为离线,等收到下次心跳设置为在线
@ -36,9 +40,15 @@ public class SipDeviceRunner implements CommandLineRunner {
List<String> onlineForAll = redisCatchStorage.getOnlineForAll(); List<String> onlineForAll = redisCatchStorage.getOnlineForAll();
for (String deviceId : onlineForAll) { for (String deviceId : onlineForAll) {
storager.online(deviceId); storager.online(deviceId);
Device device = redisCatchStorage.getDevice(deviceId);
if (device != null && device.getSubscribeCycleForCatalog() > 0) {
// 查询在线设备那些开启了订阅,为设备开启定时的目录订阅
deviceService.addCatalogSubscribe(device);
}
} }
// 重置cseq计数 // 重置cseq计数
redisCatchStorage.resetAllCSEQ(); redisCatchStorage.resetAllCSEQ();
// TODO 查询在线设备那些开启了订阅,为设备开启定时的目录订阅
} }
} }

2
src/main/java/com/genersoft/iot/vmp/conf/security/AnonymousAuthenticationEntryPoint.java

@ -21,7 +21,7 @@ public class AnonymousAuthenticationEntryPoint implements AuthenticationEntryPoi
@Override @Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) { public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) {
logger.debug("用户需要登录,访问[{}]失败,AuthenticationException=[{}]", request.getRequestURI(), e.getMessage()); // logger.debug("用户需要登录,访问[{}]失败,AuthenticationException=[{}]", request.getRequestURI(), e.getMessage());
// 允许跨域 // 允许跨域
response.setHeader("Access-Control-Allow-Origin", "*"); response.setHeader("Access-Control-Allow-Origin", "*");
// 允许自定义请求头token(允许head跨域) // 允许自定义请求头token(允许head跨域)

8
src/main/java/com/genersoft/iot/vmp/gb28181/bean/CmdType.java

@ -0,0 +1,8 @@
package com.genersoft.iot.vmp.gb28181.bean;
public class CmdType {
public static final String CATALOG = "Catalog";
public static final String ALARM = "Alarm";
public static final String MOBILE_POSITION = "MobilePosition";
}

21
src/main/java/com/genersoft/iot/vmp/gb28181/bean/DeviceNotFoundEvent.java

@ -0,0 +1,21 @@
package com.genersoft.iot.vmp.gb28181.bean;
import javax.sip.Dialog;
import java.util.EventObject;
public class DeviceNotFoundEvent extends EventObject {
/**
* Constructs a prototypical Event.
*
* @param dialog
* @throws IllegalArgumentException if source is null.
*/
public DeviceNotFoundEvent(Dialog dialog) {
super(dialog);
}
public Dialog getDialog() {
return (Dialog)super.getSource();
}
}

13
src/main/java/com/genersoft/iot/vmp/gb28181/bean/ParentPlatform.java

@ -109,6 +109,11 @@ public class ParentPlatform {
*/ */
private boolean shareAllLiveStream; private boolean shareAllLiveStream;
/**
* 默认目录Id,自动添加的通道多放在这个目录下
*/
private String catalogId;
public Integer getId() { public Integer getId() {
return id; return id;
} }
@ -277,4 +282,12 @@ public class ParentPlatform {
public void setShareAllLiveStream(boolean shareAllLiveStream) { public void setShareAllLiveStream(boolean shareAllLiveStream) {
this.shareAllLiveStream = shareAllLiveStream; this.shareAllLiveStream = shareAllLiveStream;
} }
public String getCatalogId() {
return catalogId;
}
public void setCatalogId(String catalogId) {
this.catalogId = catalogId;
}
} }

71
src/main/java/com/genersoft/iot/vmp/gb28181/bean/PlatformCatalog.java

@ -0,0 +1,71 @@
package com.genersoft.iot.vmp.gb28181.bean;
public class PlatformCatalog {
private String id;
private String name;
private String platformId;
private String parentId;
private int childrenCount; // 子节点数
private int type; // 0 目录, 1 国标通道, 2 直播流
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPlatformId() {
return platformId;
}
public void setPlatformId(String platformId) {
this.platformId = platformId;
}
public String getParentId() {
return parentId;
}
public void setParentId(String parentId) {
this.parentId = parentId;
}
public int getChildrenCount() {
return childrenCount;
}
public void setChildrenCount(int childrenCount) {
this.childrenCount = childrenCount;
}
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
public void setTypeForCatalog() {
this.type = 0;
}
public void setTypeForGb() {
this.type = 1;
}
public void setTypeForStream() {
this.type = 2;
}
}

8
src/main/java/com/genersoft/iot/vmp/gb28181/bean/PlatformGbStream.java

@ -4,6 +4,7 @@ public class PlatformGbStream {
private String app; private String app;
private String stream; private String stream;
private String platformId; private String platformId;
private String catalogId;
public String getApp() { public String getApp() {
return app; return app;
@ -29,4 +30,11 @@ public class PlatformGbStream {
this.platformId = platformId; this.platformId = platformId;
} }
public String getCatalogId() {
return catalogId;
}
public void setCatalogId(String catalogId) {
this.catalogId = catalogId;
}
} }

78
src/main/java/com/genersoft/iot/vmp/gb28181/bean/SubscribeInfo.java

@ -0,0 +1,78 @@
package com.genersoft.iot.vmp.gb28181.bean;
import javax.sip.RequestEvent;
import javax.sip.header.*;
import javax.sip.message.Request;
public class SubscribeInfo {
public SubscribeInfo() {
}
public SubscribeInfo(RequestEvent evt, String id) {
this.id = id;
Request request = evt.getRequest();
CallIdHeader callIdHeader = (CallIdHeader)request.getHeader(CallIdHeader.NAME);
this.callId = callIdHeader.getCallId();
FromHeader fromHeader = (FromHeader)request.getHeader(FromHeader.NAME);
this.fromTag = fromHeader.getTag();
ExpiresHeader expiresHeader = (ExpiresHeader)request.getHeader(ExpiresHeader.NAME);
this.expires = expiresHeader.getExpires();
this.event = ((EventHeader)request.getHeader(EventHeader.NAME)).getName();
}
private String id;
private int expires;
private String callId;
private String event;
private String fromTag;
private String toTag;
public String getId() {
return id;
}
public int getExpires() {
return expires;
}
public String getCallId() {
return callId;
}
public String getFromTag() {
return fromTag;
}
public void setToTag(String toTag) {
this.toTag = toTag;
}
public String getToTag() {
return toTag;
}
public void setId(String id) {
this.id = id;
}
public void setExpires(int expires) {
this.expires = expires;
}
public void setCallId(String callId) {
this.callId = callId;
}
public void setFromTag(String fromTag) {
this.fromTag = fromTag;
}
public String getEvent() {
return event;
}
public void setEvent(String event) {
this.event = event;
}
}

54
src/main/java/com/genersoft/iot/vmp/gb28181/event/EventPublisher.java

@ -1,19 +1,28 @@
package com.genersoft.iot.vmp.gb28181.event; package com.genersoft.iot.vmp.gb28181.event;
import com.genersoft.iot.vmp.gb28181.bean.Device; import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
import com.genersoft.iot.vmp.gb28181.bean.GbStream;
import com.genersoft.iot.vmp.gb28181.event.offline.OfflineEvent; import com.genersoft.iot.vmp.gb28181.event.offline.OfflineEvent;
import com.genersoft.iot.vmp.gb28181.event.platformKeepaliveExpire.PlatformKeepaliveExpireEvent; import com.genersoft.iot.vmp.gb28181.event.platformKeepaliveExpire.PlatformKeepaliveExpireEvent;
import com.genersoft.iot.vmp.gb28181.event.platformNotRegister.PlatformNotRegisterEvent; import com.genersoft.iot.vmp.gb28181.event.platformNotRegister.PlatformNotRegisterEvent;
import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent;
import com.genersoft.iot.vmp.media.zlm.event.ZLMOfflineEvent; import com.genersoft.iot.vmp.media.zlm.event.ZLMOfflineEvent;
import com.genersoft.iot.vmp.media.zlm.event.ZLMOnlineEvent; import com.genersoft.iot.vmp.media.zlm.event.ZLMOnlineEvent;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.ApplicationEventPublisher;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import com.genersoft.iot.vmp.gb28181.bean.DeviceAlarm; import com.genersoft.iot.vmp.gb28181.bean.DeviceAlarm;
import com.genersoft.iot.vmp.gb28181.event.alarm.AlarmEvent; import com.genersoft.iot.vmp.gb28181.event.alarm.AlarmEvent;
import com.genersoft.iot.vmp.gb28181.event.online.OnlineEvent; import com.genersoft.iot.vmp.gb28181.event.online.OnlineEvent;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/** /**
* @description:Event事件通知推送器支持推送在线事件离线事件 * @description:Event事件通知推送器支持推送在线事件离线事件
* @author: swwheihei * @author: swwheihei
@ -80,4 +89,49 @@ public class EventPublisher {
outEvent.setMediaServerId(mediaServerId); outEvent.setMediaServerId(mediaServerId);
applicationEventPublisher.publishEvent(outEvent); applicationEventPublisher.publishEvent(outEvent);
} }
@Async
public void catalogEventPublish(String platformId, DeviceChannel deviceChannel, String type) {
List<DeviceChannel> deviceChannelList = new ArrayList<>();
deviceChannelList.add(deviceChannel);
catalogEventPublish(platformId, deviceChannelList, type);
}
@Async
public void catalogEventPublish(String platformId, List<DeviceChannel> deviceChannels, String type) {
CatalogEvent outEvent = new CatalogEvent(this);
List<DeviceChannel> channels = new ArrayList<>();
if (deviceChannels.size() > 1) {
// 数据去重
Set<String> gbIdSet = new HashSet<>();
for (DeviceChannel deviceChannel : deviceChannels) {
if (!gbIdSet.contains(deviceChannel.getChannelId())) {
gbIdSet.add(deviceChannel.getChannelId());
channels.add(deviceChannel);
}
}
}else {
channels = deviceChannels;
}
outEvent.setDeviceChannels(channels);
outEvent.setType(type);
outEvent.setPlatformId(platformId);
applicationEventPublisher.publishEvent(outEvent);
}
@Async
public void catalogEventPublishForStream(String platformId, List<GbStream> gbStreams, String type) {
CatalogEvent outEvent = new CatalogEvent(this);
outEvent.setGbStreams(gbStreams);
outEvent.setType(type);
outEvent.setPlatformId(platformId);
applicationEventPublisher.publishEvent(outEvent);
}
@Async
public void catalogEventPublishForStream(String platformId, GbStream gbStream, String type) {
List<GbStream> gbStreamList = new ArrayList<>();
gbStreamList.add(gbStream);
catalogEventPublishForStream(platformId, gbStreamList, type);
}
} }

8
src/main/java/com/genersoft/iot/vmp/gb28181/event/SipSubscribe.java

@ -1,5 +1,6 @@
package com.genersoft.iot.vmp.gb28181.event; package com.genersoft.iot.vmp.gb28181.event;
import com.genersoft.iot.vmp.gb28181.bean.DeviceNotFoundEvent;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Scheduled; import org.springframework.scheduling.annotation.Scheduled;
@ -91,6 +92,13 @@ public class SipSubscribe {
this.statusCode = -1024; this.statusCode = -1024;
this.callId = dialogTerminatedEvent.getDialog().getCallId().getCallId(); this.callId = dialogTerminatedEvent.getDialog().getCallId().getCallId();
this.dialog = dialogTerminatedEvent.getDialog(); this.dialog = dialogTerminatedEvent.getDialog();
}else if (event instanceof DeviceNotFoundEvent) {
DeviceNotFoundEvent deviceNotFoundEvent = (DeviceNotFoundEvent)event;
this.type = "deviceNotFoundEvent";
this.msg = "设备未找到";
this.statusCode = -1024;
this.callId = deviceNotFoundEvent.getDialog().getCallId().getCallId();
this.dialog = deviceNotFoundEvent.getDialog();
} }
} }
} }

30
src/main/java/com/genersoft/iot/vmp/gb28181/event/offline/KeepaliveTimeoutListenerForPlatform.java

@ -1,18 +1,24 @@
package com.genersoft.iot.vmp.gb28181.event.offline; package com.genersoft.iot.vmp.gb28181.event.offline;
import com.genersoft.iot.vmp.conf.RedisKeyExpirationEventMessageListener;
import com.genersoft.iot.vmp.conf.UserSetup; import com.genersoft.iot.vmp.conf.UserSetup;
import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.DependsOn; import org.springframework.context.annotation.DependsOn;
import org.springframework.data.redis.connection.Message; import org.springframework.data.redis.connection.Message;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.listener.KeyExpirationEventMessageListener; import org.springframework.data.redis.listener.KeyExpirationEventMessageListener;
import org.springframework.data.redis.listener.RedisMessageListenerContainer; import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import com.genersoft.iot.vmp.common.VideoManagerConstants; import com.genersoft.iot.vmp.common.VideoManagerConstants;
import com.genersoft.iot.vmp.gb28181.event.EventPublisher; import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
import org.springframework.util.StringUtils;
import java.util.Properties;
/** /**
* @description:设备心跳超时监听,借助redis过期特性进行监听监听到说明设备心跳超时发送离线事件 * @description:设备心跳超时监听,借助redis过期特性进行监听监听到说明设备心跳超时发送离线事件
@ -20,7 +26,7 @@ import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
* @date: 2020年5月6日 上午11:35:46 * @date: 2020年5月6日 上午11:35:46
*/ */
@Component @Component
public class KeepaliveTimeoutListenerForPlatform extends KeyExpirationEventMessageListener { public class KeepaliveTimeoutListenerForPlatform extends RedisKeyExpirationEventMessageListener {
private Logger logger = LoggerFactory.getLogger(KeepaliveTimeoutListenerForPlatform.class); private Logger logger = LoggerFactory.getLogger(KeepaliveTimeoutListenerForPlatform.class);
@ -30,17 +36,11 @@ public class KeepaliveTimeoutListenerForPlatform extends KeyExpirationEventMessa
@Autowired @Autowired
private UserSetup userSetup; private UserSetup userSetup;
@Override @Autowired
public void init() { private SipSubscribe sipSubscribe;
if (!userSetup.getRedisConfig()) {
// 配置springboot默认Config为空,即不让应用去修改redis的默认配置,因为Redis服务出于安全会禁用CONFIG命令给远程用户使用
setKeyspaceNotificationsConfigParameter("");
}
super.init();
}
public KeepaliveTimeoutListenerForPlatform(RedisMessageListenerContainer listenerContainer) { public KeepaliveTimeoutListenerForPlatform(RedisMessageListenerContainer listenerContainer, UserSetup userSetup) {
super(listenerContainer); super(listenerContainer, userSetup);
} }
@ -58,6 +58,7 @@ public class KeepaliveTimeoutListenerForPlatform extends KeyExpirationEventMessa
String PLATFORM_KEEPLIVEKEY_PREFIX = VideoManagerConstants.PLATFORM_KEEPALIVE_PREFIX + userSetup.getServerId() + "_"; String PLATFORM_KEEPLIVEKEY_PREFIX = VideoManagerConstants.PLATFORM_KEEPALIVE_PREFIX + userSetup.getServerId() + "_";
String PLATFORM_REGISTER_PREFIX = VideoManagerConstants.PLATFORM_REGISTER_PREFIX + userSetup.getServerId() + "_"; String PLATFORM_REGISTER_PREFIX = VideoManagerConstants.PLATFORM_REGISTER_PREFIX + userSetup.getServerId() + "_";
String KEEPLIVEKEY_PREFIX = VideoManagerConstants.KEEPLIVEKEY_PREFIX + userSetup.getServerId() + "_"; String KEEPLIVEKEY_PREFIX = VideoManagerConstants.KEEPLIVEKEY_PREFIX + userSetup.getServerId() + "_";
String REGISTER_INFO_PREFIX = VideoManagerConstants.PLATFORM_REGISTER_INFO_PREFIX + userSetup.getServerId() + "_";
if (expiredKey.startsWith(PLATFORM_KEEPLIVEKEY_PREFIX)) { if (expiredKey.startsWith(PLATFORM_KEEPLIVEKEY_PREFIX)) {
String platformGBId = expiredKey.substring(PLATFORM_KEEPLIVEKEY_PREFIX.length(),expiredKey.length()); String platformGBId = expiredKey.substring(PLATFORM_KEEPLIVEKEY_PREFIX.length(),expiredKey.length());
@ -69,6 +70,13 @@ public class KeepaliveTimeoutListenerForPlatform extends KeyExpirationEventMessa
}else if (expiredKey.startsWith(KEEPLIVEKEY_PREFIX)){ }else if (expiredKey.startsWith(KEEPLIVEKEY_PREFIX)){
String deviceId = expiredKey.substring(KEEPLIVEKEY_PREFIX.length(),expiredKey.length()); String deviceId = expiredKey.substring(KEEPLIVEKEY_PREFIX.length(),expiredKey.length());
publisher.outlineEventPublish(deviceId, KEEPLIVEKEY_PREFIX); publisher.outlineEventPublish(deviceId, KEEPLIVEKEY_PREFIX);
}else if (expiredKey.startsWith(REGISTER_INFO_PREFIX)) {
String callid = expiredKey.substring(REGISTER_INFO_PREFIX.length());
SipSubscribe.EventResult eventResult = new SipSubscribe.EventResult();
eventResult.callId = callid;
eventResult.msg = "注册超时";
eventResult.type = "register timeout";
sipSubscribe.getErrorSubscribe(callid).response(eventResult);
} }
} }

10
src/main/java/com/genersoft/iot/vmp/gb28181/event/offline/KeepliveTimeoutListener.java

@ -1,5 +1,6 @@
package com.genersoft.iot.vmp.gb28181.event.offline; package com.genersoft.iot.vmp.gb28181.event.offline;
import com.genersoft.iot.vmp.conf.RedisKeyExpirationEventMessageListener;
import com.genersoft.iot.vmp.conf.UserSetup; import com.genersoft.iot.vmp.conf.UserSetup;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -20,7 +21,7 @@ import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
* @date: 2020年5月6日 上午11:35:46 * @date: 2020年5月6日 上午11:35:46
*/ */
@Component @Component
public class KeepliveTimeoutListener extends KeyExpirationEventMessageListener { public class KeepliveTimeoutListener extends RedisKeyExpirationEventMessageListener {
private Logger logger = LoggerFactory.getLogger(KeepliveTimeoutListener.class); private Logger logger = LoggerFactory.getLogger(KeepliveTimeoutListener.class);
@ -30,6 +31,10 @@ public class KeepliveTimeoutListener extends KeyExpirationEventMessageListener {
@Autowired @Autowired
private UserSetup userSetup; private UserSetup userSetup;
public KeepliveTimeoutListener(RedisMessageListenerContainer listenerContainer, UserSetup userSetup) {
super(listenerContainer, userSetup);
}
@Override @Override
public void init() { public void init() {
if (!userSetup.getRedisConfig()) { if (!userSetup.getRedisConfig()) {
@ -39,9 +44,6 @@ public class KeepliveTimeoutListener extends KeyExpirationEventMessageListener {
super.init(); super.init();
} }
public KeepliveTimeoutListener(RedisMessageListenerContainer listenerContainer) {
super(listenerContainer);
}
/** /**
* 监听失效的keykey格式为keeplive_deviceId * 监听失效的keykey格式为keeplive_deviceId

10
src/main/java/com/genersoft/iot/vmp/gb28181/event/offline/OfflineEventListener.java

@ -1,6 +1,9 @@
package com.genersoft.iot.vmp.gb28181.event.offline; package com.genersoft.iot.vmp.gb28181.event.offline;
import com.genersoft.iot.vmp.conf.UserSetup; import com.genersoft.iot.vmp.conf.UserSetup;
import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@ -13,6 +16,8 @@ import com.genersoft.iot.vmp.common.VideoManagerConstants;
import com.genersoft.iot.vmp.storager.IVideoManagerStorager; import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
import com.genersoft.iot.vmp.utils.redis.RedisUtil; import com.genersoft.iot.vmp.utils.redis.RedisUtil;
import java.util.List;
/** /**
* @description: 离线事件监听器监听到离线后修改设备离在线状态 设备离线有两个来源 * @description: 离线事件监听器监听到离线后修改设备离在线状态 设备离线有两个来源
* 1设备主动注销发送注销指令{@link com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.RegisterRequestProcessor} * 1设备主动注销发送注销指令{@link com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.RegisterRequestProcessor}
@ -34,6 +39,9 @@ public class OfflineEventListener implements ApplicationListener<OfflineEvent> {
@Autowired @Autowired
private UserSetup userSetup; private UserSetup userSetup;
@Autowired
private EventPublisher eventPublisher;
@Override @Override
public void onApplicationEvent(OfflineEvent event) { public void onApplicationEvent(OfflineEvent event) {
@ -58,6 +66,8 @@ public class OfflineEventListener implements ApplicationListener<OfflineEvent> {
} }
} }
List<DeviceChannel> deviceChannelList = storager.queryOnlineChannelsByDeviceId(event.getDeviceId());
eventPublisher.catalogEventPublish(null, deviceChannelList, CatalogEvent.OFF);
// 处理离线监听 // 处理离线监听
storager.outline(event.getDeviceId()); storager.outline(event.getDeviceId());

22
src/main/java/com/genersoft/iot/vmp/gb28181/event/online/OnlineEventListener.java

@ -3,6 +3,10 @@ package com.genersoft.iot.vmp.gb28181.event.online;
import com.genersoft.iot.vmp.conf.SipConfig; import com.genersoft.iot.vmp.conf.SipConfig;
import com.genersoft.iot.vmp.conf.UserSetup; import com.genersoft.iot.vmp.conf.UserSetup;
import com.genersoft.iot.vmp.gb28181.bean.Device; import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent;
import com.genersoft.iot.vmp.service.IDeviceService;
import com.genersoft.iot.vmp.storager.dao.dto.User; import com.genersoft.iot.vmp.storager.dao.dto.User;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -15,6 +19,7 @@ import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
import com.genersoft.iot.vmp.utils.redis.RedisUtil; import com.genersoft.iot.vmp.utils.redis.RedisUtil;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.List;
/** /**
* @description: 在线事件监听器监听到离线后修改设备离在线状态 设备在线有两个来源 * @description: 在线事件监听器监听到离线后修改设备离在线状态 设备在线有两个来源
@ -30,6 +35,9 @@ public class OnlineEventListener implements ApplicationListener<OnlineEvent> {
@Autowired @Autowired
private IVideoManagerStorager storager; private IVideoManagerStorager storager;
@Autowired
private IDeviceService deviceService;
@Autowired @Autowired
private RedisUtil redis; private RedisUtil redis;
@ -40,6 +48,9 @@ public class OnlineEventListener implements ApplicationListener<OnlineEvent> {
@Autowired @Autowired
private UserSetup userSetup; private UserSetup userSetup;
@Autowired
private EventPublisher eventPublisher;
private SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); private SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
@Override @Override
@ -49,6 +60,7 @@ public class OnlineEventListener implements ApplicationListener<OnlineEvent> {
logger.debug("设备上线事件触发,deviceId:" + event.getDevice().getDeviceId() + ",from:" + event.getFrom()); logger.debug("设备上线事件触发,deviceId:" + event.getDevice().getDeviceId() + ",from:" + event.getFrom());
} }
Device device = event.getDevice(); Device device = event.getDevice();
if (device == null) return;
String key = VideoManagerConstants.KEEPLIVEKEY_PREFIX + userSetup.getServerId() + "_" + event.getDevice().getDeviceId(); String key = VideoManagerConstants.KEEPLIVEKEY_PREFIX + userSetup.getServerId() + "_" + event.getDevice().getDeviceId();
switch (event.getFrom()) { switch (event.getFrom()) {
@ -76,10 +88,18 @@ public class OnlineEventListener implements ApplicationListener<OnlineEvent> {
} }
device.setOnline(1); device.setOnline(1);
Device deviceInStore = storager.queryVideoDevice(device.getDeviceId());
if (deviceInStore != null && deviceInStore.getOnline() == 0) {
List<DeviceChannel> deviceChannelList = storager.queryOnlineChannelsByDeviceId(device.getDeviceId());
eventPublisher.catalogEventPublish(null, deviceChannelList, CatalogEvent.ON);
}
// 处理上线监听 // 处理上线监听
storager.updateDevice(device); storager.updateDevice(device);
// TODO 上线添加订阅 // 上线添加订阅
if (device.getSubscribeCycleForCatalog() > 0) {
deviceService.addCatalogSubscribe(device);
}
} }
} }

52
src/main/java/com/genersoft/iot/vmp/gb28181/event/subscribe/SubscribeListenerForPlatform.java

@ -0,0 +1,52 @@
package com.genersoft.iot.vmp.gb28181.event.subscribe;
import com.genersoft.iot.vmp.common.VideoManagerConstants;
import com.genersoft.iot.vmp.conf.DynamicTask;
import com.genersoft.iot.vmp.conf.RedisKeyExpirationEventMessageListener;
import com.genersoft.iot.vmp.conf.UserSetup;
import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
import org.checkerframework.checker.units.qual.A;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.Message;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.stereotype.Component;
/**
* 平台订阅到期事件
*/
@Component
public class SubscribeListenerForPlatform extends RedisKeyExpirationEventMessageListener {
private Logger logger = LoggerFactory.getLogger(SubscribeListenerForPlatform.class);
@Autowired
private UserSetup userSetup;
@Autowired
private DynamicTask dynamicTask;
public SubscribeListenerForPlatform(RedisMessageListenerContainer listenerContainer, UserSetup userSetup) {
super(listenerContainer, userSetup);
}
/**
* 监听失效的key
* @param message
* @param pattern
*/
@Override
public void onMessage(Message message, byte[] pattern) {
// 获取失效的key
String expiredKey = message.toString();
logger.debug(expiredKey);
// 订阅到期
String PLATFORM_KEEPLIVEKEY_PREFIX = VideoManagerConstants.SIP_SUBSCRIBE_PREFIX + userSetup.getServerId() + "_";
if (expiredKey.startsWith(PLATFORM_KEEPLIVEKEY_PREFIX)) {
// 取消定时任务
dynamicTask.stopCron(expiredKey);
}
}
}

58
src/main/java/com/genersoft/iot/vmp/gb28181/event/subscribe/catalog/CatalogEvent.java

@ -0,0 +1,58 @@
package com.genersoft.iot.vmp.gb28181.event.subscribe.catalog;
import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
import com.genersoft.iot.vmp.gb28181.bean.GbStream;
import org.springframework.context.ApplicationEvent;
import java.util.List;
public class CatalogEvent extends ApplicationEvent {
public CatalogEvent(Object source) {
super(source);
}
public static final String ON = "ON"; // 上线
public static final String OFF = "OFF"; // 离线
public static final String VLOST = "VLOST"; // 视频丢失
public static final String DEFECT = "DEFECT"; // 故障
public static final String ADD = "ADD"; // 增加
public static final String DEL = "DEL"; // 删除
public static final String UPDATE = "UPDATE"; // 更新
private List<DeviceChannel> deviceChannels;
private List<GbStream> gbStreams;
private String type;
private String platformId;
public List<DeviceChannel> getDeviceChannels() {
return deviceChannels;
}
public void setDeviceChannels(List<DeviceChannel> deviceChannels) {
this.deviceChannels = deviceChannels;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getPlatformId() {
return platformId;
}
public void setPlatformId(String platformId) {
this.platformId = platformId;
}
public List<GbStream> getGbStreams() {
return gbStreams;
}
public void setGbStreams(List<GbStream> gbStreams) {
this.gbStreams = gbStreams;
}
}

172
src/main/java/com/genersoft/iot/vmp/gb28181/event/subscribe/catalog/CatalogEventLister.java

@ -0,0 +1,172 @@
package com.genersoft.iot.vmp.gb28181.event.subscribe.catalog;
import com.genersoft.iot.vmp.common.VideoManagerConstants;
import com.genersoft.iot.vmp.conf.SipConfig;
import com.genersoft.iot.vmp.conf.UserSetup;
import com.genersoft.iot.vmp.gb28181.bean.*;
import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
import com.genersoft.iot.vmp.gb28181.event.platformNotRegister.PlatformNotRegisterEvent;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform;
import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
import com.genersoft.iot.vmp.service.IGbStreamService;
import com.genersoft.iot.vmp.service.IMediaServerService;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import java.util.*;
/**
* catalog事件
*/
@Component
public class CatalogEventLister implements ApplicationListener<CatalogEvent> {
private final static Logger logger = LoggerFactory.getLogger(CatalogEventLister.class);
@Autowired
private IVideoManagerStorager storager;
@Autowired
private IRedisCatchStorage redisCatchStorage;
@Autowired
private IMediaServerService mediaServerService;
@Autowired
private SIPCommanderFroPlatform sipCommanderFroPlatform;
@Autowired
private ZLMRTPServerFactory zlmrtpServerFactory;
@Autowired
private SipConfig config;
@Autowired
private UserSetup userSetup;
@Autowired
private IGbStreamService gbStreamService;
@Override
public void onApplicationEvent(CatalogEvent event) {
SubscribeInfo subscribe = null;
ParentPlatform parentPlatform = null;
Map<String, List<ParentPlatform>> parentPlatformMap = new HashMap<>();
if (event.getPlatformId() != null) {
parentPlatform = storager.queryParentPlatByServerGBId(event.getPlatformId());
if (!parentPlatform.isStatus())return;
String key = VideoManagerConstants.SIP_SUBSCRIBE_PREFIX + userSetup.getServerId() + "_Catalog_" + event.getPlatformId();
subscribe = redisCatchStorage.getSubscribe(key);
if (subscribe == null) return;
}else {
// 获取所用订阅
List<String> platforms = redisCatchStorage.getAllSubscribePlatform();
if (event.getDeviceChannels() != null) {
if (platforms.size() > 0) {
for (DeviceChannel deviceChannel : event.getDeviceChannels()) {
List<ParentPlatform> parentPlatformsForGB = storager.queryPlatFormListForGBWithGBId(deviceChannel.getChannelId(), platforms);
parentPlatformMap.put(deviceChannel.getChannelId(), parentPlatformsForGB);
}
}
}else if (event.getGbStreams() != null) {
if (platforms.size() > 0) {
for (GbStream gbStream : event.getGbStreams()) {
if (gbStream == null || StringUtils.isEmpty(gbStream.getGbId())) continue;
List<ParentPlatform> parentPlatformsForGB = storager.queryPlatFormListForStreamWithGBId(gbStream.getApp(),gbStream.getStream(), platforms);
parentPlatformMap.put(gbStream.getGbId(), parentPlatformsForGB);
}
}
}
}
switch (event.getType()) {
case CatalogEvent.ON:
case CatalogEvent.OFF:
case CatalogEvent.DEL:
if (parentPlatform != null || subscribe != null) {
List<DeviceChannel> deviceChannelList = new ArrayList<>();
if (event.getDeviceChannels() != null) {
deviceChannelList.addAll(event.getDeviceChannels());
}
if (event.getGbStreams() != null && event.getGbStreams().size() > 0){
for (GbStream gbStream : event.getGbStreams()) {
DeviceChannel deviceChannelByStream = gbStreamService.getDeviceChannelListByStream(gbStream, gbStream.getCatalogId(), parentPlatform.getDeviceGBId());
deviceChannelList.add(deviceChannelByStream);
}
}
if (deviceChannelList.size() > 0) {
logger.info("[Catalog事件: {}]平台:{},影响通道{}个", event.getType(), event.getPlatformId(), deviceChannelList.size());
sipCommanderFroPlatform.sendNotifyForCatalogOther(event.getType(), parentPlatform, deviceChannelList, subscribe);
}
}else if (parentPlatformMap.keySet().size() > 0) {
for (String gbId : parentPlatformMap.keySet()) {
List<ParentPlatform> parentPlatforms = parentPlatformMap.get(gbId);
if (parentPlatforms != null && parentPlatforms.size() > 0) {
for (ParentPlatform platform : parentPlatforms) {
String key = VideoManagerConstants.SIP_SUBSCRIBE_PREFIX + userSetup.getServerId() + "_Catalog_" + platform.getServerGBId();
SubscribeInfo subscribeInfo = redisCatchStorage.getSubscribe(key);
if (subscribeInfo == null) continue;
logger.info("[Catalog事件: {}]平台:{},影响通道{}", event.getType(), platform.getServerGBId(), gbId);
List<DeviceChannel> deviceChannelList = new ArrayList<>();
DeviceChannel deviceChannel = new DeviceChannel();
deviceChannel.setChannelId(gbId);
deviceChannelList.add(deviceChannel);
sipCommanderFroPlatform.sendNotifyForCatalogOther(event.getType(), platform, deviceChannelList, subscribeInfo);
}
}
}
}
break;
case CatalogEvent.VLOST:
break;
case CatalogEvent.DEFECT:
break;
case CatalogEvent.ADD:
case CatalogEvent.UPDATE:
if (parentPlatform != null || subscribe != null) {
List<DeviceChannel> deviceChannelList = new ArrayList<>();
if (event.getDeviceChannels() != null) {
deviceChannelList.addAll(event.getDeviceChannels());
}
if (event.getGbStreams() != null && event.getGbStreams().size() > 0){
for (GbStream gbStream : event.getGbStreams()) {
DeviceChannel deviceChannelByStream = gbStreamService.getDeviceChannelListByStream(gbStream, gbStream.getCatalogId(), parentPlatform.getDeviceGBId());
deviceChannelList.add(deviceChannelByStream);
}
}
if (deviceChannelList.size() > 0) {
logger.info("[Catalog事件: {}]平台:{},影响通道{}个", event.getType(), event.getPlatformId(), deviceChannelList.size());
sipCommanderFroPlatform.sendNotifyForCatalogAddOrUpdate(event.getType(), parentPlatform, deviceChannelList, subscribe);
}
}else if (parentPlatformMap.keySet().size() > 0) {
for (String gbId : parentPlatformMap.keySet()) {
List<ParentPlatform> parentPlatforms = parentPlatformMap.get(gbId);
if (parentPlatforms != null && parentPlatforms.size() > 0) {
for (ParentPlatform platform : parentPlatforms) {
String key = VideoManagerConstants.SIP_SUBSCRIBE_PREFIX + userSetup.getServerId() + "_Catalog_" + platform.getServerGBId();
SubscribeInfo subscribeInfo = redisCatchStorage.getSubscribe(key);
if (subscribeInfo == null) continue;
logger.info("[Catalog事件: {}]平台:{},影响通道{}", event.getType(), platform.getServerGBId(), gbId);
List<DeviceChannel> deviceChannelList = new ArrayList<>();
DeviceChannel deviceChannel = storager.queryChannelInParentPlatform(platform.getServerGBId(), gbId);
deviceChannelList.add(deviceChannel);
GbStream gbStream = storager.queryStreamInParentPlatform(platform.getServerGBId(), gbId);
DeviceChannel deviceChannelByStream = gbStreamService.getDeviceChannelListByStream(gbStream, gbStream.getCatalogId(), platform.getDeviceGBId());
deviceChannelList.add(deviceChannelByStream);
sipCommanderFroPlatform.sendNotifyForCatalogOther(event.getType(), platform, deviceChannelList, subscribeInfo);
}
}
}
}
break;
default:
break;
}
}
}

70
src/main/java/com/genersoft/iot/vmp/gb28181/task/GPSSubscribeTask.java

@ -0,0 +1,70 @@
package com.genersoft.iot.vmp.gb28181.task;
import com.genersoft.iot.vmp.gb28181.bean.GbStream;
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
import com.genersoft.iot.vmp.gb28181.bean.SubscribeInfo;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform;
import com.genersoft.iot.vmp.service.bean.GPSMsgInfo;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
import java.text.SimpleDateFormat;
import java.util.List;
public class GPSSubscribeTask implements Runnable{
private IRedisCatchStorage redisCatchStorage;
private IVideoManagerStorager storager;
private ISIPCommanderForPlatform sipCommanderForPlatform;
private String platformId;
private String sn;
private String key;
private final SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
public GPSSubscribeTask(IRedisCatchStorage redisCatchStorage, ISIPCommanderForPlatform sipCommanderForPlatform, IVideoManagerStorager storager, String platformId, String sn, String key) {
this.redisCatchStorage = redisCatchStorage;
this.storager = storager;
this.platformId = platformId;
this.sn = sn;
this.key = key;
this.sipCommanderForPlatform = sipCommanderForPlatform;
}
@Override
public void run() {
SubscribeInfo subscribe = redisCatchStorage.getSubscribe(key);
if (subscribe != null) {
System.out.println("发送GPS消息");
ParentPlatform parentPlatform = storager.queryParentPlatByServerGBId(platformId);
if (parentPlatform == null || parentPlatform.isStatus()) {
// TODO 暂时只处理视频流的回复,后续增加对国标设备的支持
List<GbStream> gbStreams = storager.queryGbStreamListInPlatform(platformId);
if (gbStreams.size() > 0) {
for (GbStream gbStream : gbStreams) {
String gbId = gbStream.getGbId();
GPSMsgInfo gpsMsgInfo = redisCatchStorage.getGpsMsgInfo(gbId);
if (gbStream.isStatus()) {
if (gpsMsgInfo != null) {
// 发送GPS消息
sipCommanderForPlatform.sendNotifyMobilePosition(parentPlatform, gpsMsgInfo, subscribe);
}else {
// 没有在redis找到新的消息就使用数据库的消息
gpsMsgInfo = new GPSMsgInfo();
gpsMsgInfo.setId(gbId);
gpsMsgInfo.setLat(gbStream.getLongitude());
gpsMsgInfo.setLng(gbStream.getLongitude());
// 发送GPS消息
sipCommanderForPlatform.sendNotifyMobilePosition(parentPlatform, gpsMsgInfo, subscribe);
}
}
}
}
}
}
}
}

22
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPProcessorObserver.java

@ -14,6 +14,7 @@ import org.springframework.stereotype.Component;
import javax.sip.*; import javax.sip.*;
import javax.sip.header.CSeqHeader; import javax.sip.header.CSeqHeader;
import javax.sip.header.CallIdHeader; import javax.sip.header.CallIdHeader;
import javax.sip.header.Header;
import javax.sip.message.Response; import javax.sip.message.Response;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
@ -94,7 +95,6 @@ public class SIPProcessorObserver implements ISIPProcessorObserver {
logger.debug(responseEvent.getResponse().toString()); logger.debug(responseEvent.getResponse().toString());
int status = response.getStatusCode(); int status = response.getStatusCode();
if (((status >= 200) && (status < 300)) || status == 401) { // Success! if (((status >= 200) && (status < 300)) || status == 401) { // Success!
// ISIPResponseProcessor processor = processorFactory.createResponseProcessor(evt);
CSeqHeader cseqHeader = (CSeqHeader) responseEvent.getResponse().getHeader(CSeqHeader.NAME); CSeqHeader cseqHeader = (CSeqHeader) responseEvent.getResponse().getHeader(CSeqHeader.NAME);
String method = cseqHeader.getMethod(); String method = cseqHeader.getMethod();
ISIPResponseProcessor sipRequestProcessor = responseProcessorMap.get(method); ISIPResponseProcessor sipRequestProcessor = responseProcessorMap.get(method);
@ -108,6 +108,7 @@ public class SIPProcessorObserver implements ISIPProcessorObserver {
if (subscribe != null) { if (subscribe != null) {
SipSubscribe.EventResult eventResult = new SipSubscribe.EventResult(responseEvent); SipSubscribe.EventResult eventResult = new SipSubscribe.EventResult(responseEvent);
subscribe.response(eventResult); subscribe.response(eventResult);
sipSubscribe.removeOkSubscribe(callIdHeader.getCallId());
} }
} }
} }
@ -122,6 +123,7 @@ public class SIPProcessorObserver implements ISIPProcessorObserver {
if (subscribe != null) { if (subscribe != null) {
SipSubscribe.EventResult eventResult = new SipSubscribe.EventResult(responseEvent); SipSubscribe.EventResult eventResult = new SipSubscribe.EventResult(responseEvent);
subscribe.response(eventResult); subscribe.response(eventResult);
sipSubscribe.removeErrorSubscribe(callIdHeader.getCallId());
} }
} }
} }
@ -139,6 +141,7 @@ public class SIPProcessorObserver implements ISIPProcessorObserver {
*/ */
@Override @Override
public void processTimeout(TimeoutEvent timeoutEvent) { public void processTimeout(TimeoutEvent timeoutEvent) {
System.out.println("processTimeout");
if(timeoutProcessor != null) { if(timeoutProcessor != null) {
timeoutProcessor.process(timeoutEvent); timeoutProcessor.process(timeoutEvent);
} }
@ -146,14 +149,31 @@ public class SIPProcessorObserver implements ISIPProcessorObserver {
@Override @Override
public void processIOException(IOExceptionEvent exceptionEvent) { public void processIOException(IOExceptionEvent exceptionEvent) {
System.out.println("processIOException");
} }
@Override @Override
public void processTransactionTerminated(TransactionTerminatedEvent transactionTerminatedEvent) { public void processTransactionTerminated(TransactionTerminatedEvent transactionTerminatedEvent) {
// Transaction transaction = null;
// System.out.println("processTransactionTerminated");
// if (transactionTerminatedEvent.isServerTransaction()) {
// transaction = transactionTerminatedEvent.getServerTransaction();
// }else {
// transaction = transactionTerminatedEvent.getClientTransaction();
// }
//
// System.out.println(transaction.getBranchId());
// System.out.println(transaction.getState());
// System.out.println(transaction.getRequest().getMethod());
// CallIdHeader header = (CallIdHeader)transaction.getRequest().getHeader(CallIdHeader.NAME);
// SipSubscribe.EventResult<TransactionTerminatedEvent> terminatedEventEventResult = new SipSubscribe.EventResult<>(transactionTerminatedEvent);
// sipSubscribe.getErrorSubscribe(header.getCallId()).response(terminatedEventEventResult);
} }
@Override @Override
public void processDialogTerminated(DialogTerminatedEvent dialogTerminatedEvent) { public void processDialogTerminated(DialogTerminatedEvent dialogTerminatedEvent) {
System.out.println("processDialogTerminated");
CallIdHeader callId = dialogTerminatedEvent.getDialog().getCallId(); CallIdHeader callId = dialogTerminatedEvent.getDialog().getCallId();
} }

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

@ -41,6 +41,8 @@ public class DeferredResultHolder {
public static final String CALLBACK_CMD_STOP = "CALLBACK_STOP"; 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_MOBILEPOSITION = "CALLBACK_MOBILEPOSITION";
public static final String CALLBACK_CMD_PRESETQUERY = "CALLBACK_PRESETQUERY"; public static final String CALLBACK_CMD_PRESETQUERY = "CALLBACK_PRESETQUERY";

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

@ -328,4 +328,13 @@ public interface ISIPCommander {
* @return true = 命令发送成功 * @return true = 命令发送成功
*/ */
boolean catalogSubscribe(Device device, SipSubscribe.Event okEvent ,SipSubscribe.Event errorEvent); boolean catalogSubscribe(Device device, SipSubscribe.Event okEvent ,SipSubscribe.Event errorEvent);
/**
* 拉框控制命令
*
* @param device 控制设备
* @param channelId 通道id
* @param cmdString 前端控制指令串
*/
boolean dragZoomCmd(Device device, String channelId, String cmdString);
} }

26
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommanderForPlatform.java

@ -2,9 +2,12 @@ package com.genersoft.iot.vmp.gb28181.transmit.cmd;
import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
import com.genersoft.iot.vmp.gb28181.bean.SubscribeInfo;
import com.genersoft.iot.vmp.gb28181.event.SipSubscribe; import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
import com.genersoft.iot.vmp.service.bean.GPSMsgInfo;
import javax.sip.header.WWWAuthenticateHeader; import javax.sip.header.WWWAuthenticateHeader;
import java.util.List;
public interface ISIPCommanderForPlatform { public interface ISIPCommanderForPlatform {
@ -61,4 +64,27 @@ public interface ISIPCommanderForPlatform {
*/ */
boolean deviceStatusResponse(ParentPlatform parentPlatform, String sn, String fromTag); boolean deviceStatusResponse(ParentPlatform parentPlatform, String sn, String fromTag);
/**
* 向上级回复移动位置订阅消息
* @param parentPlatform 平台信息
* @param gpsMsgInfo GPS信息
* @param subscribeInfo 订阅相关的信息
* @return
*/
boolean sendNotifyMobilePosition(ParentPlatform parentPlatform, GPSMsgInfo gpsMsgInfo, SubscribeInfo subscribeInfo);
/**
* 回复catalog事件-增加/更新
* @param parentPlatform
* @param deviceChannels
*/
boolean sendNotifyForCatalogAddOrUpdate(String type, ParentPlatform parentPlatform, List<DeviceChannel> deviceChannels, SubscribeInfo subscribeInfo);
/**
* 回复catalog事件-删除
* @param parentPlatform
* @param deviceChannels
*/
boolean sendNotifyForCatalogOther(String type, ParentPlatform parentPlatform, List<DeviceChannel> deviceChannels, SubscribeInfo subscribeInfo);
} }

49
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderPlarformProvider.java

@ -2,6 +2,7 @@ package com.genersoft.iot.vmp.gb28181.transmit.cmd;
import com.genersoft.iot.vmp.conf.SipConfig; import com.genersoft.iot.vmp.conf.SipConfig;
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import gov.nist.javax.sip.message.MessageFactoryImpl; import gov.nist.javax.sip.message.MessageFactoryImpl;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@ -32,6 +33,9 @@ public class SIPRequestHeaderPlarformProvider {
@Autowired @Autowired
private SipFactory sipFactory; private SipFactory sipFactory;
@Autowired
private IRedisCatchStorage redisCatchStorage;
public Request createKeetpaliveMessageRequest(ParentPlatform parentPlatform, String content, String viaTag, String fromTag, String toTag, CallIdHeader callIdHeader) throws ParseException, InvalidArgumentException, PeerUnavailableException { public Request createKeetpaliveMessageRequest(ParentPlatform parentPlatform, String content, String viaTag, String fromTag, String toTag, CallIdHeader callIdHeader) throws ParseException, InvalidArgumentException, PeerUnavailableException {
Request request = null; Request request = null;
@ -57,7 +61,7 @@ public class SIPRequestHeaderPlarformProvider {
// Forwards // Forwards
MaxForwardsHeader maxForwards = sipFactory.createHeaderFactory().createMaxForwardsHeader(70); MaxForwardsHeader maxForwards = sipFactory.createHeaderFactory().createMaxForwardsHeader(70);
// ceq // ceq
CSeqHeader cSeqHeader = sipFactory.createHeaderFactory().createCSeqHeader(1L, Request.MESSAGE); CSeqHeader cSeqHeader = sipFactory.createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(Request.MESSAGE), Request.MESSAGE);
request = sipFactory.createMessageFactory().createRequest(requestURI, Request.MESSAGE, callIdHeader, cSeqHeader, fromHeader, request = sipFactory.createMessageFactory().createRequest(requestURI, Request.MESSAGE, callIdHeader, cSeqHeader, fromHeader,
toHeader, viaHeaders, maxForwards); toHeader, viaHeaders, maxForwards);
@ -122,7 +126,7 @@ public class SIPRequestHeaderPlarformProvider {
String callId, WWWAuthenticateHeader www , CallIdHeader callIdHeader) throws ParseException, PeerUnavailableException, InvalidArgumentException { String callId, WWWAuthenticateHeader www , CallIdHeader callIdHeader) throws ParseException, PeerUnavailableException, InvalidArgumentException {
Request registerRequest = createRegisterRequest(parentPlatform, 2L, fromTag, viaTag, callIdHeader); Request registerRequest = createRegisterRequest(parentPlatform, redisCatchStorage.getCSEQ(Request.REGISTER), fromTag, viaTag, callIdHeader);
String realm = www.getRealm(); String realm = www.getRealm();
String nonce = www.getNonce(); String nonce = www.getNonce();
@ -208,7 +212,7 @@ public class SIPRequestHeaderPlarformProvider {
// Forwards // Forwards
MaxForwardsHeader maxForwards = sipFactory.createHeaderFactory().createMaxForwardsHeader(70); MaxForwardsHeader maxForwards = sipFactory.createHeaderFactory().createMaxForwardsHeader(70);
// ceq // ceq
CSeqHeader cSeqHeader = sipFactory.createHeaderFactory().createCSeqHeader(1L, Request.MESSAGE); CSeqHeader cSeqHeader = sipFactory.createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(Request.MESSAGE), Request.MESSAGE);
MessageFactoryImpl messageFactory = (MessageFactoryImpl) sipFactory.createMessageFactory(); MessageFactoryImpl messageFactory = (MessageFactoryImpl) sipFactory.createMessageFactory();
// 设置编码, 防止中文乱码 // 设置编码, 防止中文乱码
messageFactory.setDefaultContentEncodingCharset("gb2312"); messageFactory.setDefaultContentEncodingCharset("gb2312");
@ -223,4 +227,43 @@ public class SIPRequestHeaderPlarformProvider {
request.setContent(content, contentTypeHeader); request.setContent(content, contentTypeHeader);
return request; return request;
} }
public Request createNotifyRequest(ParentPlatform parentPlatform, String content, String fromTag, String toTag, CallIdHeader callIdHeader) throws PeerUnavailableException, ParseException, InvalidArgumentException {
Request request = null;
// sipuri
SipURI requestURI = sipFactory.createAddressFactory().createSipURI(parentPlatform.getServerGBId(), parentPlatform.getServerIP()+ ":" + parentPlatform.getServerPort());
// via
ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();
ViaHeader viaHeader = sipFactory.createHeaderFactory().createViaHeader(parentPlatform.getDeviceIp(), Integer.parseInt(parentPlatform.getDevicePort()),
parentPlatform.getTransport(), null);
viaHeader.setRPort();
viaHeaders.add(viaHeader);
// from
SipURI fromSipURI = sipFactory.createAddressFactory().createSipURI(parentPlatform.getDeviceGBId(),
parentPlatform.getDeviceIp() + ":" + parentPlatform.getDevicePort());
Address fromAddress = sipFactory.createAddressFactory().createAddress(fromSipURI);
FromHeader fromHeader = sipFactory.createHeaderFactory().createFromHeader(fromAddress, fromTag);
// to
SipURI toSipURI = sipFactory.createAddressFactory().createSipURI(parentPlatform.getServerGBId(), parentPlatform.getServerGBDomain());
Address toAddress = sipFactory.createAddressFactory().createAddress(toSipURI);
ToHeader toHeader = sipFactory.createHeaderFactory().createToHeader(toAddress, toTag);
// Forwards
MaxForwardsHeader maxForwards = sipFactory.createHeaderFactory().createMaxForwardsHeader(70);
// ceq
CSeqHeader cSeqHeader = sipFactory.createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(Request.NOTIFY), Request.NOTIFY);
MessageFactoryImpl messageFactory = (MessageFactoryImpl) sipFactory.createMessageFactory();
// 设置编码, 防止中文乱码
messageFactory.setDefaultContentEncodingCharset("gb2312");
request = messageFactory.createRequest(requestURI, Request.NOTIFY, callIdHeader, cSeqHeader, fromHeader,
toHeader, viaHeaders, maxForwards);
List<String> agentParam = new ArrayList<>();
agentParam.add("wvp-pro");
UserAgentHeader userAgentHeader = sipFactory.createHeaderFactory().createUserAgentHeader(agentParam);
request.addHeader(userAgentHeader);
ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader("APPLICATION", "MANSCDP+xml");
request.setContent(content, contentTypeHeader);
return request;
}
} }

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

@ -1498,7 +1498,10 @@ public class SIPCommander implements ISIPCommander {
CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId() CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
: udpSipProvider.getNewCallId(); : udpSipProvider.getNewCallId();
Request request = headerProvider.createSubscribeRequest(device, cmdXml.toString(), "z9hG4bK-viaPos-" + tm, "fromTagPos" + tm, null, device.getSubscribeCycleForCatalog(), "Catalog" , callIdHeader); // 有效时间默认为60秒以上
Request request = headerProvider.createSubscribeRequest(device, cmdXml.toString(), "z9hG4bK-viaPos-" + tm,
"fromTagPos" + tm, null, device.getSubscribeCycleForCatalog() + 60, "Catalog" ,
callIdHeader);
transmitRequest(device, request, errorEvent, okEvent); transmitRequest(device, request, errorEvent, okEvent);
return true; return true;
@ -1509,6 +1512,34 @@ public class SIPCommander implements ISIPCommander {
} }
} }
@Override
public boolean dragZoomCmd(Device device, String channelId, String cmdString) {
try {
StringBuffer dragXml = new StringBuffer(200);
dragXml.append("<?xml version=\"1.0\" ?>\r\n");
dragXml.append("<Control>\r\n");
dragXml.append("<CmdType>DeviceControl</CmdType>\r\n");
dragXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");
if (StringUtils.isEmpty(channelId)) {
dragXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
} else {
dragXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
}
dragXml.append(cmdString);
dragXml.append("</Control>\r\n");
String tm = Long.toString(System.currentTimeMillis());
CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
: udpSipProvider.getNewCallId();
Request request = headerProvider.createMessageRequest(device, dragXml.toString(), "z9hG4bK-ViaPtz-" + tm, "FromPtz" + tm, null, callIdHeader);
logger.debug("拉框信令: " + request.toString());
transmitRequest(device, request);
return true;
} catch (SipException | ParseException | InvalidArgumentException e) {
e.printStackTrace();
}
return false;
}
private ClientTransaction transmitRequest(Device device, Request request) throws SipException { private ClientTransaction transmitRequest(Device device, Request request) throws SipException {
return transmitRequest(device, request, null, null); return transmitRequest(device, request, null, null);

153
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java

@ -3,9 +3,11 @@ package com.genersoft.iot.vmp.gb28181.transmit.cmd.impl;
import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatformCatch; import com.genersoft.iot.vmp.gb28181.bean.ParentPlatformCatch;
import com.genersoft.iot.vmp.gb28181.bean.SubscribeInfo;
import com.genersoft.iot.vmp.gb28181.event.SipSubscribe; import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform; import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.SIPRequestHeaderPlarformProvider; import com.genersoft.iot.vmp.gb28181.transmit.cmd.SIPRequestHeaderPlarformProvider;
import com.genersoft.iot.vmp.service.bean.GPSMsgInfo;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage; import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -21,6 +23,7 @@ import javax.sip.header.CallIdHeader;
import javax.sip.header.WWWAuthenticateHeader; import javax.sip.header.WWWAuthenticateHeader;
import javax.sip.message.Request; import javax.sip.message.Request;
import java.text.ParseException; import java.text.ParseException;
import java.util.List;
import java.util.UUID; import java.util.UUID;
@Component @Component
@ -92,9 +95,10 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform {
callIdHeader = udpSipProvider.getNewCallId(); callIdHeader = udpSipProvider.getNewCallId();
} }
request = headerProviderPlarformProvider.createRegisterRequest(parentPlatform, 1L, "FromRegister" + tm, null, callIdHeader); request = headerProviderPlarformProvider.createRegisterRequest(parentPlatform, redisCatchStorage.getCSEQ(Request.REGISTER), "FromRegister" + tm, null, callIdHeader);
// 将 callid 写入缓存, 等注册成功可以更新状态 // 将 callid 写入缓存, 等注册成功可以更新状态
redisCatchStorage.updatePlatformRegisterInfo(callIdHeader.getCallId(), parentPlatform.getServerGBId()); String callIdFromHeader = callIdHeader.getCallId();
redisCatchStorage.updatePlatformRegisterInfo(callIdFromHeader, parentPlatform.getServerGBId());
sipSubscribe.addErrorSubscribe(callIdHeader.getCallId(), (event)->{ sipSubscribe.addErrorSubscribe(callIdHeader.getCallId(), (event)->{
if (event != null) { if (event != null) {
@ -102,6 +106,7 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform {
parentPlatform.getServerGBId(), parentPlatform.getServerGBId(),
event.msg); event.msg);
} }
redisCatchStorage.delPlatformRegisterInfo(callIdFromHeader);
if (errorEvent != null ) { if (errorEvent != null ) {
errorEvent.response(event); errorEvent.response(event);
} }
@ -217,8 +222,8 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform {
catalogXml.append("<Owner>" + channel.getOwner() + "</Owner>\r\n"); catalogXml.append("<Owner>" + channel.getOwner() + "</Owner>\r\n");
catalogXml.append("<CivilCode>" + channel.getCivilCode() + "</CivilCode>\r\n"); catalogXml.append("<CivilCode>" + channel.getCivilCode() + "</CivilCode>\r\n");
catalogXml.append("<Address>" + channel.getAddress() + "</Address>\r\n"); catalogXml.append("<Address>" + channel.getAddress() + "</Address>\r\n");
catalogXml.append("<Parental>" + channel.getParental() + "</Parental>\r\n");// TODO 当前不能添加分组, 所以暂时没有父节点 catalogXml.append("<Parental>" + channel.getParental() + "</Parental>\r\n");
catalogXml.append("<ParentID>" + channel.getParentId() + "</ParentID>\r\n"); // TODO 当前不能添加分组, 所以暂时没有父节点 catalogXml.append("<ParentID>" + channel.getParentId() + "</ParentID>\r\n");
catalogXml.append("<Secrecy>" + channel.getSecrecy() + "</Secrecy>\r\n"); catalogXml.append("<Secrecy>" + channel.getSecrecy() + "</Secrecy>\r\n");
catalogXml.append("<RegisterWay>" + channel.getRegisterWay() + "</RegisterWay>\r\n"); catalogXml.append("<RegisterWay>" + channel.getRegisterWay() + "</RegisterWay>\r\n");
catalogXml.append("<Status>" + (channel.getStatus() == 0?"OFF":"ON") + "</Status>\r\n"); catalogXml.append("<Status>" + (channel.getStatus() == 0?"OFF":"ON") + "</Status>\r\n");
@ -325,4 +330,144 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform {
} }
return true; return true;
} }
@Override
public boolean sendNotifyMobilePosition(ParentPlatform parentPlatform, GPSMsgInfo gpsMsgInfo, SubscribeInfo subscribeInfo) {
if (parentPlatform == null) {
return false;
}
try {
StringBuffer deviceStatusXml = new StringBuffer(600);
deviceStatusXml.append("<?xml version=\"1.0\" encoding=\"GB2312\"?>\r\n");
deviceStatusXml.append("<Notify>\r\n");
deviceStatusXml.append("<CmdType>MobilePosition</CmdType>\r\n");
deviceStatusXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
deviceStatusXml.append("<DeviceID>" + gpsMsgInfo.getId() + "</DeviceID>\r\n");
deviceStatusXml.append("<Time>" + gpsMsgInfo.getTime() + "</Time>\r\n");
deviceStatusXml.append("<Longitude>" + gpsMsgInfo.getLng() + "</Longitude>\r\n");
deviceStatusXml.append("<Latitude>" + gpsMsgInfo.getLat() + "</Latitude>\r\n");
deviceStatusXml.append("<Speed>" + gpsMsgInfo.getSpeed() + "</Speed>\r\n");
deviceStatusXml.append("<Direction>" + gpsMsgInfo.getDirection() + "</Direction>\r\n");
deviceStatusXml.append("<Altitude>" + gpsMsgInfo.getAltitude() + "</Altitude>\r\n");
deviceStatusXml.append("</Notify>\r\n");
CallIdHeader callIdHeader = parentPlatform.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
: udpSipProvider.getNewCallId();
callIdHeader.setCallId(subscribeInfo.getCallId());
String tm = Long.toString(System.currentTimeMillis());
Request request = headerProviderPlarformProvider.createNotifyRequest(parentPlatform, deviceStatusXml.toString(), subscribeInfo.getToTag(), subscribeInfo.getFromTag(), callIdHeader);
transmitRequest(parentPlatform, request);
} catch (SipException | ParseException | InvalidArgumentException e) {
e.printStackTrace();
return false;
}
return true;
}
@Override
public boolean sendNotifyForCatalogAddOrUpdate(String type, ParentPlatform parentPlatform, List<DeviceChannel> deviceChannels, SubscribeInfo subscribeInfo) {
if (parentPlatform == null || deviceChannels == null || deviceChannels.size() == 0 || subscribeInfo == null) {
return false;
}
for (DeviceChannel channel : deviceChannels) {
try {
StringBuffer catalogXml = new StringBuffer(600);
catalogXml.append("<?xml version=\"1.0\" encoding=\"GB2312\"?>\r\n");
catalogXml.append("<Notify>\r\n");
catalogXml.append("<CmdType>Catalog</CmdType>\r\n");
catalogXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");
catalogXml.append("<SumNum>" + deviceChannels.size() + "</SumNum>\r\n");
catalogXml.append("<DeviceList Num=\"1\">\r\n");
catalogXml.append("<Item>\r\n");
catalogXml.append("<DeviceID>" + channel.getChannelId() + "</DeviceID>\r\n");
catalogXml.append("<Event>" + type + "</Event>\r\n");
catalogXml.append("<Name>" + channel.getName() + "</Name>\r\n");
catalogXml.append("<Manufacturer>" + channel.getManufacture() + "</Manufacturer>\r\n");
catalogXml.append("<Model>" + channel.getModel() + "</Model>\r\n");
catalogXml.append("<Owner>" + channel.getOwner() + "</Owner>\r\n");
catalogXml.append("<CivilCode>" + channel.getCivilCode() + "</CivilCode>\r\n");
catalogXml.append("<Address>" + channel.getAddress() + "</Address>\r\n");
catalogXml.append("<Parental>" + channel.getParental() + "</Parental>\r\n");
catalogXml.append("<ParentID>" + channel.getParentId() + "</ParentID>\r\n");
catalogXml.append("<Secrecy>" + channel.getSecrecy() + "</Secrecy>\r\n");
catalogXml.append("<RegisterWay>" + channel.getRegisterWay() + "</RegisterWay>\r\n");
catalogXml.append("<Status>" + (channel.getStatus() == 0 ? "OFF" : "ON") + "</Status>\r\n");
catalogXml.append("<Longitude>" + channel.getLongitude() + "</Longitude>\r\n");
catalogXml.append("<Latitude>" + channel.getLatitude() + "</Latitude>\r\n");
catalogXml.append("<IPAddress>" + channel.getIpAddress() + "</IPAddress>\r\n");
catalogXml.append("<Port>" + channel.getPort() + "</Port>\r\n");
catalogXml.append("<Info>\r\n");
catalogXml.append("<PTZType>" + channel.getPTZType() + "</PTZType>\r\n");
catalogXml.append("</Info>\r\n");
catalogXml.append("</Item>\r\n");
catalogXml.append("</DeviceList>\r\n");
catalogXml.append("</Notify>\r\n");
CallIdHeader callIdHeader = parentPlatform.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
: udpSipProvider.getNewCallId();
callIdHeader.setCallId(subscribeInfo.getCallId());
String tm = Long.toString(System.currentTimeMillis());
Request request = headerProviderPlarformProvider.createNotifyRequest(parentPlatform, catalogXml.toString(), subscribeInfo.getToTag(), subscribeInfo.getFromTag(), callIdHeader);
transmitRequest(parentPlatform, request);
Thread.sleep(100);
} catch (SipException | ParseException | InvalidArgumentException e) {
e.printStackTrace();
return false;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return true;
}
@Override
public boolean sendNotifyForCatalogOther(String type, ParentPlatform parentPlatform, List<DeviceChannel> deviceChannels, SubscribeInfo subscribeInfo) {
if (parentPlatform == null
|| deviceChannels == null
|| deviceChannels.size() == 0
|| subscribeInfo == null) {
return false;
}
for (DeviceChannel channel : deviceChannels) {
try {
StringBuffer catalogXml = new StringBuffer(600);
catalogXml.append("<?xml version=\"1.0\" encoding=\"GB2312\"?>\r\n");
catalogXml.append("<Notify>\r\n");
catalogXml.append("<CmdType>Catalog</CmdType>\r\n");
catalogXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");
catalogXml.append("<SumNum>" + deviceChannels.size() + "</SumNum>\r\n");
catalogXml.append("<DeviceList Num=\"1\">\r\n");
catalogXml.append("<Item>\r\n");
catalogXml.append("<DeviceID>" + channel.getChannelId() + "</DeviceID>\r\n");
catalogXml.append("<Event>" + type + "</Event>\r\n");
catalogXml.append("</Item>\r\n");
catalogXml.append("</DeviceList>\r\n");
catalogXml.append("</Notify>\r\n");
CallIdHeader callIdHeader = parentPlatform.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
: udpSipProvider.getNewCallId();
callIdHeader.setCallId(subscribeInfo.getCallId());
String tm = Long.toString(System.currentTimeMillis());
Request request = headerProviderPlarformProvider.createNotifyRequest(parentPlatform, catalogXml.toString(), subscribeInfo.getToTag(), subscribeInfo.getFromTag(), callIdHeader);
transmitRequest(parentPlatform, request);
Thread.sleep(100);
} catch (SipException | ParseException | InvalidArgumentException e) {
e.printStackTrace();
return false;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return true;
}
} }

28
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/SIPRequestProcessorParent.java

@ -18,6 +18,7 @@ import javax.sip.address.Address;
import javax.sip.address.AddressFactory; import javax.sip.address.AddressFactory;
import javax.sip.address.SipURI; import javax.sip.address.SipURI;
import javax.sip.header.ContentTypeHeader; import javax.sip.header.ContentTypeHeader;
import javax.sip.header.ExpiresHeader;
import javax.sip.header.HeaderFactory; import javax.sip.header.HeaderFactory;
import javax.sip.header.ViaHeader; import javax.sip.header.ViaHeader;
import javax.sip.message.MessageFactory; import javax.sip.message.MessageFactory;
@ -153,7 +154,7 @@ public abstract class SIPRequestProcessorParent {
* @throws InvalidArgumentException * @throws InvalidArgumentException
* @throws ParseException * @throws ParseException
*/ */
public void responseAck(RequestEvent evt, String sdp) throws SipException, InvalidArgumentException, ParseException { public void responseSdpAck(RequestEvent evt, String sdp) throws SipException, InvalidArgumentException, ParseException {
Response response = getMessageFactory().createResponse(Response.OK, evt.getRequest()); Response response = getMessageFactory().createResponse(Response.OK, evt.getRequest());
SipFactory sipFactory = SipFactory.getInstance(); SipFactory sipFactory = SipFactory.getInstance();
ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader("APPLICATION", "SDP"); ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader("APPLICATION", "SDP");
@ -168,6 +169,31 @@ public abstract class SIPRequestProcessorParent {
getServerTransaction(evt).sendResponse(response); getServerTransaction(evt).sendResponse(response);
} }
/**
* 回复带xml的200
* @param evt
* @param xml
* @throws SipException
* @throws InvalidArgumentException
* @throws ParseException
*/
public Response responseXmlAck(RequestEvent evt, String xml) throws SipException, InvalidArgumentException, ParseException {
Response response = getMessageFactory().createResponse(Response.OK, evt.getRequest());
SipFactory sipFactory = SipFactory.getInstance();
ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader("APPLICATION", "MANSCDP+xml");
response.setContent(xml, contentTypeHeader);
SipURI sipURI = (SipURI)evt.getRequest().getRequestURI();
Address concatAddress = sipFactory.createAddressFactory().createAddress(
sipFactory.createAddressFactory().createSipURI(sipURI.getUser(), sipURI.getHost()+":"+sipURI.getPort()
));
response.addHeader(sipFactory.createHeaderFactory().createContactHeader(concatAddress));
response.addHeader(evt.getRequest().getHeader(ExpiresHeader.NAME));
getServerTransaction(evt).sendResponse(response);
return response;
}
public Element getRootElement(RequestEvent evt) throws DocumentException { public Element getRootElement(RequestEvent evt) throws DocumentException {
return getRootElement(evt, "gb2312"); return getRootElement(evt, "gb2312");
} }

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

@ -106,8 +106,8 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
if (platform != null) { if (platform != null) {
// 查询平台下是否有该通道 // 查询平台下是否有该通道
DeviceChannel channel = storager.queryChannelInParentPlatform(requesterId, channelId); DeviceChannel channel = storager.queryChannelInParentPlatform(requesterId, channelId);
List<GbStream> gbStreams = storager.queryStreamInParentPlatform(requesterId, channelId); GbStream gbStream = storager.queryStreamInParentPlatform(requesterId, channelId);
GbStream gbStream = gbStreams.size() > 0? gbStreams.get(0):null; PlatformCatalog catalog = storager.getCatalog(channelId);
MediaServerItem mediaServerItem = null; MediaServerItem mediaServerItem = null;
// 不是通道可能是直播流 // 不是通道可能是直播流
if (channel != null && gbStream == null ) { if (channel != null && gbStream == null ) {
@ -132,7 +132,10 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
return; return;
} }
responseAck(evt, Response.CALL_IS_BEING_FORWARDED); // 通道存在,发181,呼叫转接中 responseAck(evt, Response.CALL_IS_BEING_FORWARDED); // 通道存在,发181,呼叫转接中
}else { }else if (catalog != null) {
responseAck(evt, Response.BAD_REQUEST, "catalog channel can not play"); // 目录不支持点播
return;
} else {
logger.info("通道不存在,返回404"); logger.info("通道不存在,返回404");
responseAck(evt, Response.NOT_FOUND); // 通道不存在,发404,资源不存在 responseAck(evt, Response.NOT_FOUND); // 通道不存在,发404,资源不存在
return; return;
@ -249,7 +252,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
content.append("f=\r\n"); content.append("f=\r\n");
try { try {
responseAck(evt, content.toString()); responseSdpAck(evt, content.toString());
} catch (SipException e) { } catch (SipException e) {
e.printStackTrace(); e.printStackTrace();
} catch (InvalidArgumentException e) { } catch (InvalidArgumentException e) {
@ -306,7 +309,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
content.append("f=\r\n"); content.append("f=\r\n");
try { try {
responseAck(evt, content.toString()); responseSdpAck(evt, content.toString());
} catch (SipException e) { } catch (SipException e) {
e.printStackTrace(); e.printStackTrace();
} catch (InvalidArgumentException e) { } catch (InvalidArgumentException e) {

121
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/NotifyRequestProcessor.java

@ -6,6 +6,7 @@ import com.genersoft.iot.vmp.conf.UserSetup;
import com.genersoft.iot.vmp.gb28181.bean.*; import com.genersoft.iot.vmp.gb28181.bean.*;
import com.genersoft.iot.vmp.gb28181.event.DeviceOffLineDetector; import com.genersoft.iot.vmp.gb28181.event.DeviceOffLineDetector;
import com.genersoft.iot.vmp.gb28181.event.EventPublisher; import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent;
import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver; import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver;
import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
@ -50,6 +51,9 @@ public class NotifyRequestProcessor extends SIPRequestProcessorParent implements
@Autowired @Autowired
private IVideoManagerStorager storager; private IVideoManagerStorager storager;
@Autowired
private EventPublisher eventPublisher;
@Autowired @Autowired
private SipConfig sipConfig; private SipConfig sipConfig;
@ -62,9 +66,7 @@ public class NotifyRequestProcessor extends SIPRequestProcessorParent implements
@Autowired @Autowired
private DeviceOffLineDetector offLineDetector; private DeviceOffLineDetector offLineDetector;
private static final String NOTIFY_CATALOG = "Catalog";
private static final String NOTIFY_ALARM = "Alarm";
private static final String NOTIFY_MOBILE_POSITION = "MobilePosition";
private String method = "NOTIFY"; private String method = "NOTIFY";
@Autowired @Autowired
@ -82,13 +84,13 @@ public class NotifyRequestProcessor extends SIPRequestProcessorParent implements
Element rootElement = getRootElement(evt); Element rootElement = getRootElement(evt);
String cmd = XmlUtil.getText(rootElement, "CmdType"); String cmd = XmlUtil.getText(rootElement, "CmdType");
if (NOTIFY_CATALOG.equals(cmd)) { if (CmdType.CATALOG.equals(cmd)) {
logger.info("接收到Catalog通知"); logger.info("接收到Catalog通知");
processNotifyCatalogList(evt); processNotifyCatalogList(evt);
} else if (NOTIFY_ALARM.equals(cmd)) { } else if (CmdType.ALARM.equals(cmd)) {
logger.info("接收到Alarm通知"); logger.info("接收到Alarm通知");
processNotifyAlarm(evt); processNotifyAlarm(evt);
} else if (NOTIFY_MOBILE_POSITION.equals(cmd)) { } else if (CmdType.MOBILE_POSITION.equals(cmd)) {
logger.info("接收到MobilePosition通知"); logger.info("接收到MobilePosition通知");
processNotifyMobilePosition(evt); processNotifyMobilePosition(evt);
} else { } else {
@ -257,41 +259,43 @@ public class NotifyRequestProcessor extends SIPRequestProcessorParent implements
continue; continue;
} }
Element eventElement = itemDevice.element("Event"); Element eventElement = itemDevice.element("Event");
DeviceChannel channel = channelContentHander(itemDevice); DeviceChannel channel = XmlUtil.channelContentHander(itemDevice);
channel.setDeviceId(device.getDeviceId());
logger.debug("收到来自设备【{}】的通道: {}【{}】", device.getDeviceId(), channel.getName(), channel.getChannelId());
switch (eventElement.getText().toUpperCase()) { switch (eventElement.getText().toUpperCase()) {
case "ON" : // 上线 case CatalogEvent.ON: // 上线
logger.info("收到来自设备【{}】的通道【{}】上线通知", device.getDeviceId(), channel.getChannelId()); logger.info("收到来自设备【{}】的通道【{}】上线通知", device.getDeviceId(), channel.getChannelId());
storager.deviceChannelOnline(deviceId, channel.getChannelId()); storager.deviceChannelOnline(deviceId, channel.getChannelId());
// 回复200 OK // 回复200 OK
responseAck(evt, Response.OK); responseAck(evt, Response.OK);
break; break;
case "OFF" : // 离线 case CatalogEvent.OFF : // 离线
logger.info("收到来自设备【{}】的通道【{}】离线通知", device.getDeviceId(), channel.getChannelId()); logger.info("收到来自设备【{}】的通道【{}】离线通知", device.getDeviceId(), channel.getChannelId());
storager.deviceChannelOffline(deviceId, channel.getChannelId()); storager.deviceChannelOffline(deviceId, channel.getChannelId());
// 回复200 OK // 回复200 OK
responseAck(evt, Response.OK); responseAck(evt, Response.OK);
break; break;
case "VLOST" : // 视频丢失 case CatalogEvent.VLOST: // 视频丢失
logger.info("收到来自设备【{}】的通道【{}】视频丢失通知", device.getDeviceId(), channel.getChannelId()); logger.info("收到来自设备【{}】的通道【{}】视频丢失通知", device.getDeviceId(), channel.getChannelId());
storager.deviceChannelOffline(deviceId, channel.getChannelId()); storager.deviceChannelOffline(deviceId, channel.getChannelId());
// 回复200 OK // 回复200 OK
responseAck(evt, Response.OK); responseAck(evt, Response.OK);
break; break;
case "DEFECT" : // 故障 case CatalogEvent.DEFECT: // 故障
// 回复200 OK // 回复200 OK
responseAck(evt, Response.OK); responseAck(evt, Response.OK);
break; break;
case "ADD" : // 增加 case CatalogEvent.ADD: // 增加
logger.info("收到来自设备【{}】的增加通道【{}】通知", device.getDeviceId(), channel.getChannelId()); logger.info("收到来自设备【{}】的增加通道【{}】通知", device.getDeviceId(), channel.getChannelId());
storager.updateChannel(deviceId, channel); storager.updateChannel(deviceId, channel);
responseAck(evt, Response.OK); responseAck(evt, Response.OK);
break; break;
case "DEL" : // 删除 case CatalogEvent.DEL: // 删除
logger.info("收到来自设备【{}】的删除通道【{}】通知", device.getDeviceId(), channel.getChannelId()); logger.info("收到来自设备【{}】的删除通道【{}】通知", device.getDeviceId(), channel.getChannelId());
storager.delChannel(deviceId, channel.getChannelId()); storager.delChannel(deviceId, channel.getChannelId());
responseAck(evt, Response.OK); responseAck(evt, Response.OK);
break; break;
case "UPDATE" : // 更新 case CatalogEvent.UPDATE: // 更新
logger.info("收到来自设备【{}】的更新通道【{}】通知", device.getDeviceId(), channel.getChannelId()); logger.info("收到来自设备【{}】的更新通道【{}】通知", device.getDeviceId(), channel.getChannelId());
storager.updateChannel(deviceId, channel); storager.updateChannel(deviceId, channel);
responseAck(evt, Response.OK); responseAck(evt, Response.OK);
@ -300,6 +304,8 @@ public class NotifyRequestProcessor extends SIPRequestProcessorParent implements
responseAck(evt, Response.BAD_REQUEST, "event not found"); responseAck(evt, Response.BAD_REQUEST, "event not found");
} }
// 转发变化信息
eventPublisher.catalogEventPublish(null, channel, eventElement.getText().toUpperCase());
} }
@ -318,93 +324,6 @@ public class NotifyRequestProcessor extends SIPRequestProcessorParent implements
} }
} }
public DeviceChannel channelContentHander(Element itemDevice){
Element channdelNameElement = itemDevice.element("Name");
String channelName = channdelNameElement != null ? channdelNameElement.getTextTrim().toString() : "";
Element statusElement = itemDevice.element("Status");
String status = statusElement != null ? statusElement.getTextTrim().toString() : "ON";
DeviceChannel deviceChannel = new DeviceChannel();
deviceChannel.setName(channelName);
Element channdelIdElement = itemDevice.element("DeviceID");
String channelId = channdelIdElement != null ? channdelIdElement.getTextTrim().toString() : "";
deviceChannel.setChannelId(channelId);
// ONLINE OFFLINE HIKVISION DS-7716N-E4 NVR的兼容性处理
if (status.equals("ON") || status.equals("On") || status.equals("ONLINE")) {
deviceChannel.setStatus(1);
}
if (status.equals("OFF") || status.equals("Off") || status.equals("OFFLINE")) {
deviceChannel.setStatus(0);
}
deviceChannel.setManufacture(XmlUtil.getText(itemDevice, "Manufacturer"));
deviceChannel.setModel(XmlUtil.getText(itemDevice, "Model"));
deviceChannel.setOwner(XmlUtil.getText(itemDevice, "Owner"));
deviceChannel.setCivilCode(XmlUtil.getText(itemDevice, "CivilCode"));
deviceChannel.setBlock(XmlUtil.getText(itemDevice, "Block"));
deviceChannel.setAddress(XmlUtil.getText(itemDevice, "Address"));
if (XmlUtil.getText(itemDevice, "Parental") == null
|| XmlUtil.getText(itemDevice, "Parental") == "") {
deviceChannel.setParental(0);
} else {
deviceChannel.setParental(Integer.parseInt(XmlUtil.getText(itemDevice, "Parental")));
}
deviceChannel.setParentId(XmlUtil.getText(itemDevice, "ParentID"));
if (XmlUtil.getText(itemDevice, "SafetyWay") == null
|| XmlUtil.getText(itemDevice, "SafetyWay") == "") {
deviceChannel.setSafetyWay(0);
} else {
deviceChannel.setSafetyWay(Integer.parseInt(XmlUtil.getText(itemDevice, "SafetyWay")));
}
if (XmlUtil.getText(itemDevice, "RegisterWay") == null
|| XmlUtil.getText(itemDevice, "RegisterWay") == "") {
deviceChannel.setRegisterWay(1);
} else {
deviceChannel.setRegisterWay(Integer.parseInt(XmlUtil.getText(itemDevice, "RegisterWay")));
}
deviceChannel.setCertNum(XmlUtil.getText(itemDevice, "CertNum"));
if (XmlUtil.getText(itemDevice, "Certifiable") == null
|| XmlUtil.getText(itemDevice, "Certifiable") == "") {
deviceChannel.setCertifiable(0);
} else {
deviceChannel.setCertifiable(Integer.parseInt(XmlUtil.getText(itemDevice, "Certifiable")));
}
if (XmlUtil.getText(itemDevice, "ErrCode") == null
|| XmlUtil.getText(itemDevice, "ErrCode") == "") {
deviceChannel.setErrCode(0);
} else {
deviceChannel.setErrCode(Integer.parseInt(XmlUtil.getText(itemDevice, "ErrCode")));
}
deviceChannel.setEndTime(XmlUtil.getText(itemDevice, "EndTime"));
deviceChannel.setSecrecy(XmlUtil.getText(itemDevice, "Secrecy"));
deviceChannel.setIpAddress(XmlUtil.getText(itemDevice, "IPAddress"));
if (XmlUtil.getText(itemDevice, "Port") == null || XmlUtil.getText(itemDevice, "Port") == "") {
deviceChannel.setPort(0);
} else {
deviceChannel.setPort(Integer.parseInt(XmlUtil.getText(itemDevice, "Port")));
}
deviceChannel.setPassword(XmlUtil.getText(itemDevice, "Password"));
if (NumericUtil.isDouble(XmlUtil.getText(itemDevice, "Longitude"))) {
deviceChannel.setLongitude(Double.parseDouble(XmlUtil.getText(itemDevice, "Longitude")));
} else {
deviceChannel.setLongitude(0.00);
}
if (NumericUtil.isDouble(XmlUtil.getText(itemDevice, "Latitude"))) {
deviceChannel.setLatitude(Double.parseDouble(XmlUtil.getText(itemDevice, "Latitude")));
} else {
deviceChannel.setLatitude(0.00);
}
if (XmlUtil.getText(itemDevice, "PTZType") == null
|| XmlUtil.getText(itemDevice, "PTZType") == "") {
deviceChannel.setPTZType(0);
} else {
deviceChannel.setPTZType(Integer.parseInt(XmlUtil.getText(itemDevice, "PTZType")));
}
deviceChannel.setHasAudio(true); // 默认含有音频,播放时再检查是否有音频及是否AAC
return deviceChannel;
}
public void setCmder(SIPCommander cmder) { public void setCmder(SIPCommander cmder) {
} }

9
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/RegisterRequestProcessor.java

@ -90,8 +90,13 @@ public class RegisterRequestProcessor extends SIPRequestProcessorParent implemen
AddressImpl address = (AddressImpl) fromHeader.getAddress(); AddressImpl address = (AddressImpl) fromHeader.getAddress();
SipUri uri = (SipUri) address.getURI(); SipUri uri = (SipUri) address.getURI();
String deviceId = uri.getUser(); String deviceId = uri.getUser();
Device device = redisCatchStorage.getDevice(deviceId); Device deviceInRedis = redisCatchStorage.getDevice(deviceId);
AuthorizationHeader authorhead = (AuthorizationHeader) request.getHeader(AuthorizationHeader.NAME); Device device = storager.queryVideoDevice(deviceId);
if (deviceInRedis != null && device == null) {
// redis 存在脏数据
redisCatchStorage.clearCatchByDeviceId(deviceId);
}
AuthorizationHeader authorhead = (AuthorizationHeader) request.getHeader(AuthorizationHeader.NAME);
// 校验密码是否正确 // 校验密码是否正确
if (authorhead != null) { if (authorhead != null) {
passwordCorrect = new DigestServerAuthenticationHelper().doAuthenticatePlainTextPassword(request, passwordCorrect = new DigestServerAuthenticationHelper().doAuthenticatePlainTextPassword(request,

166
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/SubscribeRequestProcessor.java

@ -1,8 +1,21 @@
package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl; package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl;
import com.genersoft.iot.vmp.common.VideoManagerConstants;
import com.genersoft.iot.vmp.conf.DynamicTask;
import com.genersoft.iot.vmp.conf.UserSetup;
import com.genersoft.iot.vmp.gb28181.bean.CmdType;
import com.genersoft.iot.vmp.gb28181.bean.SubscribeInfo;
import com.genersoft.iot.vmp.gb28181.task.GPSSubscribeTask;
import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver; import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.ISIPRequestProcessor; import com.genersoft.iot.vmp.gb28181.transmit.event.request.ISIPRequestProcessor;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent; import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
import com.genersoft.iot.vmp.gb28181.utils.SipUtils;
import com.genersoft.iot.vmp.gb28181.utils.XmlUtil;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.InitializingBean;
@ -13,7 +26,10 @@ import javax.sip.InvalidArgumentException;
import javax.sip.RequestEvent; import javax.sip.RequestEvent;
import javax.sip.ServerTransaction; import javax.sip.ServerTransaction;
import javax.sip.SipException; import javax.sip.SipException;
import javax.sip.header.CallIdHeader;
import javax.sip.header.ExpiresHeader; import javax.sip.header.ExpiresHeader;
import javax.sip.header.Header;
import javax.sip.header.ToHeader;
import javax.sip.message.Request; import javax.sip.message.Request;
import javax.sip.message.Response; import javax.sip.message.Response;
import java.text.ParseException; import java.text.ParseException;
@ -30,6 +46,21 @@ public class SubscribeRequestProcessor extends SIPRequestProcessorParent impleme
@Autowired @Autowired
private SIPProcessorObserver sipProcessorObserver; private SIPProcessorObserver sipProcessorObserver;
@Autowired
private IRedisCatchStorage redisCatchStorage;
@Autowired
private ISIPCommanderForPlatform sipCommanderForPlatform;
@Autowired
private IVideoManagerStorager storager;
@Autowired
private DynamicTask dynamicTask;
@Autowired
private UserSetup userSetup;
@Override @Override
public void afterPropertiesSet() throws Exception { public void afterPropertiesSet() throws Exception {
// 添加消息处理的订阅 // 添加消息处理的订阅
@ -46,30 +77,137 @@ public class SubscribeRequestProcessor extends SIPRequestProcessorParent impleme
Request request = evt.getRequest(); Request request = evt.getRequest();
try { try {
Response response = null; Element rootElement = getRootElement(evt);
response = getMessageFactory().createResponse(200, request); String cmd = XmlUtil.getText(rootElement, "CmdType");
if (response != null) { if (CmdType.MOBILE_POSITION.equals(cmd)) {
ExpiresHeader expireHeader = getHeaderFactory().createExpiresHeader(30); processNotifyMobilePosition(evt, rootElement);
response.setExpires(expireHeader); // } else if (CmdType.ALARM.equals(cmd)) {
} // logger.info("接收到Alarm订阅");
logger.info("response : " + response.toString()); // processNotifyAlarm(evt, rootElement);
ServerTransaction transaction = getServerTransaction(evt); } else if (CmdType.CATALOG.equals(cmd)) {
if (transaction != null) { processNotifyCatalogList(evt, rootElement);
transaction.sendResponse(response);
transaction.getDialog().delete();
transaction.terminate();
} else { } else {
logger.info("processRequest serverTransactionId is null."); logger.info("接收到消息:" + cmd);
Response response = null;
response = getMessageFactory().createResponse(200, request);
if (response != null) {
ExpiresHeader expireHeader = getHeaderFactory().createExpiresHeader(30);
response.setExpires(expireHeader);
}
logger.info("response : " + response.toString());
ServerTransaction transaction = getServerTransaction(evt);
if (transaction != null) {
transaction.sendResponse(response);
transaction.getDialog().delete();
transaction.terminate();
} else {
logger.info("processRequest serverTransactionId is null.");
}
}
} catch (ParseException e) {
e.printStackTrace();
} catch (SipException e) {
e.printStackTrace();
} catch (InvalidArgumentException e) {
e.printStackTrace();
} catch (DocumentException e) {
e.printStackTrace();
}
}
/**
* 处理移动位置订阅消息
*/
private void processNotifyMobilePosition(RequestEvent evt, Element rootElement) {
String platformId = SipUtils.getUserIdFromFromHeader(evt.getRequest());
String deviceID = XmlUtil.getText(rootElement, "DeviceID");
SubscribeInfo subscribeInfo = new SubscribeInfo(evt, platformId);
String sn = XmlUtil.getText(rootElement, "SN");
String key = VideoManagerConstants.SIP_SUBSCRIBE_PREFIX + userSetup.getServerId() + "_MobilePosition_" + platformId;
logger.info("接收到{}的MobilePosition订阅", platformId);
StringBuilder resultXml = new StringBuilder(200);
resultXml.append("<?xml version=\"1.0\" ?>\r\n")
.append("<Response>\r\n")
.append("<CmdType>MobilePosition</CmdType>\r\n")
.append("<SN>" + sn + "</SN>\r\n")
.append("<DeviceID>" + deviceID + "</DeviceID>\r\n")
.append("<Result>OK</Result>\r\n")
.append("</Response>\r\n");
if (subscribeInfo.getExpires() > 0) {
if (redisCatchStorage.getSubscribe(key) != null) {
dynamicTask.stopCron(key);
} }
String interval = XmlUtil.getText(rootElement, "Interval"); // GPS上报时间间隔
dynamicTask.startCron(key, new GPSSubscribeTask(redisCatchStorage, sipCommanderForPlatform, storager, platformId, sn, key), Integer.parseInt(interval));
redisCatchStorage.updateSubscribe(key, subscribeInfo);
}else if (subscribeInfo.getExpires() == 0) {
dynamicTask.stopCron(key);
redisCatchStorage.delSubscribe(key);
}
try {
Response response = responseXmlAck(evt, resultXml.toString());
ToHeader toHeader = (ToHeader)response.getHeader(ToHeader.NAME);
subscribeInfo.setToTag(toHeader.getTag());
redisCatchStorage.updateSubscribe(key, subscribeInfo);
} catch (SipException e) {
e.printStackTrace();
} catch (InvalidArgumentException e) {
e.printStackTrace();
} catch (ParseException e) { } catch (ParseException e) {
e.printStackTrace(); e.printStackTrace();
}
}
private void processNotifyAlarm(RequestEvent evt, Element rootElement) {
}
private void processNotifyCatalogList(RequestEvent evt, Element rootElement) {
String platformId = SipUtils.getUserIdFromFromHeader(evt.getRequest());
String deviceID = XmlUtil.getText(rootElement, "DeviceID");
SubscribeInfo subscribeInfo = new SubscribeInfo(evt, platformId);
String sn = XmlUtil.getText(rootElement, "SN");
String key = VideoManagerConstants.SIP_SUBSCRIBE_PREFIX + userSetup.getServerId() + "_Catalog_" + platformId;
logger.info("接收到{}的Catalog订阅", platformId);
StringBuilder resultXml = new StringBuilder(200);
resultXml.append("<?xml version=\"1.0\" ?>\r\n")
.append("<Response>\r\n")
.append("<CmdType>Catalog</CmdType>\r\n")
.append("<SN>" + sn + "</SN>\r\n")
.append("<DeviceID>" + deviceID + "</DeviceID>\r\n")
.append("<Result>OK</Result>\r\n")
.append("</Response>\r\n");
if (subscribeInfo.getExpires() > 0) {
redisCatchStorage.updateSubscribe(key, subscribeInfo);
}else if (subscribeInfo.getExpires() == 0) {
redisCatchStorage.delSubscribe(key);
}
try {
Response response = responseXmlAck(evt, resultXml.toString());
ToHeader toHeader = (ToHeader)response.getHeader(ToHeader.NAME);
subscribeInfo.setToTag(toHeader.getTag());
redisCatchStorage.updateSubscribe(key, subscribeInfo);
} catch (SipException e) { } catch (SipException e) {
e.printStackTrace(); e.printStackTrace();
} catch (InvalidArgumentException e) { } catch (InvalidArgumentException e) {
e.printStackTrace(); e.printStackTrace();
} catch (ParseException e) {
e.printStackTrace();
} }
} }
} }

14
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/MessageRequestProcessor.java

@ -1,7 +1,9 @@
package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message; package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message;
import com.genersoft.iot.vmp.gb28181.bean.Device; import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.gb28181.bean.DeviceNotFoundEvent;
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver; import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.ISIPRequestProcessor; import com.genersoft.iot.vmp.gb28181.transmit.event.request.ISIPRequestProcessor;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent; import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
@ -19,6 +21,7 @@ import org.springframework.stereotype.Component;
import javax.sip.InvalidArgumentException; import javax.sip.InvalidArgumentException;
import javax.sip.RequestEvent; import javax.sip.RequestEvent;
import javax.sip.SipException; import javax.sip.SipException;
import javax.sip.header.CallIdHeader;
import javax.sip.message.Response; import javax.sip.message.Response;
import java.text.ParseException; import java.text.ParseException;
import java.util.Map; import java.util.Map;
@ -39,6 +42,9 @@ public class MessageRequestProcessor extends SIPRequestProcessorParent implement
@Autowired @Autowired
private IVideoManagerStorager storage; private IVideoManagerStorager storage;
@Autowired
private SipSubscribe sipSubscribe;
@Autowired @Autowired
private IRedisCatchStorage redisCatchStorage; private IRedisCatchStorage redisCatchStorage;
@ -56,6 +62,7 @@ public class MessageRequestProcessor extends SIPRequestProcessorParent implement
public void process(RequestEvent evt) { public void process(RequestEvent evt) {
logger.debug("接收到消息:" + evt.getRequest()); logger.debug("接收到消息:" + evt.getRequest());
String deviceId = SipUtils.getUserIdFromFromHeader(evt.getRequest()); String deviceId = SipUtils.getUserIdFromFromHeader(evt.getRequest());
CallIdHeader callIdHeader = (CallIdHeader)evt.getRequest().getHeader(CallIdHeader.NAME);
// 查询设备是否存在 // 查询设备是否存在
Device device = redisCatchStorage.getDevice(deviceId); Device device = redisCatchStorage.getDevice(deviceId);
// 查询上级平台是否存在 // 查询上级平台是否存在
@ -63,7 +70,12 @@ public class MessageRequestProcessor extends SIPRequestProcessorParent implement
try { try {
if (device == null && parentPlatform == null) { if (device == null && parentPlatform == null) {
// 不存在则回复404 // 不存在则回复404
responseAck(evt, Response.NOT_FOUND, "device id not found"); responseAck(evt, Response.NOT_FOUND, "device "+ deviceId +" not found");
logger.warn("[设备未找到 ]: {}", deviceId);
if (sipSubscribe.getErrorSubscribe(callIdHeader.getCallId()) != null){
SipSubscribe.EventResult eventResult = new SipSubscribe.EventResult(new DeviceNotFoundEvent(evt.getDialog()));
sipSubscribe.getErrorSubscribe(callIdHeader.getCallId()).response(eventResult);
};
}else { }else {
Element rootElement = getRootElement(evt); Element rootElement = getRootElement(evt);
String name = rootElement.getName(); String name = rootElement.getName();

43
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/CatalogNotifyMessageHandler.java

@ -1,10 +1,7 @@
package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.notify.cmd; package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.notify.cmd;
import com.genersoft.iot.vmp.conf.SipConfig; import com.genersoft.iot.vmp.conf.SipConfig;
import com.genersoft.iot.vmp.gb28181.bean.Device; import com.genersoft.iot.vmp.gb28181.bean.*;
import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
import com.genersoft.iot.vmp.gb28181.bean.GbStream;
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
import com.genersoft.iot.vmp.gb28181.event.EventPublisher; 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.DeferredResultHolder;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform; import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform;
@ -71,11 +68,41 @@ public class CatalogNotifyMessageHandler extends SIPRequestProcessorParent imple
// 查询关联的直播通道 // 查询关联的直播通道
List<GbStream> gbStreams = storager.queryGbStreamListInPlatform(parentPlatform.getServerGBId()); List<GbStream> gbStreams = storager.queryGbStreamListInPlatform(parentPlatform.getServerGBId());
int size = channelReduces.size() + gbStreams.size(); int size = channelReduces.size() + gbStreams.size();
// 回复目录信息
List<PlatformCatalog> catalogs = storager.queryCatalogInPlatform(parentPlatform.getServerGBId());
if (catalogs.size() > 0) {
for (PlatformCatalog catalog : catalogs) {
DeviceChannel deviceChannel = new DeviceChannel();
deviceChannel.setChannelId(catalog.getId());
deviceChannel.setName(catalog.getName());
deviceChannel.setLongitude(0.0);
deviceChannel.setLatitude(0.0);
deviceChannel.setDeviceId(parentPlatform.getDeviceGBId());
deviceChannel.setManufacture("wvp-pro");
deviceChannel.setStatus(1);
deviceChannel.setParental(1);
deviceChannel.setParentId(catalog.getParentId());
deviceChannel.setRegisterWay(1);
deviceChannel.setCivilCode(config.getDomain());
deviceChannel.setModel("live");
deviceChannel.setOwner("wvp-pro");
deviceChannel.setSecrecy("0");
cmderFroPlatform.catalogQuery(deviceChannel, parentPlatform, sn, fromHeader.getTag(), size);
// 防止发送过快
Thread.sleep(10);
}
}
// 回复级联的通道 // 回复级联的通道
if (channelReduces.size() > 0) { if (channelReduces.size() > 0) {
for (ChannelReduce channelReduce : channelReduces) { for (ChannelReduce channelReduce : channelReduces) {
DeviceChannel deviceChannel = storager.queryChannel(channelReduce.getDeviceId(), channelReduce.getChannelId()); DeviceChannel deviceChannel = storager.queryChannel(channelReduce.getDeviceId(), channelReduce.getChannelId());
// TODO 目前暂时认为这里只用通道没有目录
deviceChannel.setParental(0);
deviceChannel.setParentId(channelReduce.getCatalogId());
cmderFroPlatform.catalogQuery(deviceChannel, parentPlatform, sn, fromHeader.getTag(), size); cmderFroPlatform.catalogQuery(deviceChannel, parentPlatform, sn, fromHeader.getTag(), size);
// 防止发送过快
Thread.sleep(10);
} }
} }
// 回复直播的通道 // 回复直播的通道
@ -89,16 +116,16 @@ public class CatalogNotifyMessageHandler extends SIPRequestProcessorParent imple
deviceChannel.setDeviceId(parentPlatform.getDeviceGBId()); deviceChannel.setDeviceId(parentPlatform.getDeviceGBId());
deviceChannel.setManufacture("wvp-pro"); deviceChannel.setManufacture("wvp-pro");
deviceChannel.setStatus(gbStream.isStatus()?1:0); deviceChannel.setStatus(gbStream.isStatus()?1:0);
// deviceChannel.setParentId(parentPlatform.getDeviceGBId()); deviceChannel.setParentId(gbStream.getCatalogId());
deviceChannel.setRegisterWay(1); deviceChannel.setRegisterWay(1);
deviceChannel.setCivilCode(config.getDomain()); deviceChannel.setCivilCode(config.getDomain());
deviceChannel.setModel("live"); deviceChannel.setModel("live");
deviceChannel.setOwner("wvp-pro"); deviceChannel.setOwner("wvp-pro");
deviceChannel.setParental(0); deviceChannel.setParental(0);
deviceChannel.setSecrecy("0"); deviceChannel.setSecrecy("0");
deviceChannel.setSecrecy("0");
cmderFroPlatform.catalogQuery(deviceChannel, parentPlatform, sn, fromHeader.getTag(), size); cmderFroPlatform.catalogQuery(deviceChannel, parentPlatform, sn, fromHeader.getTag(), size);
// 防止发送过快
Thread.sleep(10);
} }
} }
if (size == 0) { if (size == 0) {
@ -111,6 +138,8 @@ public class CatalogNotifyMessageHandler extends SIPRequestProcessorParent imple
e.printStackTrace(); e.printStackTrace();
} catch (ParseException e) { } catch (ParseException e) {
e.printStackTrace(); e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
} }
} }

41
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/CatalogQueryMessageHandler.java

@ -1,10 +1,7 @@
package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.query.cmd; package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.query.cmd;
import com.genersoft.iot.vmp.conf.SipConfig; import com.genersoft.iot.vmp.conf.SipConfig;
import com.genersoft.iot.vmp.gb28181.bean.Device; import com.genersoft.iot.vmp.gb28181.bean.*;
import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
import com.genersoft.iot.vmp.gb28181.bean.GbStream;
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
import com.genersoft.iot.vmp.gb28181.event.EventPublisher; 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.DeferredResultHolder;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform; import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform;
@ -73,12 +70,41 @@ public class CatalogQueryMessageHandler extends SIPRequestProcessorParent implem
List<ChannelReduce> channelReduces = storager.queryChannelListInParentPlatform(parentPlatform.getServerGBId()); List<ChannelReduce> channelReduces = storager.queryChannelListInParentPlatform(parentPlatform.getServerGBId());
// 查询关联的直播通道 // 查询关联的直播通道
List<GbStream> gbStreams = storager.queryGbStreamListInPlatform(parentPlatform.getServerGBId()); List<GbStream> gbStreams = storager.queryGbStreamListInPlatform(parentPlatform.getServerGBId());
int size = channelReduces.size() + gbStreams.size(); // 回复目录信息
List<PlatformCatalog> catalogs = storager.queryCatalogInPlatform(parentPlatform.getServerGBId());
int size = catalogs.size() + channelReduces.size() + gbStreams.size();
if (catalogs.size() > 0) {
for (PlatformCatalog catalog : catalogs) {
DeviceChannel deviceChannel = new DeviceChannel();
deviceChannel.setChannelId(catalog.getId());
deviceChannel.setName(catalog.getName());
deviceChannel.setLongitude(0.0);
deviceChannel.setLatitude(0.0);
deviceChannel.setDeviceId(parentPlatform.getDeviceGBId());
deviceChannel.setManufacture("wvp-pro");
deviceChannel.setStatus(1);
deviceChannel.setParental(1);
deviceChannel.setParentId(catalog.getParentId());
deviceChannel.setRegisterWay(1);
deviceChannel.setCivilCode(config.getDomain());
deviceChannel.setModel("live");
deviceChannel.setOwner("wvp-pro");
deviceChannel.setSecrecy("0");
cmderFroPlatform.catalogQuery(deviceChannel, parentPlatform, sn, fromHeader.getTag(), size);
// 防止发送过快
Thread.sleep(10);
}
}
// 回复级联的通道 // 回复级联的通道
if (channelReduces.size() > 0) { if (channelReduces.size() > 0) {
for (ChannelReduce channelReduce : channelReduces) { for (ChannelReduce channelReduce : channelReduces) {
DeviceChannel deviceChannel = storager.queryChannel(channelReduce.getDeviceId(), channelReduce.getChannelId()); DeviceChannel deviceChannel = storager.queryChannel(channelReduce.getDeviceId(), channelReduce.getChannelId());
// TODO 目前暂时认为这里只用通道没有目录
deviceChannel.setParental(0);
deviceChannel.setParentId(channelReduce.getCatalogId());
cmderFroPlatform.catalogQuery(deviceChannel, parentPlatform, sn, fromHeader.getTag(), size); cmderFroPlatform.catalogQuery(deviceChannel, parentPlatform, sn, fromHeader.getTag(), size);
// 防止发送过快
Thread.sleep(10);
} }
} }
// 回复直播的通道 // 回复直播的通道
@ -92,14 +118,13 @@ public class CatalogQueryMessageHandler extends SIPRequestProcessorParent implem
deviceChannel.setDeviceId(parentPlatform.getDeviceGBId()); deviceChannel.setDeviceId(parentPlatform.getDeviceGBId());
deviceChannel.setManufacture("wvp-pro"); deviceChannel.setManufacture("wvp-pro");
deviceChannel.setStatus(gbStream.isStatus()?1:0); deviceChannel.setStatus(gbStream.isStatus()?1:0);
// deviceChannel.setParentId(parentPlatform.getDeviceGBId()); deviceChannel.setParentId(gbStream.getCatalogId());
deviceChannel.setRegisterWay(1); deviceChannel.setRegisterWay(1);
deviceChannel.setCivilCode(config.getDomain()); deviceChannel.setCivilCode(config.getDomain());
deviceChannel.setModel("live"); deviceChannel.setModel("live");
deviceChannel.setOwner("wvp-pro"); deviceChannel.setOwner("wvp-pro");
deviceChannel.setParental(0); deviceChannel.setParental(0);
deviceChannel.setSecrecy("0"); deviceChannel.setSecrecy("0");
deviceChannel.setSecrecy("0");
cmderFroPlatform.catalogQuery(deviceChannel, parentPlatform, sn, fromHeader.getTag(), size); cmderFroPlatform.catalogQuery(deviceChannel, parentPlatform, sn, fromHeader.getTag(), size);
} }
@ -114,6 +139,8 @@ public class CatalogQueryMessageHandler extends SIPRequestProcessorParent implem
e.printStackTrace(); e.printStackTrace();
} catch (ParseException e) { } catch (ParseException e) {
e.printStackTrace(); e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
} }
} }

81
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/CatalogResponseMessageHandler.java

@ -14,6 +14,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.IMessageHandler;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.ResponseMessageHandler; import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.ResponseMessageHandler;
import com.genersoft.iot.vmp.gb28181.utils.NumericUtil; import com.genersoft.iot.vmp.gb28181.utils.NumericUtil;
import com.genersoft.iot.vmp.gb28181.utils.XmlUtil;
import com.genersoft.iot.vmp.storager.IVideoManagerStorager; import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
import com.genersoft.iot.vmp.vmanager.bean.WVPResult; import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
import org.dom4j.DocumentException; import org.dom4j.DocumentException;
@ -94,85 +95,9 @@ public class CatalogResponseMessageHandler extends SIPRequestProcessorParent imp
if (channelDeviceElement == null) { if (channelDeviceElement == null) {
continue; continue;
} }
String channelDeviceId = channelDeviceElement.getText(); DeviceChannel deviceChannel = XmlUtil.channelContentHander(itemDevice);
Element channdelNameElement = itemDevice.element("Name");
String channelName = channdelNameElement != null ? channdelNameElement.getTextTrim().toString() : "";
Element statusElement = itemDevice.element("Status");
String status = statusElement != null ? statusElement.getText().toString() : "ON";
DeviceChannel deviceChannel = new DeviceChannel();
deviceChannel.setName(channelName);
deviceChannel.setDeviceId(device.getDeviceId()); deviceChannel.setDeviceId(device.getDeviceId());
String now = this.format.format(new Date(System.currentTimeMillis())); logger.debug("收到来自设备【{}】的通道: {}【{}】", device.getDeviceId(), deviceChannel.getName(), deviceChannel.getChannelId());
deviceChannel.setCreateTime(now);
deviceChannel.setUpdateTime(now);
deviceChannel.setChannelId(channelDeviceId);
// ONLINE OFFLINE HIKVISION DS-7716N-E4 NVR的兼容性处理
if (status.equals("ON") || status.equals("On") || status.equals("ONLINE")) {
deviceChannel.setStatus(1);
}
if (status.equals("OFF") || status.equals("Off") || status.equals("OFFLINE")) {
deviceChannel.setStatus(0);
}
deviceChannel.setManufacture(getText(itemDevice, "Manufacturer"));
deviceChannel.setModel(getText(itemDevice, "Model"));
deviceChannel.setOwner(getText(itemDevice, "Owner"));
deviceChannel.setCivilCode(getText(itemDevice, "CivilCode"));
deviceChannel.setBlock(getText(itemDevice, "Block"));
deviceChannel.setAddress(getText(itemDevice, "Address"));
if (getText(itemDevice, "Parental") == null || getText(itemDevice, "Parental") == "") {
deviceChannel.setParental(0);
} else {
deviceChannel.setParental(Integer.parseInt(getText(itemDevice, "Parental")));
}
deviceChannel.setParentId(getText(itemDevice, "ParentID"));
if (getText(itemDevice, "SafetyWay") == null || getText(itemDevice, "SafetyWay") == "") {
deviceChannel.setSafetyWay(0);
} else {
deviceChannel.setSafetyWay(Integer.parseInt(getText(itemDevice, "SafetyWay")));
}
if (getText(itemDevice, "RegisterWay") == null || getText(itemDevice, "RegisterWay") == "") {
deviceChannel.setRegisterWay(1);
} else {
deviceChannel.setRegisterWay(Integer.parseInt(getText(itemDevice, "RegisterWay")));
}
deviceChannel.setCertNum(getText(itemDevice, "CertNum"));
if (getText(itemDevice, "Certifiable") == null || getText(itemDevice, "Certifiable") == "") {
deviceChannel.setCertifiable(0);
} else {
deviceChannel.setCertifiable(Integer.parseInt(getText(itemDevice, "Certifiable")));
}
if (getText(itemDevice, "ErrCode") == null || getText(itemDevice, "ErrCode") == "") {
deviceChannel.setErrCode(0);
} else {
deviceChannel.setErrCode(Integer.parseInt(getText(itemDevice, "ErrCode")));
}
deviceChannel.setEndTime(getText(itemDevice, "EndTime"));
deviceChannel.setSecrecy(getText(itemDevice, "Secrecy"));
deviceChannel.setIpAddress(getText(itemDevice, "IPAddress"));
if (getText(itemDevice, "Port") == null || getText(itemDevice, "Port") == "") {
deviceChannel.setPort(0);
} else {
deviceChannel.setPort(Integer.parseInt(getText(itemDevice, "Port")));
}
deviceChannel.setPassword(getText(itemDevice, "Password"));
if (NumericUtil.isDouble(getText(itemDevice, "Longitude"))) {
deviceChannel.setLongitude(Double.parseDouble(getText(itemDevice, "Longitude")));
} else {
deviceChannel.setLongitude(0.00);
}
if (NumericUtil.isDouble(getText(itemDevice, "Latitude"))) {
deviceChannel.setLatitude(Double.parseDouble(getText(itemDevice, "Latitude")));
} else {
deviceChannel.setLatitude(0.00);
}
Element InfoNode = channelDeviceElement.element("Info");
if (getText(InfoNode, "PTZType") == null || getText(InfoNode, "PTZType") == "") {
deviceChannel.setPTZType(0);
} else {
deviceChannel.setPTZType(Integer.parseInt(getText(InfoNode, "PTZType")));
}
deviceChannel.setHasAudio(true); // 默认含有音频,播放时再检查是否有音频及是否AAC
channelList.add(deviceChannel); channelList.add(deviceChannel);
} }

34
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/DeviceControlResponseMessageHandler.java

@ -16,7 +16,12 @@ import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import javax.sip.InvalidArgumentException;
import javax.sip.RequestEvent; import javax.sip.RequestEvent;
import javax.sip.SipException;
import javax.sip.message.Response;
import java.text.ParseException;
import static com.genersoft.iot.vmp.gb28181.utils.XmlUtil.getText; import static com.genersoft.iot.vmp.gb28181.utils.XmlUtil.getText;
@ -40,17 +45,26 @@ public class DeviceControlResponseMessageHandler extends SIPRequestProcessorPare
@Override @Override
public void handForDevice(RequestEvent evt, Device device, Element element) { public void handForDevice(RequestEvent evt, Device device, Element element) {
// 此处是对本平台发出DeviceControl指令的应答 // 此处是对本平台发出DeviceControl指令的应答
JSONObject json = new JSONObject(); try {
String channelId = getText(element, "DeviceID"); responseAck(evt, Response.OK);
XmlUtil.node2Json(element, json); JSONObject json = new JSONObject();
if (logger.isDebugEnabled()) { String channelId = getText(element, "DeviceID");
logger.debug(json.toJSONString()); XmlUtil.node2Json(element, json);
if (logger.isDebugEnabled()) {
logger.debug(json.toJSONString());
}
RequestMessage msg = new RequestMessage();
String key = DeferredResultHolder.CALLBACK_CMD_DEVICECONTROL + device.getDeviceId() + channelId;
msg.setKey(key);
msg.setData(json);
deferredResultHolder.invokeAllResult(msg);
} catch (SipException e) {
e.printStackTrace();
} catch (InvalidArgumentException e) {
e.printStackTrace();
} catch (ParseException e) {
e.printStackTrace();
} }
RequestMessage msg = new RequestMessage();
String key = DeferredResultHolder.CALLBACK_CMD_DEVICECONTROL + device.getDeviceId() + channelId;
msg.setKey(key);
msg.setData(json);
deferredResultHolder.invokeAllResult(msg);
} }
@Override @Override

86
src/main/java/com/genersoft/iot/vmp/gb28181/utils/XmlUtil.java

@ -2,6 +2,7 @@ package com.genersoft.iot.vmp.gb28181.utils;
import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
import org.dom4j.Attribute; import org.dom4j.Attribute;
import org.dom4j.Document; import org.dom4j.Document;
import org.dom4j.DocumentException; import org.dom4j.DocumentException;
@ -178,4 +179,89 @@ public class XmlUtil {
Document xml = reader.read(new ByteArrayInputStream(content)); Document xml = reader.read(new ByteArrayInputStream(content));
return xml.getRootElement(); return xml.getRootElement();
} }
public static DeviceChannel channelContentHander(Element itemDevice){
Element channdelNameElement = itemDevice.element("Name");
String channelName = channdelNameElement != null ? channdelNameElement.getTextTrim().toString() : "";
Element statusElement = itemDevice.element("Status");
String status = statusElement != null ? statusElement.getTextTrim().toString() : "ON";
DeviceChannel deviceChannel = new DeviceChannel();
deviceChannel.setName(channelName);
Element channdelIdElement = itemDevice.element("DeviceID");
String channelId = channdelIdElement != null ? channdelIdElement.getTextTrim().toString() : "";
deviceChannel.setChannelId(channelId);
// ONLINE OFFLINE HIKVISION DS-7716N-E4 NVR的兼容性处理
if (status.equals("ON") || status.equals("On") || status.equals("ONLINE")) {
deviceChannel.setStatus(1);
}
if (status.equals("OFF") || status.equals("Off") || status.equals("OFFLINE")) {
deviceChannel.setStatus(0);
}
deviceChannel.setManufacture(XmlUtil.getText(itemDevice, "Manufacturer"));
deviceChannel.setModel(XmlUtil.getText(itemDevice, "Model"));
deviceChannel.setOwner(XmlUtil.getText(itemDevice, "Owner"));
deviceChannel.setCivilCode(XmlUtil.getText(itemDevice, "CivilCode"));
deviceChannel.setBlock(XmlUtil.getText(itemDevice, "Block"));
deviceChannel.setAddress(XmlUtil.getText(itemDevice, "Address"));
if (XmlUtil.getText(itemDevice, "Parental") == null
|| XmlUtil.getText(itemDevice, "Parental") == "") {
deviceChannel.setParental(0);
} else {
deviceChannel.setParental(Integer.parseInt(XmlUtil.getText(itemDevice, "Parental")));
}
deviceChannel.setParentId(XmlUtil.getText(itemDevice, "ParentID"));
if (XmlUtil.getText(itemDevice, "SafetyWay") == null
|| XmlUtil.getText(itemDevice, "SafetyWay") == "") {
deviceChannel.setSafetyWay(0);
} else {
deviceChannel.setSafetyWay(Integer.parseInt(XmlUtil.getText(itemDevice, "SafetyWay")));
}
if (XmlUtil.getText(itemDevice, "RegisterWay") == null
|| XmlUtil.getText(itemDevice, "RegisterWay") == "") {
deviceChannel.setRegisterWay(1);
} else {
deviceChannel.setRegisterWay(Integer.parseInt(XmlUtil.getText(itemDevice, "RegisterWay")));
}
deviceChannel.setCertNum(XmlUtil.getText(itemDevice, "CertNum"));
if (XmlUtil.getText(itemDevice, "Certifiable") == null
|| XmlUtil.getText(itemDevice, "Certifiable") == "") {
deviceChannel.setCertifiable(0);
} else {
deviceChannel.setCertifiable(Integer.parseInt(XmlUtil.getText(itemDevice, "Certifiable")));
}
if (XmlUtil.getText(itemDevice, "ErrCode") == null
|| XmlUtil.getText(itemDevice, "ErrCode") == "") {
deviceChannel.setErrCode(0);
} else {
deviceChannel.setErrCode(Integer.parseInt(XmlUtil.getText(itemDevice, "ErrCode")));
}
deviceChannel.setEndTime(XmlUtil.getText(itemDevice, "EndTime"));
deviceChannel.setSecrecy(XmlUtil.getText(itemDevice, "Secrecy"));
deviceChannel.setIpAddress(XmlUtil.getText(itemDevice, "IPAddress"));
if (XmlUtil.getText(itemDevice, "Port") == null || XmlUtil.getText(itemDevice, "Port") == "") {
deviceChannel.setPort(0);
} else {
deviceChannel.setPort(Integer.parseInt(XmlUtil.getText(itemDevice, "Port")));
}
deviceChannel.setPassword(XmlUtil.getText(itemDevice, "Password"));
if (NumericUtil.isDouble(XmlUtil.getText(itemDevice, "Longitude"))) {
deviceChannel.setLongitude(Double.parseDouble(XmlUtil.getText(itemDevice, "Longitude")));
} else {
deviceChannel.setLongitude(0.00);
}
if (NumericUtil.isDouble(XmlUtil.getText(itemDevice, "Latitude"))) {
deviceChannel.setLatitude(Double.parseDouble(XmlUtil.getText(itemDevice, "Latitude")));
} else {
deviceChannel.setLatitude(0.00);
}
if (XmlUtil.getText(itemDevice, "PTZType") == null
|| XmlUtil.getText(itemDevice, "PTZType") == "") {
deviceChannel.setPTZType(0);
} else {
deviceChannel.setPTZType(Integer.parseInt(XmlUtil.getText(itemDevice, "PTZType")));
}
deviceChannel.setHasAudio(true); // 默认含有音频,播放时再检查是否有音频及是否AAC
return deviceChannel;
}
} }

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

@ -1,14 +1,17 @@
package com.genersoft.iot.vmp.media.zlm; package com.genersoft.iot.vmp.media.zlm;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.genersoft.iot.vmp.common.StreamInfo; import com.genersoft.iot.vmp.common.StreamInfo;
import com.genersoft.iot.vmp.conf.MediaConfig; import com.genersoft.iot.vmp.conf.MediaConfig;
import com.genersoft.iot.vmp.conf.UserSetup; import com.genersoft.iot.vmp.conf.UserSetup;
import com.genersoft.iot.vmp.gb28181.bean.Device; import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.gb28181.bean.GbStream;
import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent;
import com.genersoft.iot.vmp.media.zlm.dto.*; import com.genersoft.iot.vmp.media.zlm.dto.*;
import com.genersoft.iot.vmp.service.*; import com.genersoft.iot.vmp.service.*;
import com.genersoft.iot.vmp.service.bean.SSRCInfo; import com.genersoft.iot.vmp.service.bean.SSRCInfo;
@ -66,7 +69,7 @@ public class ZLMHttpHookListener {
private IMediaService mediaService; private IMediaService mediaService;
@Autowired @Autowired
private ZLMRESTfulUtils zlmresTfulUtils; private EventPublisher eventPublisher;
@Autowired @Autowired
private ZLMMediaListManager zlmMediaListManager; private ZLMMediaListManager zlmMediaListManager;
@ -302,7 +305,7 @@ public class ZLMHttpHookListener {
@ResponseBody @ResponseBody
@PostMapping(value = "/on_stream_changed", produces = "application/json;charset=UTF-8") @PostMapping(value = "/on_stream_changed", produces = "application/json;charset=UTF-8")
public ResponseEntity<String> onStreamChanged(@RequestBody MediaItem item){ public ResponseEntity<String> onStreamChanged(@RequestBody MediaItem item){
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {
logger.debug("[ ZLM HOOK ]on_stream_changed API调用,参数:" + JSONObject.toJSONString(item)); logger.debug("[ ZLM HOOK ]on_stream_changed API调用,参数:" + JSONObject.toJSONString(item));
} }
@ -322,10 +325,8 @@ public class ZLMHttpHookListener {
String schema = item.getSchema(); String schema = item.getSchema();
List<MediaItem.MediaTrack> tracks = item.getTracks(); List<MediaItem.MediaTrack> tracks = item.getTracks();
boolean regist = item.isRegist(); boolean regist = item.isRegist();
if (tracks != null) {
logger.info("[stream: " + streamId + "] on_stream_changed->>" + schema);
}
if ("rtmp".equals(schema)){ if ("rtmp".equals(schema)){
logger.info("on_stream_changed:注册->{}, app->{}, stream->{}", regist, app, streamId);
if (regist) { if (regist) {
mediaServerService.addCount(mediaServerId); mediaServerService.addCount(mediaServerId);
}else { }else {
@ -344,37 +345,52 @@ public class ZLMHttpHookListener {
if (!"rtp".equals(app)){ if (!"rtp".equals(app)){
String type = OriginType.values()[item.getOriginType()].getType(); String type = OriginType.values()[item.getOriginType()].getType();
MediaServerItem mediaServerItem = mediaServerService.getOne(mediaServerId); MediaServerItem mediaServerItem = mediaServerService.getOne(mediaServerId);
if (mediaServerItem != null){ if (mediaServerItem != null){
if (regist) { if (regist) {
StreamInfo streamInfo = mediaService.getStreamInfoByAppAndStream(mediaServerItem, app, streamId, tracks); StreamPushItem streamPushItem = null;
redisCatchStorage.addStream(mediaServerItem, type, app, streamId, streamInfo); redisCatchStorage.addStream(mediaServerItem, type, app, streamId, item);
if (item.getOriginType() == OriginType.RTSP_PUSH.ordinal() if (item.getOriginType() == OriginType.RTSP_PUSH.ordinal()
|| item.getOriginType() == OriginType.RTMP_PUSH.ordinal() || item.getOriginType() == OriginType.RTMP_PUSH.ordinal()
|| item.getOriginType() == OriginType.RTC_PUSH.ordinal() ) { || item.getOriginType() == OriginType.RTC_PUSH.ordinal() ) {
zlmMediaListManager.addPush(item); streamPushItem = zlmMediaListManager.addPush(item);
} }
}else { List<GbStream> gbStreams = new ArrayList<>();
// 兼容流注销时类型错误的问题,等zlm更新后删除 if (streamPushItem == null || streamPushItem.getGbId() == null) {
StreamPushItem streamPushItem = streamPushService.getPush(app, streamId); GbStream gbStream = storager.getGbStream(app, streamId);
if (streamPushItem != null) { gbStreams.add(gbStream);
type = "PUSH";
}else { }else {
StreamProxyItem streamProxyByAppAndStream = streamProxyService.getStreamProxyByAppAndStream(app, streamId); if (streamPushItem.getGbId() != null) {
if (streamProxyByAppAndStream != null) { gbStreams.add(streamPushItem);
type = "PULL";
} }
} }
if (gbStreams.size() > 0) {
eventPublisher.catalogEventPublishForStream(null, gbStreams, CatalogEvent.ON);
}
}else {
// 兼容流注销时类型从redis记录获取
MediaItem mediaItem = redisCatchStorage.getStreamInfo(app, streamId, mediaServerId);
if (mediaItem != null) {
type = OriginType.values()[mediaItem.getOriginType()].getType();
redisCatchStorage.removeStream(mediaServerItem.getId(), type, app, streamId);
}
GbStream gbStream = storager.getGbStream(app, streamId);
if (gbStream != null) {
eventPublisher.catalogEventPublishForStream(null, gbStream, CatalogEvent.OFF);
}
zlmMediaListManager.removeMedia(app, streamId); zlmMediaListManager.removeMedia(app, streamId);
redisCatchStorage.removeStream(mediaServerItem.getId(), type, app, streamId);
} }
// 发送流变化redis消息 if (type != null) {
JSONObject jsonObject = new JSONObject(); // 发送流变化redis消息
jsonObject.put("serverId", userSetup.getServerId()); JSONObject jsonObject = new JSONObject();
jsonObject.put("app", app); jsonObject.put("serverId", userSetup.getServerId());
jsonObject.put("stream", streamId); jsonObject.put("app", app);
jsonObject.put("register", regist); jsonObject.put("stream", streamId);
jsonObject.put("mediaServerId", mediaServerId); jsonObject.put("register", regist);
redisCatchStorage.sendStreamChangeMsg(type, jsonObject); jsonObject.put("mediaServerId", mediaServerId);
redisCatchStorage.sendStreamChangeMsg(type, jsonObject);
}
} }
} }
} }

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

@ -105,7 +105,7 @@ public class ZLMMediaListManager {
updateMedia(mediaServerItem, app, streamId); updateMedia(mediaServerItem, app, streamId);
} }
public void addPush(MediaItem mediaItem) { public StreamPushItem addPush(MediaItem mediaItem) {
// 查找此直播流是否存在redis预设gbId // 查找此直播流是否存在redis预设gbId
StreamPushItem transform = streamPushService.transform(mediaItem); StreamPushItem transform = streamPushService.transform(mediaItem);
// 从streamId取出查询关键值 // 从streamId取出查询关键值
@ -130,7 +130,6 @@ public class ZLMMediaListManager {
for (GbStream gbStream : gbStreams) { for (GbStream gbStream : gbStreams) {
// 出现使用相同国标Id的视频流时,使用新流替换旧流, // 出现使用相同国标Id的视频流时,使用新流替换旧流,
gbStreamMapper.del(gbStream.getApp(), gbStream.getStream()); gbStreamMapper.del(gbStream.getApp(), gbStream.getStream());
platformGbStreamMapper.delByAppAndStream(gbStream.getApp(), gbStream.getStream());
if (!gbStream.isStatus()) { if (!gbStream.isStatus()) {
streamPushMapper.del(gbStream.getApp(), gbStream.getStream()); streamPushMapper.del(gbStream.getApp(), gbStream.getStream());
} }
@ -142,6 +141,7 @@ public class ZLMMediaListManager {
gbStreamMapper.add(transform); gbStreamMapper.add(transform);
} }
} }
return transform;
} }

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

@ -2,6 +2,7 @@ package com.genersoft.iot.vmp.media.zlm.event;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import com.genersoft.iot.vmp.common.VideoManagerConstants; import com.genersoft.iot.vmp.common.VideoManagerConstants;
import com.genersoft.iot.vmp.conf.RedisKeyExpirationEventMessageListener;
import com.genersoft.iot.vmp.conf.UserSetup; import com.genersoft.iot.vmp.conf.UserSetup;
import com.genersoft.iot.vmp.gb28181.event.EventPublisher; import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils; import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
@ -21,7 +22,7 @@ import org.springframework.stereotype.Component;
* @date: 2020年5月6日 上午11:35:46 * @date: 2020年5月6日 上午11:35:46
*/ */
@Component @Component
public class ZLMKeepliveTimeoutListener extends KeyExpirationEventMessageListener { public class ZLMKeepliveTimeoutListener extends RedisKeyExpirationEventMessageListener {
private Logger logger = LoggerFactory.getLogger(ZLMKeepliveTimeoutListener.class); private Logger logger = LoggerFactory.getLogger(ZLMKeepliveTimeoutListener.class);
@ -37,20 +38,12 @@ public class ZLMKeepliveTimeoutListener extends KeyExpirationEventMessageListene
@Autowired @Autowired
private IMediaServerService mediaServerService; private IMediaServerService mediaServerService;
@Override public ZLMKeepliveTimeoutListener(RedisMessageListenerContainer listenerContainer, UserSetup userSetup) {
public void init() { super(listenerContainer, userSetup);
if (!userSetup.getRedisConfig()) {
// 配置springboot默认Config为空,即不让应用去修改redis的默认配置,因为Redis服务出于安全会禁用CONFIG命令给远程用户使用
setKeyspaceNotificationsConfigParameter("");
}
super.init();
} }
public ZLMKeepliveTimeoutListener(RedisMessageListenerContainer listenerContainer) {
super(listenerContainer);
}
/** /**
* 监听失效的keykey格式为keeplive_deviceId * 监听失效的keykey格式为keeplive_deviceId
* @param message * @param message
* @param pattern * @param pattern

12
src/main/java/com/genersoft/iot/vmp/service/IGbStreamService.java

@ -1,5 +1,6 @@
package com.genersoft.iot.vmp.service; package com.genersoft.iot.vmp.service;
import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
import com.genersoft.iot.vmp.gb28181.bean.GbStream; import com.genersoft.iot.vmp.gb28181.bean.GbStream;
import com.github.pagehelper.PageInfo; import com.github.pagehelper.PageInfo;
@ -16,7 +17,7 @@ public interface IGbStreamService {
* @param count * @param count
* @return * @return
*/ */
PageInfo<GbStream> getAll(Integer page, Integer count); PageInfo<GbStream> getAll(Integer page, Integer count, String platFormId);
/** /**
@ -30,11 +31,16 @@ public interface IGbStreamService {
* 保存国标关联 * 保存国标关联
* @param gbStreams * @param gbStreams
*/ */
boolean addPlatformInfo(List<GbStream> gbStreams, String platformId); boolean addPlatformInfo(List<GbStream> gbStreams, String platformId, String catalogId);
/** /**
* 移除国标关联 * 移除国标关联
* @param gbStreams * @param gbStreams
* @param platformId
*/ */
boolean delPlatformInfo(List<GbStream> gbStreams); boolean delPlatformInfo(String platformId, List<GbStream> gbStreams);
DeviceChannel getDeviceChannelListByStream(GbStream gbStream, String catalogId, String deviceGBId);
void sendCatalogMsg(GbStream gbStream, String type);
} }

3
src/main/java/com/genersoft/iot/vmp/service/IStreamPushService.java

@ -5,6 +5,7 @@ import com.genersoft.iot.vmp.media.zlm.ZLMServerConfig;
import com.genersoft.iot.vmp.media.zlm.dto.MediaItem; import com.genersoft.iot.vmp.media.zlm.dto.MediaItem;
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem; import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem;
import com.genersoft.iot.vmp.vmanager.bean.StreamPushExcelDto;
import com.github.pagehelper.PageInfo; import com.github.pagehelper.PageInfo;
import java.util.List; import java.util.List;
@ -65,4 +66,6 @@ public interface IStreamPushService {
void clean(); void clean();
boolean saveToRandomGB(); boolean saveToRandomGB();
void batchAdd(List<StreamPushItem> streamPushExcelDtoList);
} }

39
src/main/java/com/genersoft/iot/vmp/service/StreamGPSSubscribeTask.java

@ -0,0 +1,39 @@
package com.genersoft.iot.vmp.service;
import com.genersoft.iot.vmp.service.bean.GPSMsgInfo;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.util.List;
/**
* 定时查找redis中的GPS推送消息并保存到对应的流中
*/
@Component
public class StreamGPSSubscribeTask {
@Autowired
private IRedisCatchStorage redisCatchStorage;
@Autowired
private IVideoManagerStorager storager;
@Scheduled(fixedRate = 30 * 1000) //每30秒执行一次
public void execute(){
List<GPSMsgInfo> gpsMsgInfo = redisCatchStorage.getAllGpsMsgInfo();
if (gpsMsgInfo.size() > 0) {
storager.updateStreamGPS(gpsMsgInfo);
for (GPSMsgInfo msgInfo : gpsMsgInfo) {
msgInfo.setStored(true);
redisCatchStorage.updateGpsMsgInfo(msgInfo);
}
}
}
}

16
src/main/java/com/genersoft/iot/vmp/service/bean/CatalogSubscribeTask.java

@ -26,20 +26,8 @@ public class CatalogSubscribeTask implements Runnable{
ResponseEvent event = (ResponseEvent) eventResult.event; ResponseEvent event = (ResponseEvent) eventResult.event;
Element rootElement = null; Element rootElement = null;
if (event.getResponse().getRawContent() != null) { if (event.getResponse().getRawContent() != null) {
try { // 成功
rootElement = XmlUtil.getRootElement(event.getResponse().getRawContent(), "gb2312"); logger.info("[目录订阅]成功: {}", device.getDeviceId());
} catch (DocumentException e) {
e.printStackTrace();
}
Element resultElement = rootElement.element("Result");
String result = resultElement.getText();
if (result.toUpperCase().equals("OK")){
// 成功
logger.info("[目录订阅]成功: {}", device.getDeviceId());
}else {
// 失败
logger.info("[目录订阅]失败: {}-{}", device.getDeviceId(), result);
}
}else { }else {
// 成功 // 成功
logger.info("[目录订阅]成功: {}", device.getDeviceId()); logger.info("[目录订阅]成功: {}", device.getDeviceId());

106
src/main/java/com/genersoft/iot/vmp/service/bean/GPSMsgInfo.java

@ -0,0 +1,106 @@
package com.genersoft.iot.vmp.service.bean;
public class GPSMsgInfo {
/**
*
*/
private String id;
/**
* 经度 (必选)
*/
private double lng;
/**
* 纬度 (必选)
*/
private double lat;
/**
* 速度,单位:km/h (可选)
*/
private double speed;
/**
* 产生通知时间, 时间格式 2020-01-14T14:32:12
*/
private String time;
/**
* 方向,取值为当前摄像头方向与正北方的顺时针夹角,取值范围0°~360°,单位:(°)(可选)
*/
private String direction;
/**
* 海拔高度,单位:m(可选)
*/
private String altitude;
private boolean stored;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public double getLng() {
return lng;
}
public void setLng(double lng) {
this.lng = lng;
}
public double getLat() {
return lat;
}
public void setLat(double lat) {
this.lat = lat;
}
public double getSpeed() {
return speed;
}
public void setSpeed(double speed) {
this.speed = speed;
}
public String getTime() {
return time;
}
public void setTime(String time) {
this.time = time;
}
public String getDirection() {
return direction;
}
public void setDirection(String direction) {
this.direction = direction;
}
public String getAltitude() {
return altitude;
}
public void setAltitude(String altitude) {
this.altitude = altitude;
}
public boolean isStored() {
return stored;
}
public void setStored(boolean stored) {
this.stored = stored;
}
}

6
src/main/java/com/genersoft/iot/vmp/service/impl/DeviceServiceImpl.java

@ -30,11 +30,15 @@ public class DeviceServiceImpl implements IDeviceService {
if (device == null || device.getSubscribeCycleForCatalog() < 0) { if (device == null || device.getSubscribeCycleForCatalog() < 0) {
return false; return false;
} }
if (dynamicTask.contains(device.getDeviceId())) {
logger.info("[添加目录订阅] 设备{}的目录订阅以存在", device.getDeviceId());
return false;
}
logger.info("[添加目录订阅] 设备{}", device.getDeviceId());
// 添加目录订阅 // 添加目录订阅
CatalogSubscribeTask catalogSubscribeTask = new CatalogSubscribeTask(device, sipCommander); CatalogSubscribeTask catalogSubscribeTask = new CatalogSubscribeTask(device, sipCommander);
catalogSubscribeTask.run(); catalogSubscribeTask.run();
// 提前开始刷新订阅 // 提前开始刷新订阅
// TODO 使用jain sip的当时刷新订阅
int subscribeCycleForCatalog = device.getSubscribeCycleForCatalog(); int subscribeCycleForCatalog = device.getSubscribeCycleForCatalog();
// 设置最小值为30 // 设置最小值为30
subscribeCycleForCatalog = Math.max(subscribeCycleForCatalog, 30); subscribeCycleForCatalog = Math.max(subscribeCycleForCatalog, 30);

80
src/main/java/com/genersoft/iot/vmp/service/impl/GbStreamServiceImpl.java

@ -1,7 +1,14 @@
package com.genersoft.iot.vmp.service.impl; package com.genersoft.iot.vmp.service.impl;
import com.genersoft.iot.vmp.conf.SipConfig;
import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
import com.genersoft.iot.vmp.gb28181.bean.GbStream; import com.genersoft.iot.vmp.gb28181.bean.GbStream;
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent;
import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem;
import com.genersoft.iot.vmp.storager.dao.GbStreamMapper; import com.genersoft.iot.vmp.storager.dao.GbStreamMapper;
import com.genersoft.iot.vmp.storager.dao.ParentPlatformMapper;
import com.genersoft.iot.vmp.storager.dao.PlatformGbStreamMapper; import com.genersoft.iot.vmp.storager.dao.PlatformGbStreamMapper;
import com.genersoft.iot.vmp.service.IGbStreamService; import com.genersoft.iot.vmp.service.IGbStreamService;
import com.github.pagehelper.PageHelper; import com.github.pagehelper.PageHelper;
@ -14,6 +21,7 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionDefinition; import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.TransactionStatus;
import java.util.ArrayList;
import java.util.List; import java.util.List;
@Service @Service
@ -33,10 +41,19 @@ public class GbStreamServiceImpl implements IGbStreamService {
@Autowired @Autowired
private PlatformGbStreamMapper platformGbStreamMapper; private PlatformGbStreamMapper platformGbStreamMapper;
@Autowired
private ParentPlatformMapper platformMapper;
@Autowired
private SipConfig sipConfig;
@Autowired
private EventPublisher eventPublisher;
@Override @Override
public PageInfo<GbStream> getAll(Integer page, Integer count) { public PageInfo<GbStream> getAll(Integer page, Integer count, String platFormId) {
PageHelper.startPage(page, count); PageHelper.startPage(page, count);
List<GbStream> all = gbStreamMapper.selectAll(); List<GbStream> all = gbStreamMapper.selectAll(platFormId);
return new PageInfo<>(all); return new PageInfo<>(all);
} }
@ -47,34 +64,66 @@ public class GbStreamServiceImpl implements IGbStreamService {
@Override @Override
public boolean addPlatformInfo(List<GbStream> gbStreams, String platformId) { public boolean addPlatformInfo(List<GbStream> gbStreams, String platformId, String catalogId) {
// 放在事务内执行 // 放在事务内执行
boolean result = false; boolean result = false;
TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition); TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition);
ParentPlatform parentPlatform = platformMapper.getParentPlatByServerGBId(platformId);
try { try {
List<DeviceChannel> deviceChannelList = new ArrayList<>();
for (GbStream gbStream : gbStreams) { for (GbStream gbStream : gbStreams) {
gbStream.setCatalogId(catalogId);
gbStream.setPlatformId(platformId); gbStream.setPlatformId(platformId);
// TODO 修改为批量提交
platformGbStreamMapper.add(gbStream); platformGbStreamMapper.add(gbStream);
DeviceChannel deviceChannelListByStream = getDeviceChannelListByStream(gbStream, catalogId, parentPlatform.getDeviceGBId());
deviceChannelList.add(deviceChannelListByStream);
} }
dataSourceTransactionManager.commit(transactionStatus); //手动提交 dataSourceTransactionManager.commit(transactionStatus); //手动提交
eventPublisher.catalogEventPublish(platformId, deviceChannelList, CatalogEvent.ADD);
result = true; result = true;
}catch (Exception e) { }catch (Exception e) {
logger.error("批量保存流与平台的关系时错误", e); logger.error("批量保存流与平台的关系时错误", e);
dataSourceTransactionManager.rollback(transactionStatus); dataSourceTransactionManager.rollback(transactionStatus);
} }
return result; return result;
}
@Override
public DeviceChannel getDeviceChannelListByStream(GbStream gbStream, String catalogId, String deviceGBId) {
DeviceChannel deviceChannel = new DeviceChannel();
deviceChannel.setChannelId(gbStream.getGbId());
deviceChannel.setName(gbStream.getName());
deviceChannel.setLongitude(gbStream.getLongitude());
deviceChannel.setLatitude(gbStream.getLatitude());
deviceChannel.setDeviceId(deviceGBId);
deviceChannel.setManufacture("wvp-pro");
deviceChannel.setStatus(gbStream.isStatus()?1:0);
deviceChannel.setParentId(catalogId ==null?gbStream.getCatalogId():catalogId);
deviceChannel.setRegisterWay(1);
deviceChannel.setCivilCode(sipConfig.getDomain());
deviceChannel.setModel("live");
deviceChannel.setOwner("wvp-pro");
deviceChannel.setParental(0);
deviceChannel.setSecrecy("0");
return deviceChannel;
} }
@Override @Override
public boolean delPlatformInfo(List<GbStream> gbStreams) { public boolean delPlatformInfo(String platformId, List<GbStream> gbStreams) {
// 放在事务内执行 // 放在事务内执行
boolean result = false; boolean result = false;
TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition); TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition);
try { try {
List<DeviceChannel> deviceChannelList = new ArrayList<>();
for (GbStream gbStream : gbStreams) { for (GbStream gbStream : gbStreams) {
platformGbStreamMapper.delByAppAndStream(gbStream.getApp(), gbStream.getStream()); platformGbStreamMapper.delByAppAndStream(gbStream.getApp(), gbStream.getStream());
DeviceChannel deviceChannel = new DeviceChannel();
deviceChannel.setChannelId(gbStream.getGbId());
deviceChannelList.add(deviceChannel);
eventPublisher.catalogEventPublish(platformId, deviceChannel, CatalogEvent.DEL);
} }
dataSourceTransactionManager.commit(transactionStatus); //手动提交 dataSourceTransactionManager.commit(transactionStatus); //手动提交
result = true; result = true;
}catch (Exception e) { }catch (Exception e) {
@ -83,4 +132,27 @@ public class GbStreamServiceImpl implements IGbStreamService {
} }
return result; return result;
} }
@Override
public void sendCatalogMsg(GbStream gbStream, String type) {
List<GbStream> gbStreams = new ArrayList<>();
if (gbStream.getGbId() != null) {
gbStreams.add(gbStream);
}else {
StreamProxyItem streamProxyItem = gbStreamMapper.selectOne(gbStream.getApp(), gbStream.getStream());
if (streamProxyItem != null && streamProxyItem.getGbId() != null){
gbStreams.add(streamProxyItem);
}
}
if (gbStreams.size() > 0) {
for (GbStream gs : gbStreams) {
List<ParentPlatform> parentPlatforms = platformGbStreamMapper.selectByAppAndStream(gs.getApp(), gs.getStream());
if (parentPlatforms.size() > 0) {
for (ParentPlatform parentPlatform : parentPlatforms) {
eventPublisher.catalogEventPublishForStream(parentPlatform.getServerGBId(), gs, type);
}
}
}
}
}
} }

22
src/main/java/com/genersoft/iot/vmp/service/impl/RedisGPSMsgListener.java

@ -0,0 +1,22 @@
package com.genersoft.iot.vmp.service.impl;
import com.alibaba.fastjson.JSON;
import com.genersoft.iot.vmp.service.bean.GPSMsgInfo;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.Message;
import org.springframework.data.redis.connection.MessageListener;
import org.springframework.stereotype.Component;
@Component
public class RedisGPSMsgListener implements MessageListener {
@Autowired
private IRedisCatchStorage redisCatchStorage;
@Override
public void onMessage(Message message, byte[] bytes) {
GPSMsgInfo gpsMsgInfo = JSON.parseObject(message.getBody(), GPSMsgInfo.class);
redisCatchStorage.updateGpsMsgInfo(gpsMsgInfo);
}
}

27
src/main/java/com/genersoft/iot/vmp/service/impl/StreamProxyServiceImpl.java

@ -2,9 +2,13 @@ package com.genersoft.iot.vmp.service.impl;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import com.genersoft.iot.vmp.common.StreamInfo; import com.genersoft.iot.vmp.common.StreamInfo;
import com.genersoft.iot.vmp.conf.SipConfig;
import com.genersoft.iot.vmp.conf.UserSetup; import com.genersoft.iot.vmp.conf.UserSetup;
import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
import com.genersoft.iot.vmp.gb28181.bean.GbStream; import com.genersoft.iot.vmp.gb28181.bean.GbStream;
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent;
import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils; import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
import com.genersoft.iot.vmp.media.zlm.ZLMServerConfig; import com.genersoft.iot.vmp.media.zlm.ZLMServerConfig;
import com.genersoft.iot.vmp.media.zlm.dto.MediaItem; import com.genersoft.iot.vmp.media.zlm.dto.MediaItem;
@ -57,12 +61,18 @@ public class StreamProxyServiceImpl implements IStreamProxyService {
@Autowired @Autowired
private UserSetup userSetup; private UserSetup userSetup;
@Autowired
private SipConfig sipConfig;
@Autowired @Autowired
private GbStreamMapper gbStreamMapper; private GbStreamMapper gbStreamMapper;
@Autowired @Autowired
private PlatformGbStreamMapper platformGbStreamMapper; private PlatformGbStreamMapper platformGbStreamMapper;
@Autowired
private EventPublisher eventPublisher;
@Autowired @Autowired
private ParentPlatformMapper parentPlatformMapper; private ParentPlatformMapper parentPlatformMapper;
@ -130,7 +140,7 @@ public class StreamProxyServiceImpl implements IStreamProxyService {
if ( !StringUtils.isEmpty(param.getPlatformGbId()) && streamLive) { if ( !StringUtils.isEmpty(param.getPlatformGbId()) && streamLive) {
List<GbStream> gbStreams = new ArrayList<>(); List<GbStream> gbStreams = new ArrayList<>();
gbStreams.add(param); gbStreams.add(param);
if (gbStreamService.addPlatformInfo(gbStreams, param.getPlatformGbId())){ if (gbStreamService.addPlatformInfo(gbStreams, param.getPlatformGbId(), param.getCatalogId())){
result.append(", 关联国标平台[ " + param.getPlatformGbId() + " ]成功"); result.append(", 关联国标平台[ " + param.getPlatformGbId() + " ]成功");
}else { }else {
result.append(", 关联国标平台[ " + param.getPlatformGbId() + " ]失败"); result.append(", 关联国标平台[ " + param.getPlatformGbId() + " ]失败");
@ -141,10 +151,12 @@ public class StreamProxyServiceImpl implements IStreamProxyService {
if (parentPlatforms.size() > 0) { if (parentPlatforms.size() > 0) {
for (ParentPlatform parentPlatform : parentPlatforms) { for (ParentPlatform parentPlatform : parentPlatforms) {
param.setPlatformId(parentPlatform.getServerGBId()); param.setPlatformId(parentPlatform.getServerGBId());
param.setCatalogId(parentPlatform.getCatalogId());
String stream = param.getStream(); String stream = param.getStream();
StreamProxyItem streamProxyItems = platformGbStreamMapper.selectOne(param.getApp(), stream, parentPlatform.getServerGBId()); StreamProxyItem streamProxyItems = platformGbStreamMapper.selectOne(param.getApp(), stream, parentPlatform.getServerGBId());
if (streamProxyItems == null) { if (streamProxyItems == null) {
platformGbStreamMapper.add(param); platformGbStreamMapper.add(param);
eventPublisher.catalogEventPublishForStream(parentPlatform.getServerGBId(), param, CatalogEvent.ADD);
} }
} }
} }
@ -193,6 +205,7 @@ public class StreamProxyServiceImpl implements IStreamProxyService {
public void del(String app, String stream) { public void del(String app, String stream) {
StreamProxyItem streamProxyItem = videoManagerStorager.queryStreamProxy(app, stream); StreamProxyItem streamProxyItem = videoManagerStorager.queryStreamProxy(app, stream);
if (streamProxyItem != null) { if (streamProxyItem != null) {
gbStreamService.sendCatalogMsg(streamProxyItem, CatalogEvent.DEL);
videoManagerStorager.deleteStreamProxy(app, stream); videoManagerStorager.deleteStreamProxy(app, stream);
JSONObject jsonObject = removeStreamProxyFromZlm(streamProxyItem); JSONObject jsonObject = removeStreamProxyFromZlm(streamProxyItem);
if (jsonObject != null && jsonObject.getInteger("code") == 0) { if (jsonObject != null && jsonObject.getInteger("code") == 0) {
@ -278,18 +291,18 @@ public class StreamProxyServiceImpl implements IStreamProxyService {
String type = "PULL"; String type = "PULL";
// 发送redis消息 // 发送redis消息
List<StreamInfo> streamInfoList = redisCatchStorage.getStreams(mediaServerId, type); List<MediaItem> mediaItems = redisCatchStorage.getStreams(mediaServerId, type);
if (streamInfoList.size() > 0) { if (mediaItems.size() > 0) {
for (StreamInfo streamInfo : streamInfoList) { for (MediaItem mediaItem : mediaItems) {
JSONObject jsonObject = new JSONObject(); JSONObject jsonObject = new JSONObject();
jsonObject.put("serverId", userSetup.getServerId()); jsonObject.put("serverId", userSetup.getServerId());
jsonObject.put("app", streamInfo.getApp()); jsonObject.put("app", mediaItem.getApp());
jsonObject.put("stream", streamInfo.getStreamId()); jsonObject.put("stream", mediaItem.getStream());
jsonObject.put("register", false); jsonObject.put("register", false);
jsonObject.put("mediaServerId", mediaServerId); jsonObject.put("mediaServerId", mediaServerId);
redisCatchStorage.sendStreamChangeMsg(type, jsonObject); redisCatchStorage.sendStreamChangeMsg(type, jsonObject);
// 移除redis内流的信息 // 移除redis内流的信息
redisCatchStorage.removeStream(mediaServerId, type, streamInfo.getApp(), streamInfo.getStreamId()); redisCatchStorage.removeStream(mediaServerId, type, mediaItem.getApp(), mediaItem.getStream());
} }
} }
} }

96
src/main/java/com/genersoft/iot/vmp/service/impl/StreamPushServiceImpl.java

@ -5,12 +5,16 @@ import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference; import com.alibaba.fastjson.TypeReference;
import com.genersoft.iot.vmp.common.StreamInfo; import com.genersoft.iot.vmp.common.StreamInfo;
import com.genersoft.iot.vmp.conf.UserSetup; import com.genersoft.iot.vmp.conf.UserSetup;
import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
import com.genersoft.iot.vmp.gb28181.bean.GbStream; import com.genersoft.iot.vmp.gb28181.bean.GbStream;
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent;
import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe; import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe;
import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils; import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
import com.genersoft.iot.vmp.media.zlm.ZLMServerConfig; import com.genersoft.iot.vmp.media.zlm.ZLMServerConfig;
import com.genersoft.iot.vmp.media.zlm.dto.*; import com.genersoft.iot.vmp.media.zlm.dto.*;
import com.genersoft.iot.vmp.service.IGbStreamService;
import com.genersoft.iot.vmp.service.IMediaServerService; import com.genersoft.iot.vmp.service.IMediaServerService;
import com.genersoft.iot.vmp.service.IStreamPushService; import com.genersoft.iot.vmp.service.IStreamPushService;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage; import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
@ -18,6 +22,7 @@ import com.genersoft.iot.vmp.storager.dao.GbStreamMapper;
import com.genersoft.iot.vmp.storager.dao.ParentPlatformMapper; import com.genersoft.iot.vmp.storager.dao.ParentPlatformMapper;
import com.genersoft.iot.vmp.storager.dao.PlatformGbStreamMapper; import com.genersoft.iot.vmp.storager.dao.PlatformGbStreamMapper;
import com.genersoft.iot.vmp.storager.dao.StreamPushMapper; import com.genersoft.iot.vmp.storager.dao.StreamPushMapper;
import com.genersoft.iot.vmp.vmanager.bean.StreamPushExcelDto;
import com.github.pagehelper.PageHelper; import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo; import com.github.pagehelper.PageInfo;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@ -41,6 +46,12 @@ public class StreamPushServiceImpl implements IStreamPushService {
@Autowired @Autowired
private PlatformGbStreamMapper platformGbStreamMapper; private PlatformGbStreamMapper platformGbStreamMapper;
@Autowired
private IGbStreamService gbStreamService;
@Autowired
private EventPublisher eventPublisher;
@Autowired @Autowired
private ZLMRESTfulUtils zlmresTfulUtils; private ZLMRESTfulUtils zlmresTfulUtils;
@ -115,24 +126,38 @@ public class StreamPushServiceImpl implements IStreamPushService {
stream.setStreamType("push"); stream.setStreamType("push");
stream.setStatus(true); stream.setStatus(true);
int add = gbStreamMapper.add(stream); int add = gbStreamMapper.add(stream);
// 查找开启了全部直播流共享的上级平台 // 查找开启了全部直播流共享的上级平台
List<ParentPlatform> parentPlatforms = parentPlatformMapper.selectAllAhareAllLiveStream(); List<ParentPlatform> parentPlatforms = parentPlatformMapper.selectAllAhareAllLiveStream();
if (parentPlatforms.size() > 0) { if (parentPlatforms.size() > 0) {
for (ParentPlatform parentPlatform : parentPlatforms) { for (ParentPlatform parentPlatform : parentPlatforms) {
stream.setCatalogId(parentPlatform.getCatalogId());
stream.setPlatformId(parentPlatform.getServerGBId()); stream.setPlatformId(parentPlatform.getServerGBId());
String streamId = stream.getStream(); String streamId = stream.getStream();
StreamProxyItem streamProxyItems = platformGbStreamMapper.selectOne(stream.getApp(), streamId, parentPlatform.getServerGBId()); StreamProxyItem streamProxyItem = platformGbStreamMapper.selectOne(stream.getApp(), streamId, parentPlatform.getServerGBId());
if (streamProxyItems == null) { if (streamProxyItem == null) {
platformGbStreamMapper.add(stream); platformGbStreamMapper.add(stream);
eventPublisher.catalogEventPublishForStream(parentPlatform.getServerGBId(), stream, CatalogEvent.ADD);
}else {
if (!streamProxyItem.getGbId().equals(stream.getGbId())) {
// 此流使用另一个国标Id已经与该平台关联,移除此记录
platformGbStreamMapper.delByAppAndStreamAndPlatform(stream.getApp(), streamId, parentPlatform.getServerGBId());
platformGbStreamMapper.add(stream);
eventPublisher.catalogEventPublishForStream(parentPlatform.getServerGBId(), stream, CatalogEvent.ADD);
}
} }
} }
} }
return add > 0; return add > 0;
} }
@Override @Override
public boolean removeFromGB(GbStream stream) { public boolean removeFromGB(GbStream stream) {
// 判断是否需要发送事件
gbStreamService.sendCatalogMsg(stream, CatalogEvent.DEL);
int del = gbStreamMapper.del(stream.getApp(), stream.getStream()); int del = gbStreamMapper.del(stream.getApp(), stream.getStream());
platformGbStreamMapper.delByAppAndStream(stream.getApp(), stream.getStream());
MediaServerItem mediaInfo = mediaServerService.getOne(stream.getMediaServerId()); MediaServerItem mediaInfo = mediaServerService.getOne(stream.getMediaServerId());
JSONObject mediaList = zlmresTfulUtils.getMediaList(mediaInfo, stream.getApp(), stream.getStream()); JSONObject mediaList = zlmresTfulUtils.getMediaList(mediaInfo, stream.getApp(), stream.getStream());
if (mediaList == null) { if (mediaList == null) {
@ -151,6 +176,8 @@ public class StreamPushServiceImpl implements IStreamPushService {
@Override @Override
public boolean stop(String app, String streamId) { public boolean stop(String app, String streamId) {
StreamPushItem streamPushItem = streamPushMapper.selectOne(app, streamId); StreamPushItem streamPushItem = streamPushMapper.selectOne(app, streamId);
gbStreamService.sendCatalogMsg(streamPushItem, CatalogEvent.DEL);
int delStream = streamPushMapper.del(app, streamId); int delStream = streamPushMapper.del(app, streamId);
gbStreamMapper.del(app, streamId); gbStreamMapper.del(app, streamId);
platformGbStreamMapper.delByAppAndStream(app, streamId); platformGbStreamMapper.delByAppAndStream(app, streamId);
@ -172,16 +199,16 @@ public class StreamPushServiceImpl implements IStreamPushService {
List<StreamPushItem> pushList = getPushList(mediaServerId); List<StreamPushItem> pushList = getPushList(mediaServerId);
Map<String, StreamPushItem> pushItemMap = new HashMap<>(); Map<String, StreamPushItem> pushItemMap = new HashMap<>();
// redis记录 // redis记录
List<StreamInfo> streamInfoPushList = redisCatchStorage.getStreams(mediaServerId, "PUSH"); List<MediaItem> mediaItems = redisCatchStorage.getStreams(mediaServerId, "PUSH");
Map<String, StreamInfo> streamInfoPushItemMap = new HashMap<>(); Map<String, MediaItem> streamInfoPushItemMap = new HashMap<>();
if (pushList.size() > 0) { if (pushList.size() > 0) {
for (StreamPushItem streamPushItem : pushList) { for (StreamPushItem streamPushItem : pushList) {
pushItemMap.put(streamPushItem.getApp() + streamPushItem.getStream(), streamPushItem); pushItemMap.put(streamPushItem.getApp() + streamPushItem.getStream(), streamPushItem);
} }
} }
if (streamInfoPushList.size() > 0) { if (mediaItems.size() > 0) {
for (StreamInfo streamInfo : streamInfoPushList) { for (MediaItem mediaItem : mediaItems) {
streamInfoPushItemMap.put(streamInfo.getApp() + streamInfo.getStreamId(), streamInfo); streamInfoPushItemMap.put(mediaItem.getApp() + mediaItem.getStream(), mediaItem);
} }
} }
zlmresTfulUtils.getMediaList(mediaServerItem, (mediaList ->{ zlmresTfulUtils.getMediaList(mediaServerItem, (mediaList ->{
@ -220,19 +247,19 @@ public class StreamPushServiceImpl implements IStreamPushService {
} }
} }
Collection<StreamInfo> offlineStreamInfoItems = streamInfoPushItemMap.values(); Collection<MediaItem> offlineMediaItemList = streamInfoPushItemMap.values();
if (offlineStreamInfoItems.size() > 0) { if (offlineMediaItemList.size() > 0) {
String type = "PUSH"; String type = "PUSH";
for (StreamInfo offlineStreamInfoItem : offlineStreamInfoItems) { for (MediaItem offlineMediaItem : offlineMediaItemList) {
JSONObject jsonObject = new JSONObject(); JSONObject jsonObject = new JSONObject();
jsonObject.put("serverId", userSetup.getServerId()); jsonObject.put("serverId", userSetup.getServerId());
jsonObject.put("app", offlineStreamInfoItem.getApp()); jsonObject.put("app", offlineMediaItem.getApp());
jsonObject.put("stream", offlineStreamInfoItem.getStreamId()); jsonObject.put("stream", offlineMediaItem.getStream());
jsonObject.put("register", false); jsonObject.put("register", false);
jsonObject.put("mediaServerId", mediaServerId); jsonObject.put("mediaServerId", mediaServerId);
redisCatchStorage.sendStreamChangeMsg(type, jsonObject); redisCatchStorage.sendStreamChangeMsg(type, jsonObject);
// 移除redis内流的信息 // 移除redis内流的信息
redisCatchStorage.removeStream(mediaServerItem.getId(), "PUSH", offlineStreamInfoItem.getApp(), offlineStreamInfoItem.getStreamId()); redisCatchStorage.removeStream(mediaServerItem.getId(), "PUSH", offlineMediaItem.getApp(), offlineMediaItem.getStream());
} }
} }
})); }));
@ -249,15 +276,15 @@ public class StreamPushServiceImpl implements IStreamPushService {
// 发送流停止消息 // 发送流停止消息
String type = "PUSH"; String type = "PUSH";
// 发送redis消息 // 发送redis消息
List<StreamInfo> streamInfoList = redisCatchStorage.getStreams(mediaServerId, type); List<MediaItem> streamInfoList = redisCatchStorage.getStreams(mediaServerId, type);
if (streamInfoList.size() > 0) { if (streamInfoList.size() > 0) {
for (StreamInfo streamInfo : streamInfoList) { for (MediaItem mediaItem : streamInfoList) {
// 移除redis内流的信息 // 移除redis内流的信息
redisCatchStorage.removeStream(mediaServerId, type, streamInfo.getApp(), streamInfo.getStreamId()); redisCatchStorage.removeStream(mediaServerId, type, mediaItem.getApp(), mediaItem.getStream());
JSONObject jsonObject = new JSONObject(); JSONObject jsonObject = new JSONObject();
jsonObject.put("serverId", userSetup.getServerId()); jsonObject.put("serverId", userSetup.getServerId());
jsonObject.put("app", streamInfo.getApp()); jsonObject.put("app", mediaItem.getApp());
jsonObject.put("stream", streamInfo.getStreamId()); jsonObject.put("stream", mediaItem.getStream());
jsonObject.put("register", false); jsonObject.put("register", false);
jsonObject.put("mediaServerId", mediaServerId); jsonObject.put("mediaServerId", mediaServerId);
redisCatchStorage.sendStreamChangeMsg(type, jsonObject); redisCatchStorage.sendStreamChangeMsg(type, jsonObject);
@ -295,4 +322,37 @@ public class StreamPushServiceImpl implements IStreamPushService {
} }
return true; return true;
} }
@Override
public void batchAdd(List<StreamPushItem> streamPushItems) {
streamPushMapper.addAll(streamPushItems);
gbStreamMapper.batchAdd(streamPushItems);
// 查找开启了全部直播流共享的上级平台
List<ParentPlatform> parentPlatforms = parentPlatformMapper.selectAllAhareAllLiveStream();
if (parentPlatforms.size() > 0) {
for (StreamPushItem stream : streamPushItems) {
for (ParentPlatform parentPlatform : parentPlatforms) {
stream.setCatalogId(parentPlatform.getCatalogId());
stream.setPlatformId(parentPlatform.getServerGBId());
String streamId = stream.getStream();
StreamProxyItem streamProxyItem = platformGbStreamMapper.selectOne(stream.getApp(), streamId, parentPlatform.getServerGBId());
if (streamProxyItem == null) {
platformGbStreamMapper.add(stream);
eventPublisher.catalogEventPublishForStream(parentPlatform.getServerGBId(), stream, CatalogEvent.ADD);
}else {
if (!streamProxyItem.getGbId().equals(stream.getGbId())) {
// 此流使用另一个国标Id已经与该平台关联,移除此记录
platformGbStreamMapper.delByAppAndStreamAndPlatform(stream.getApp(), streamId, parentPlatform.getServerGBId());
platformGbStreamMapper.add(stream);
eventPublisher.catalogEventPublishForStream(parentPlatform.getServerGBId(), stream, CatalogEvent.ADD);
stream.setGbId(streamProxyItem.getGbId());
eventPublisher.catalogEventPublishForStream(parentPlatform.getServerGBId(), stream, CatalogEvent.DEL);
}
}
}
}
}
}
} }

85
src/main/java/com/genersoft/iot/vmp/service/impl/StreamPushUploadFileHandler.java

@ -0,0 +1,85 @@
package com.genersoft.iot.vmp.service.impl;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem;
import com.genersoft.iot.vmp.service.IStreamPushService;
import com.genersoft.iot.vmp.vmanager.bean.StreamPushExcelDto;
import org.springframework.util.StringUtils;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class StreamPushUploadFileHandler extends AnalysisEventListener<StreamPushExcelDto> {
private ErrorDataHandler errorDataHandler;
private IStreamPushService pushService;
private String defaultMediaServerId;
private List<StreamPushItem> streamPushItems = new ArrayList<>();
private Set<String> streamPushStreamSet = new HashSet<>();
private Set<String> streamPushGBSet = new HashSet<>();
private List<String> errorStreamList = new ArrayList<>();
private List<String> errorGBList = new ArrayList<>();
public StreamPushUploadFileHandler(IStreamPushService pushService, String defaultMediaServerId, ErrorDataHandler errorDataHandler) {
this.pushService = pushService;
this.defaultMediaServerId = defaultMediaServerId;
this.errorDataHandler = errorDataHandler;
}
public interface ErrorDataHandler{
void handle(List<String> streams, List<String> gbId);
}
@Override
public void invoke(StreamPushExcelDto streamPushExcelDto, AnalysisContext analysisContext) {
if (StringUtils.isEmpty(streamPushExcelDto.getApp())
|| StringUtils.isEmpty(streamPushExcelDto.getStream())
|| StringUtils.isEmpty(streamPushExcelDto.getGbId())) {
return;
}
if (streamPushGBSet.contains(streamPushExcelDto.getGbId())) {
errorGBList.add(streamPushExcelDto.getGbId());
}
if (streamPushStreamSet.contains(streamPushExcelDto.getApp() + streamPushExcelDto.getStream())) {
errorStreamList.add(streamPushExcelDto.getApp() + "/" + streamPushExcelDto.getStream());
}
if (streamPushGBSet.contains(streamPushExcelDto.getGbId()) || streamPushStreamSet.contains(streamPushExcelDto.getApp() + streamPushExcelDto.getStream())) {
return;
}
StreamPushItem streamPushItem = new StreamPushItem();
streamPushItem.setApp(streamPushExcelDto.getApp());
streamPushItem.setStream(streamPushExcelDto.getStream());
streamPushItem.setGbId(streamPushExcelDto.getGbId());
streamPushItem.setStatus(false);
streamPushItem.setStreamType("push");
streamPushItem.setCreateStamp(System.currentTimeMillis()/1000);
streamPushItem.setMediaServerId(defaultMediaServerId);
streamPushItem.setName(streamPushExcelDto.getName());
streamPushItem.setOriginType(2);
streamPushItem.setOriginTypeStr("rtsp_push");
streamPushItem.setTotalReaderCount("0");
streamPushItems.add(streamPushItem);
streamPushGBSet.add(streamPushExcelDto.getGbId());
streamPushStreamSet.add(streamPushExcelDto.getApp()+streamPushExcelDto.getStream());
if (streamPushItems.size() > 300) {
pushService.batchAdd(streamPushItems);
// 存储完成清理 list
streamPushItems.clear();
}
}
@Override
public void doAfterAllAnalysed(AnalysisContext analysisContext) {
// 这里也要保存数据,确保最后遗留的数据也存储到数据库
if (streamPushItems.size() > 0) {
pushService.batchAdd(streamPushItems);
}
streamPushGBSet.clear();
streamPushStreamSet.clear();
errorDataHandler.handle(errorStreamList, errorGBList);
}
}

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

@ -2,11 +2,11 @@ package com.genersoft.iot.vmp.storager;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import com.genersoft.iot.vmp.common.StreamInfo; import com.genersoft.iot.vmp.common.StreamInfo;
import com.genersoft.iot.vmp.gb28181.bean.Device; import com.genersoft.iot.vmp.gb28181.bean.*;
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; import com.genersoft.iot.vmp.media.zlm.dto.MediaItem;
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatformCatch;
import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; 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.GPSMsgInfo;
import com.genersoft.iot.vmp.service.bean.ThirdPartyGB; import com.genersoft.iot.vmp.service.bean.ThirdPartyGB;
import java.util.List; import java.util.List;
@ -145,7 +145,7 @@ public interface IRedisCatchStorage {
* @param app * @param app
* @param streamId * @param streamId
*/ */
void addStream(MediaServerItem mediaServerItem, String type, String app, String streamId, StreamInfo streamInfo); void addStream(MediaServerItem mediaServerItem, String type, String app, String streamId, MediaItem item);
/** /**
* 移除流信息从redis * 移除流信息从redis
@ -177,7 +177,7 @@ public interface IRedisCatchStorage {
*/ */
ThirdPartyGB queryMemberNoGBId(String queryKey); ThirdPartyGB queryMemberNoGBId(String queryKey);
List<StreamInfo> getStreams(String mediaServerId, String pull); List<MediaItem> getStreams(String mediaServerId, String pull);
/** /**
* 将device信息写入redis * 将device信息写入redis
@ -185,10 +185,33 @@ public interface IRedisCatchStorage {
*/ */
void updateDevice(Device device); void updateDevice(Device device);
void removeDevice(String deviceId);
/** /**
* 获取Device * 获取Device
*/ */
Device getDevice(String deviceId); Device getDevice(String deviceId);
void resetAllCSEQ(); void resetAllCSEQ();
void updateGpsMsgInfo(GPSMsgInfo gpsMsgInfo);
GPSMsgInfo getGpsMsgInfo(String gbId);
List<GPSMsgInfo> getAllGpsMsgInfo();
Long getSN(String method);
void resetAllSN();
void updateSubscribe(String key, SubscribeInfo subscribeInfo);
SubscribeInfo getSubscribe(String key);
void delSubscribe(String key);
MediaItem getStreamInfo(String app, String streamId, String mediaServerId);
List<SubscribeInfo> getAllSubscribe();
List<String> getAllSubscribePlatform();
} }

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

@ -4,6 +4,7 @@ import com.genersoft.iot.vmp.gb28181.bean.*;
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem; import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem;
import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem; import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem;
import com.genersoft.iot.vmp.service.bean.GPSMsgInfo;
import com.genersoft.iot.vmp.vmanager.gb28181.platform.bean.ChannelReduce; import com.genersoft.iot.vmp.vmanager.gb28181.platform.bean.ChannelReduce;
import com.github.pagehelper.PageInfo; import com.github.pagehelper.PageInfo;
@ -99,6 +100,7 @@ public interface IVideoManagerStorager {
* @return * @return
*/ */
public List<DeviceChannel> queryChannelsByDeviceId(String deviceId); public List<DeviceChannel> queryChannelsByDeviceId(String deviceId);
public List<DeviceChannel> queryOnlineChannelsByDeviceId(String deviceId);
/** /**
* 获取某个设备的通道 * 获取某个设备的通道
@ -243,7 +245,7 @@ public interface IVideoManagerStorager {
* @param channelReduces * @param channelReduces
* @return * @return
*/ */
int updateChannelForGB(String platformId, List<ChannelReduce> channelReduces); int updateChannelForGB(String platformId, List<ChannelReduce> channelReduces, String catalogId);
/** /**
* 移除上级平台的通道信息 * 移除上级平台的通道信息
@ -256,6 +258,9 @@ public interface IVideoManagerStorager {
DeviceChannel queryChannelInParentPlatform(String platformId, String channelId); DeviceChannel queryChannelInParentPlatform(String platformId, String channelId);
List<PlatformCatalog> queryChannelInParentPlatformAndCatalog(String platformId, String catalogId);
List<PlatformCatalog> queryStreamInParentPlatformAndCatalog(String platformId, String catalogId);
Device queryVideoDeviceByPlatformIdAndChannelId(String platformId, String channelId); Device queryVideoDeviceByPlatformIdAndChannelId(String platformId, String channelId);
@ -337,7 +342,7 @@ public interface IVideoManagerStorager {
* @param channelId * @param channelId
* @return * @return
*/ */
List<GbStream> queryStreamInParentPlatform(String platformId, String channelId); GbStream queryStreamInParentPlatform(String platformId, String channelId);
/** /**
* 获取平台关联的直播流 * 获取平台关联的直播流
@ -431,4 +436,38 @@ public interface IVideoManagerStorager {
* @param deviceChannelList * @param deviceChannelList
*/ */
boolean resetChannels(String deviceId, List<DeviceChannel> deviceChannelList); boolean resetChannels(String deviceId, List<DeviceChannel> deviceChannelList);
/**
* 获取目录信息
* @param platformId
* @param parentId
* @return
*/
List<PlatformCatalog> getChildrenCatalogByPlatform(String platformId, String parentId);
int addCatalog(PlatformCatalog platformCatalog);
PlatformCatalog getCatalog(String id);
int delCatalog(String id);
int updateCatalog(PlatformCatalog platformCatalog);
int setDefaultCatalog(String platformId, String catalogId);
List<PlatformCatalog> queryCatalogInPlatform(String serverGBId);
int delRelation(PlatformCatalog platformCatalog);
int updateStreamGPS(List<GPSMsgInfo> gpsMsgInfo);
List<ParentPlatform> queryPlatFormListForGBWithGBId(String channelId, List<String> platforms);
List<ParentPlatform> queryPlatFormListForStreamWithGBId(String app, String stream, List<String> platforms);
GbStream getGbStream(String app, String streamId);
void delCatalogByPlatformId(String serverGBId);
void delRelationByPlatformId(String serverGBId);
} }

59
src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceChannelMapper.java

@ -54,17 +54,22 @@ public interface DeviceChannelMapper {
int update(DeviceChannel channel); int update(DeviceChannel channel);
@Select(value = {" <script>" + @Select(value = {" <script>" +
"SELECT * FROM ( "+ "SELECT " +
" SELECT * , (SELECT count(0) FROM device_channel WHERE parentId=dc.channelId) as subCount FROM device_channel dc " + "dc1.*, " +
" WHERE dc.deviceId=#{deviceId} " + "COUNT(dc2.channelId) as subCount " +
" <if test='query != null'> AND (dc.channelId LIKE '%${query}%' OR dc.name LIKE '%${query}%' OR dc.name LIKE '%${query}%')</if> " + "from " +
" <if test='parentChannelId != null'> AND dc.parentId=#{parentChannelId} </if> " + "device_channel dc1 " +
" <if test='online == true' > AND dc.status=1</if>" + "left join device_channel dc2 on " +
" <if test='online == false' > AND dc.status=0</if>) dcr" + "dc1.channelId = dc2.parentId " +
" WHERE 1=1 " + "WHERE " +
"dc1.deviceId = #{deviceId} " +
" <if test='query != null'> AND (dc1.channelId LIKE '%${query}%' OR dc1.name LIKE '%${query}%' OR dc1.name LIKE '%${query}%')</if> " +
" <if test='parentChannelId != null'> AND dc1.parentId=#{parentChannelId} </if> " +
" <if test='online == true' > AND dc1.status=1</if>" +
" <if test='online == false' > AND dc1.status=0</if>" +
" <if test='hasSubChannel == true' > AND subCount >0</if>" + " <if test='hasSubChannel == true' > AND subCount >0</if>" +
" <if test='hasSubChannel == false' > AND subCount=0</if>" + " <if test='hasSubChannel == false' > AND subCount=0</if>" +
" ORDER BY channelId ASC" + "GROUP BY dc1.channelId " +
" </script>"}) " </script>"})
List<DeviceChannel> queryChannels(String deviceId, String parentChannelId, String query, Boolean hasSubChannel, Boolean online); List<DeviceChannel> queryChannels(String deviceId, String parentChannelId, String query, Boolean hasSubChannel, Boolean online);
@ -91,7 +96,8 @@ public interface DeviceChannelMapper {
"SELECT * FROM ( "+ "SELECT * FROM ( "+
" SELECT dc.channelId, dc.deviceId, dc.name, de.manufacturer, de.hostAddress, " + " SELECT dc.channelId, dc.deviceId, dc.name, de.manufacturer, de.hostAddress, " +
"(SELECT count(0) FROM device_channel WHERE parentId=dc.channelId) as subCount, " + "(SELECT count(0) FROM device_channel WHERE parentId=dc.channelId) as subCount, " +
"(SELECT pc.platformId FROM platform_gb_channel pc WHERE pc.deviceId=dc.deviceId AND pc.channelId = dc.channelId ) as platformId " + "(SELECT pc.platformId FROM platform_gb_channel pc WHERE pc.deviceId=dc.deviceId AND pc.channelId = dc.channelId ) as platformId, " +
"(SELECT pc.catalogId FROM platform_gb_channel pc WHERE pc.deviceId=dc.deviceId AND pc.channelId = dc.channelId ) as catalogId " +
"FROM device_channel dc " + "FROM device_channel dc " +
"LEFT JOIN device de ON dc.deviceId = de.deviceId " + "LEFT JOIN device de ON dc.deviceId = de.deviceId " +
" WHERE 1=1 " + " WHERE 1=1 " +
@ -169,19 +175,30 @@ public interface DeviceChannelMapper {
"</script>"}) "</script>"})
int batchUpdate(List<DeviceChannel> updateChannels); int batchUpdate(List<DeviceChannel> updateChannels);
@Select(value = {" <script>" + @Select(value = {" <script>" +
"SELECT * FROM ( "+ "SELECT " +
" SELECT * , (SELECT count(0) FROM device_channel WHERE parentId=dc.channelId) as subCount FROM device_channel dc " + "dc1.*, " +
" WHERE dc.deviceId=#{deviceId} " + "COUNT(dc2.channelId) as subCount " +
" <if test='query != null'> AND (dc.channelId LIKE '%${query}%' OR dc.name LIKE '%${query}%' OR dc.name LIKE '%${query}%')</if> " + "from " +
" <if test='parentChannelId != null'> AND dc.parentId=#{parentChannelId} </if> " + "device_channel dc1 " +
" <if test='online == true' > AND dc.status=1</if>" + "left join device_channel dc2 on " +
" <if test='online == false' > AND dc.status=0</if>) dcr" + "dc1.channelId = dc2.parentId " +
" WHERE 1=1 " + "WHERE " +
"dc1.deviceId = #{deviceId} " +
" <if test='query != null'> AND (dc1.channelId LIKE '%${query}%' OR dc1.name LIKE '%${query}%' OR dc1.name LIKE '%${query}%')</if> " +
" <if test='parentChannelId != null'> AND dc1.parentId=#{parentChannelId} </if> " +
" <if test='online == true' > AND dc1.status=1</if>" +
" <if test='online == false' > AND dc1.status=0</if>" +
" <if test='hasSubChannel == true' > AND subCount >0</if>" + " <if test='hasSubChannel == true' > AND subCount >0</if>" +
" <if test='hasSubChannel == false' > AND subCount=0</if>" + " <if test='hasSubChannel == false' > AND subCount=0</if>" +
" ORDER BY channelId ASC" + "GROUP BY dc1.channelId " +
" LIMIT #{limit} OFFSET #{start}" + "ORDER BY dc1.channelId ASC " +
"Limit #{limit} OFFSET #{start}" +
" </script>"}) " </script>"})
List<DeviceChannel> queryChannelsByDeviceIdWithStartAndLimit(String deviceId, String parentChannelId, String query, Boolean hasSubChannel, Boolean online, int start, int limit); List<DeviceChannel> queryChannelsByDeviceIdWithStartAndLimit(String deviceId, String parentChannelId, String query,
Boolean hasSubChannel, Boolean online, int start, int limit);
@Select("SELECT * FROM device_channel WHERE deviceId=#{deviceId} AND status=1")
List<DeviceChannel> queryOnlineChannelsByDeviceId(String deviceId);
} }

39
src/main/java/com/genersoft/iot/vmp/storager/dao/GbStreamMapper.java

@ -3,6 +3,8 @@ package com.genersoft.iot.vmp.storager.dao;
import com.genersoft.iot.vmp.gb28181.bean.GbStream; import com.genersoft.iot.vmp.gb28181.bean.GbStream;
import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem; import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem;
import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem; import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem;
import com.genersoft.iot.vmp.service.bean.GPSMsgInfo;
import com.genersoft.iot.vmp.vmanager.bean.StreamPushExcelDto;
import org.apache.ibatis.annotations.*; import org.apache.ibatis.annotations.*;
import org.springframework.stereotype.Repository; import org.springframework.stereotype.Repository;
@ -12,7 +14,7 @@ import java.util.List;
@Repository @Repository
public interface GbStreamMapper { public interface GbStreamMapper {
@Insert("INSERT INTO gb_stream (app, stream, gbId, name, " + @Insert("REPLACE INTO gb_stream (app, stream, gbId, name, " +
"longitude, latitude, streamType, mediaServerId, status) VALUES" + "longitude, latitude, streamType, mediaServerId, status) VALUES" +
"('${app}', '${stream}', '${gbId}', '${name}', " + "('${app}', '${stream}', '${gbId}', '${name}', " +
"'${longitude}', '${latitude}', '${streamType}', " + "'${longitude}', '${latitude}', '${streamType}', " +
@ -35,8 +37,10 @@ public interface GbStreamMapper {
@Delete("DELETE FROM gb_stream WHERE app=#{app} AND stream=#{stream}") @Delete("DELETE FROM gb_stream WHERE app=#{app} AND stream=#{stream}")
int del(String app, String stream); int del(String app, String stream);
@Select("SELECT gs.*, pgs.platformId FROM gb_stream gs LEFT JOIN platform_gb_stream pgs ON gs.app = pgs.app AND gs.stream = pgs.stream") @Select("SELECT gs.*, pgs.platformId AS platformId, pgs.catalogId AS catalogId FROM gb_stream gs " +
List<GbStream> selectAll(); "LEFT JOIN platform_gb_stream pgs ON gs.app = pgs.app AND gs.stream = pgs.stream " +
"WHERE pgs.platformId is null OR pgs.platformId = #{platformId}")
List<GbStream> selectAll(String platformId);
@Select("SELECT * FROM gb_stream WHERE app=#{app} AND stream=#{stream}") @Select("SELECT * FROM gb_stream WHERE app=#{app} AND stream=#{stream}")
StreamProxyItem selectOne(String app, String stream); StreamProxyItem selectOne(String app, String stream);
@ -44,32 +48,31 @@ public interface GbStreamMapper {
@Select("SELECT * FROM gb_stream WHERE gbId=#{gbId}") @Select("SELECT * FROM gb_stream WHERE gbId=#{gbId}")
List<GbStream> selectByGBId(String gbId); List<GbStream> selectByGBId(String gbId);
@Select("SELECT gs.*, pgs.platformId FROM gb_stream gs " + @Select("SELECT gs.*, pgs.platformId as platformId, pgs.catalogId as catalogId FROM gb_stream gs " +
"LEFT JOIN platform_gb_stream pgs ON gs.app = pgs.app AND gs.stream = pgs.stream " + "LEFT JOIN platform_gb_stream pgs ON gs.app = pgs.app AND gs.stream = pgs.stream " +
"WHERE gs.gbId = '${gbId}' AND pgs.platformId = '${platformId}'") "WHERE gs.gbId = '${gbId}' AND pgs.platformId = '${platformId}'")
List<GbStream> queryStreamInPlatform(String platformId, String gbId); GbStream queryStreamInPlatform(String platformId, String gbId);
@Select("SELECT gs.*, pgs.platformId FROM gb_stream gs " + @Select("SELECT gs.*, pgs.platformId as platformId, pgs.catalogId as catalogId FROM gb_stream gs " +
"LEFT JOIN platform_gb_stream pgs ON gs.app = pgs.app AND gs.stream = pgs.stream " + "LEFT JOIN platform_gb_stream pgs ON gs.app = pgs.app AND gs.stream = pgs.stream " +
"WHERE pgs.platformId = '${platformId}'") "WHERE pgs.platformId = '${platformId}'")
List<GbStream> queryGbStreamListInPlatform(String platformId); List<GbStream> queryGbStreamListInPlatform(String platformId);
@Select("SELECT gs.*, pgs.platformId as platformId, pgs.catalogId as catalogId FROM gb_stream gs LEFT JOIN platform_gb_stream pgs " +
"ON gs.app = pgs.app and gs.stream = pgs.stream WHERE pgs.app is NULL and pgs.stream is NULL")
List<GbStream> queryStreamNotInPlatform();
@Update("UPDATE gb_stream " + @Update("UPDATE gb_stream " +
"SET status=${status} " + "SET status=${status} " +
"WHERE app=#{app} AND stream=#{stream}") "WHERE app=#{app} AND stream=#{stream}")
int setStatus(String app, String stream, boolean status); int setStatus(String app, String stream, boolean status);
@Select("SELECT gs.*, pgs.platformId FROM gb_stream gs LEFT JOIN platform_gb_stream pgs ON gs.app = pgs.app AND gs.stream = pgs.stream WHERE mediaServerId=#{mediaServerId} ")
List<GbStream> selectAllByMediaServerId(String mediaServerId);
@Update("UPDATE gb_stream " + @Update("UPDATE gb_stream " +
"SET status=${status} " + "SET status=${status} " +
"WHERE mediaServerId=#{mediaServerId} ") "WHERE mediaServerId=#{mediaServerId} ")
void updateStatusByMediaServerId(String mediaServerId, boolean status); void updateStatusByMediaServerId(String mediaServerId, boolean status);
@Select("SELECT * FROM gb_stream WHERE mediaServerId=#{mediaServerId}")
void delByMediaServerId(String mediaServerId);
@Delete("DELETE FROM gb_stream WHERE streamType=#{type} AND gbId=NULL AND mediaServerId=#{mediaServerId}") @Delete("DELETE FROM gb_stream WHERE streamType=#{type} AND gbId=NULL AND mediaServerId=#{mediaServerId}")
void deleteWithoutGBId(String type, String mediaServerId); void deleteWithoutGBId(String type, String mediaServerId);
@ -82,7 +85,7 @@ public interface GbStreamMapper {
void batchDel(List<StreamProxyItem> streamProxyItemList); void batchDel(List<StreamProxyItem> streamProxyItemList);
@Insert("<script> " + @Insert("<script> " +
"insert into gb_stream " + "REPLACE into gb_stream " +
"(app, stream, gbId, name, " + "(app, stream, gbId, name, " +
"longitude, latitude, streamType, mediaServerId, status)" + "longitude, latitude, streamType, mediaServerId, status)" +
"values " + "values " +
@ -93,4 +96,14 @@ public interface GbStreamMapper {
"</foreach> " + "</foreach> " +
"</script>") "</script>")
void batchAdd(List<StreamPushItem> subList); void batchAdd(List<StreamPushItem> subList);
@Update({"<script>" +
"<foreach collection='gpsMsgInfos' item='item' separator=';'>" +
" UPDATE" +
" gb_stream" +
" SET longitude=${item.lng}, latitude=${item.lat} " +
"WHERE gbId=#{item.id}"+
"</foreach>" +
"</script>"})
int updateStreamGPS(List<GPSMsgInfo> gpsMsgInfos);
} }

14
src/main/java/com/genersoft/iot/vmp/storager/dao/ParentPlatformMapper.java

@ -15,10 +15,10 @@ public interface ParentPlatformMapper {
@Insert("INSERT INTO parent_platform (enable, name, serverGBId, serverGBDomain, serverIP, serverPort, deviceGBId, deviceIp, " + @Insert("INSERT INTO parent_platform (enable, name, serverGBId, serverGBDomain, serverIP, serverPort, deviceGBId, deviceIp, " +
" devicePort, username, password, expires, keepTimeout, transport, characterSet, ptz, rtcp, " + " devicePort, username, password, expires, keepTimeout, transport, characterSet, ptz, rtcp, " +
" status, shareAllLiveStream) " + " status, shareAllLiveStream, catalogId) " +
" VALUES (${enable}, '${name}', '${serverGBId}', '${serverGBDomain}', '${serverIP}', ${serverPort}, '${deviceGBId}', '${deviceIp}', " + " VALUES (${enable}, '${name}', '${serverGBId}', '${serverGBDomain}', '${serverIP}', ${serverPort}, '${deviceGBId}', '${deviceIp}', " +
" '${devicePort}', '${username}', '${password}', '${expires}', '${keepTimeout}', '${transport}', '${characterSet}', ${ptz}, ${rtcp}, " + " '${devicePort}', '${username}', '${password}', '${expires}', '${keepTimeout}', '${transport}', '${characterSet}', ${ptz}, ${rtcp}, " +
" ${status}, ${shareAllLiveStream})") " ${status}, ${shareAllLiveStream}, #{catalogId})")
int addParentPlatform(ParentPlatform parentPlatform); int addParentPlatform(ParentPlatform parentPlatform);
@Update("UPDATE parent_platform " + @Update("UPDATE parent_platform " +
@ -40,7 +40,8 @@ public interface ParentPlatformMapper {
"ptz=#{ptz}, " + "ptz=#{ptz}, " +
"rtcp=#{rtcp}, " + "rtcp=#{rtcp}, " +
"status=#{status}, " + "status=#{status}, " +
"shareAllLiveStream=#{shareAllLiveStream} " + "shareAllLiveStream=#{shareAllLiveStream}, " +
"catalogId=#{catalogId} " +
"WHERE id=#{id}") "WHERE id=#{id}")
int updateParentPlatform(ParentPlatform parentPlatform); int updateParentPlatform(ParentPlatform parentPlatform);
@ -74,4 +75,11 @@ public interface ParentPlatformMapper {
@Select("SELECT * FROM parent_platform WHERE shareAllLiveStream=true") @Select("SELECT * FROM parent_platform WHERE shareAllLiveStream=true")
List<ParentPlatform> selectAllAhareAllLiveStream(); List<ParentPlatform> selectAllAhareAllLiveStream();
@Update(value = {" <script>" +
"UPDATE parent_platform " +
"SET catalogId=#{catalogId}" +
"WHERE serverGBId=#{platformId}"+
"</script>"})
int setDefaultCatalog(String platformId, String catalogId);
} }

44
src/main/java/com/genersoft/iot/vmp/storager/dao/PlatformCatalogMapper.java

@ -0,0 +1,44 @@
package com.genersoft.iot.vmp.storager.dao;
import com.genersoft.iot.vmp.gb28181.bean.GbStream;
import com.genersoft.iot.vmp.gb28181.bean.PlatformCatalog;
import com.genersoft.iot.vmp.gb28181.bean.PlatformGbStream;
import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem;
import org.apache.ibatis.annotations.*;
import org.springframework.stereotype.Repository;
import java.util.List;
@Mapper
@Repository
public interface PlatformCatalogMapper {
@Insert("INSERT INTO platform_catalog (id, name, platformId, parentId) VALUES" +
"(#{id}, #{name}, #{platformId}, #{parentId})")
int add(PlatformCatalog platformCatalog);
@Delete("DELETE FROM platform_catalog WHERE id=#{id}")
int del(String id);
@Delete("DELETE FROM platform_catalog WHERE platformId=#{platformId}")
int delByPlatformId(String platformId);
@Select("SELECT pc.*, count(pc2.id) as childrenCount FROM platform_catalog pc " +
"left join platform_catalog pc2 on pc.id = pc2.parentId " +
"WHERE pc.parentId=#{parentId} AND pc.platformId=#{platformId} group by pc.id")
List<PlatformCatalog> selectByParentId(String platformId, String parentId);
@Select("SELECT *, (SELECT COUNT(1) from platform_catalog where parentId = pc.id) as childrenCount FROM platform_catalog pc WHERE pc.id=#{id}")
PlatformCatalog select(String id);
@Update(value = {" <script>" +
"UPDATE platform_catalog " +
"SET name=#{name}" +
"WHERE id=#{id}"+
"</script>"})
int update(PlatformCatalog platformCatalog);
@Select("SELECT *, (SELECT COUNT(1) from platform_catalog where parentId = pc.id) as childrenCount FROM platform_catalog pc WHERE pc.platformId=#{platformId}")
List<PlatformCatalog> selectByPlatForm(String platformId);
}

41
src/main/java/com/genersoft/iot/vmp/storager/dao/PlatformChannelMapper.java

@ -2,6 +2,8 @@ package com.genersoft.iot.vmp.storager.dao;
import com.genersoft.iot.vmp.gb28181.bean.Device; import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
import com.genersoft.iot.vmp.gb28181.bean.PlatformCatalog;
import com.genersoft.iot.vmp.vmanager.gb28181.platform.bean.ChannelReduce; import com.genersoft.iot.vmp.vmanager.gb28181.platform.bean.ChannelReduce;
import org.apache.ibatis.annotations.Delete; import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert; import org.apache.ibatis.annotations.Insert;
@ -25,9 +27,9 @@ public interface PlatformChannelMapper {
List<String> findChannelRelatedPlatform(String platformId, List<String> deviceAndChannelIds); List<String> findChannelRelatedPlatform(String platformId, List<String> deviceAndChannelIds);
@Insert("<script> "+ @Insert("<script> "+
"INSERT INTO platform_gb_channel (channelId, deviceId, platformId, deviceAndChannelId) VALUES" + "INSERT INTO platform_gb_channel (channelId, deviceId, platformId, deviceAndChannelId, catalogId) VALUES" +
"<foreach collection='channelReducesToAdd' item='item' separator=','>" + "<foreach collection='channelReducesToAdd' item='item' separator=','>" +
" ('${item.channelId}','${item.deviceId}', '${platformId}', '${item.deviceId}_${item.channelId}' )" + " ('${item.channelId}','${item.deviceId}', '${platformId}', '${item.deviceId}_${item.channelId}' , '${item.catalogId}' )" +
"</foreach>" + "</foreach>" +
"</script>") "</script>")
int addChannels(String platformId, List<ChannelReduce> channelReducesToAdd); int addChannels(String platformId, List<ChannelReduce> channelReducesToAdd);
@ -54,6 +56,41 @@ public interface PlatformChannelMapper {
"platformId='${platformId}' AND channelId='${channelId}' ) AND channelId='${channelId}'") "platformId='${platformId}' AND channelId='${channelId}' ) AND channelId='${channelId}'")
DeviceChannel queryChannelInParentPlatform(String platformId, String channelId); DeviceChannel queryChannelInParentPlatform(String platformId, String channelId);
@Select("select dc.channelId as id, dc.name as name, pgc.platformId as platformId, pgc.catalogId as parentId, 0 as childrenCount, 1 as type " +
"from device_channel dc left join platform_gb_channel pgc on dc.deviceId = pgc.deviceId and dc.channelId = pgc.channelId " +
"where pgc.platformId=#{platformId} and pgc.catalogId=#{catalogId}")
List<PlatformCatalog> queryChannelInParentPlatformAndCatalog(String platformId, String catalogId);
@Select("SELECT * FROM device WHERE deviceId = (SELECT deviceId FROM platform_gb_channel WHERE platformId='${platformId}' AND channelId='${channelId}')") @Select("SELECT * FROM device WHERE deviceId = (SELECT deviceId FROM platform_gb_channel WHERE platformId='${platformId}' AND channelId='${channelId}')")
Device queryVideoDeviceByPlatformIdAndChannelId(String platformId, String channelId); Device queryVideoDeviceByPlatformIdAndChannelId(String platformId, String channelId);
@Delete("<script> "+
"DELETE FROM platform_gb_channel WHERE catalogId=#{id}" +
"</script>")
int delByCatalogId(String id);
@Delete("<script> "+
"DELETE FROM platform_gb_channel WHERE catalogId=#{parentId} AND platformId=#{platformId} AND channelId=#{id}" +
"</script>")
int delByCatalogIdAndChannelIdAndPlatformId(PlatformCatalog platformCatalog);
@Select("<script> " +
"SELECT " +
"pp.* " +
"FROM " +
"parent_platform pp " +
"left join platform_gb_channel pgc on " +
"pp.serverGBId = pgc.platformId " +
"WHERE " +
"pgc.channelId = #{channelId} and pp.status = true " +
"AND pp.serverGBId IN" +
"<foreach collection='platforms' item='item' open='(' separator=',' close=')' > #{item}</foreach>" +
"</script> ")
List<ParentPlatform> queryPlatFormListForGBWithGBId(String channelId, List<String> platforms);
@Delete("<script> " +
"DELETE FROM platform_gb_channel WHERE platformId=#{serverGBId}" +
"</script>")
void delByPlatformId(String serverGBId);
} }

58
src/main/java/com/genersoft/iot/vmp/storager/dao/PlatformGbStreamMapper.java

@ -1,5 +1,8 @@
package com.genersoft.iot.vmp.storager.dao; package com.genersoft.iot.vmp.storager.dao;
import com.genersoft.iot.vmp.gb28181.bean.GbStream;
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
import com.genersoft.iot.vmp.gb28181.bean.PlatformCatalog;
import com.genersoft.iot.vmp.gb28181.bean.PlatformGbStream; import com.genersoft.iot.vmp.gb28181.bean.PlatformGbStream;
import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem; import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem;
import org.apache.ibatis.annotations.*; import org.apache.ibatis.annotations.*;
@ -12,8 +15,8 @@ import java.util.List;
@Repository @Repository
public interface PlatformGbStreamMapper { public interface PlatformGbStreamMapper {
@Insert("INSERT INTO platform_gb_stream (app, stream, platformId) VALUES" + @Insert("REPLACE INTO platform_gb_stream (app, stream, platformId, catalogId) VALUES" +
"('${app}', '${stream}', '${platformId}')") "('${app}', '${stream}', '${platformId}', '${catalogId}')")
int add(PlatformGbStream platformGbStream); int add(PlatformGbStream platformGbStream);
@Delete("DELETE FROM platform_gb_stream WHERE app=#{app} AND stream=#{stream}") @Delete("DELETE FROM platform_gb_stream WHERE app=#{app} AND stream=#{stream}")
@ -22,9 +25,54 @@ public interface PlatformGbStreamMapper {
@Delete("DELETE FROM platform_gb_stream WHERE platformId=#{platformId}") @Delete("DELETE FROM platform_gb_stream WHERE platformId=#{platformId}")
int delByPlatformId(String platformId); int delByPlatformId(String platformId);
@Select("SELECT * FROM platform_gb_stream WHERE app=#{app} AND stream=#{stream}") @Select("SELECT " +
List<StreamProxyItem> selectByAppAndStream(String app, String stream); "pp.* " +
"FROM " +
"platform_gb_stream pgs " +
"LEFT JOIN parent_platform pp ON pp.serverGBId = pgs.platformId " +
"WHERE " +
"pgs.app =#{app} " +
"AND pgs.stream =#{stream} " +
"GROUP BY pp.serverGBId")
List<ParentPlatform> selectByAppAndStream(String app, String stream);
@Select("SELECT * FROM platform_gb_stream WHERE app=#{app} AND stream=#{stream} AND platformId=#{serverGBId}") @Select("SELECT pgs.*, gs.gbId FROM platform_gb_stream pgs " +
"LEFT JOIN gb_stream gs ON pgs.app = gs.app AND pgs.stream = gs.stream " +
"WHERE pgs.app=#{app} AND pgs.stream=#{stream} AND pgs.platformId=#{serverGBId}")
StreamProxyItem selectOne(String app, String stream, String serverGBId); StreamProxyItem selectOne(String app, String stream, String serverGBId);
@Select("select gs.* \n" +
"from gb_stream gs\n" +
" left join platform_gb_stream pgs\n" +
" on gs.app = pgs.app and gs.stream = pgs.stream\n" +
"where pgs.platformId=#{platformId} and pgs.catalogId=#{catalogId}")
List<GbStream> queryChannelInParentPlatformAndCatalog(String platformId, String catalogId);
@Select("select gs.gbId as id, gs.name as name, pgs.platformId as platformId, pgs.catalogId as catalogId , 0 as childrenCount, 2 as type\n" +
"from gb_stream gs\n" +
" left join platform_gb_stream pgs\n" +
" on gs.app = pgs.app and gs.stream = pgs.stream\n" +
"where pgs.platformId=#{platformId} and pgs.catalogId=#{catalogId}")
List<PlatformCatalog> queryChannelInParentPlatformAndCatalogForCatalog(String platformId, String catalogId);
@Delete("DELETE FROM platform_gb_stream WHERE catalogId=#{id}")
int delByCatalogId(String id);
@Select("<script> " +
"SELECT " +
"pp.* " +
"FROM " +
"parent_platform pp " +
"left join platform_gb_stream pgs on " +
"pp.serverGBId = pgs.platformId " +
"WHERE " +
"pgs.app = #{app} " +
"AND pgs.stream = #{stream}" +
"AND pp.serverGBId IN" +
"<foreach collection='platforms' item='item' open='(' separator=',' close=')' > #{item}</foreach>" +
"</script> ")
List<ParentPlatform> queryPlatFormListForGBWithGBId(String app, String stream, List<String> platforms);
@Select("SELECT * FROM platform_gb_stream WHERE app=#{app} AND stream=#{stream} AND platformId=#{platformId}")
int delByAppAndStreamAndPlatform(String app, String streamId, String platformId);
} }

6
src/main/java/com/genersoft/iot/vmp/storager/dao/StreamPushMapper.java

@ -40,7 +40,7 @@ public interface StreamPushMapper {
"</script>") "</script>")
int delAll(List<StreamPushItem> streamPushItems); int delAll(List<StreamPushItem> streamPushItems);
@Select("SELECT st.*, pgs.gbId, pgs.status, pgs.name, pgs.longitude, pgs.latitude FROM stream_push st LEFT JOIN gb_stream pgs on st.app = pgs.app AND st.stream = pgs.stream") @Select("SELECT st.*, pgs.gbId, pgs.status, pgs.name, pgs.longitude, pgs.latitude FROM stream_push st LEFT JOIN gb_stream pgs on st.app = pgs.app AND st.stream = pgs.stream order by st.createStamp desc")
List<StreamPushItem> selectAll(); List<StreamPushItem> selectAll();
@Select("SELECT st.*, pgs.gbId, pgs.status, pgs.name, pgs.longitude, pgs.latitude FROM stream_push st LEFT JOIN gb_stream pgs on st.app = pgs.app AND st.stream = pgs.stream WHERE st.enable=${enable}") @Select("SELECT st.*, pgs.gbId, pgs.status, pgs.name, pgs.longitude, pgs.latitude FROM stream_push st LEFT JOIN gb_stream pgs on st.app = pgs.app AND st.stream = pgs.stream WHERE st.enable=${enable}")
@ -50,9 +50,9 @@ public interface StreamPushMapper {
StreamPushItem selectOne(String app, String stream); StreamPushItem selectOne(String app, String stream);
@Insert("<script>" + @Insert("<script>" +
"INSERT INTO stream_push (app, stream, totalReaderCount, originType, originTypeStr, " + "REPLACE INTO stream_push (app, stream, totalReaderCount, originType, originTypeStr, " +
"createStamp, aliveSecond, mediaServerId) " + "createStamp, aliveSecond, mediaServerId) " +
"VALUES <foreach collection='streamPushItems' item='item' index='index' >" + "VALUES <foreach collection='streamPushItems' item='item' index='index' separator=','>" +
"( '${item.app}', '${item.stream}', '${item.totalReaderCount}', '${item.originType}', " + "( '${item.app}', '${item.stream}', '${item.totalReaderCount}', '${item.originType}', " +
"'${item.originTypeStr}','${item.createStamp}', '${item.aliveSecond}', '${item.mediaServerId}' )" + "'${item.originTypeStr}','${item.createStamp}', '${item.aliveSecond}', '${item.mediaServerId}' )" +
" </foreach>" + " </foreach>" +

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

@ -5,7 +5,10 @@ import com.genersoft.iot.vmp.common.StreamInfo;
import com.genersoft.iot.vmp.common.VideoManagerConstants; import com.genersoft.iot.vmp.common.VideoManagerConstants;
import com.genersoft.iot.vmp.conf.UserSetup; import com.genersoft.iot.vmp.conf.UserSetup;
import com.genersoft.iot.vmp.gb28181.bean.*; import com.genersoft.iot.vmp.gb28181.bean.*;
import com.genersoft.iot.vmp.media.zlm.dto.MediaItem;
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; 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.GPSMsgInfo;
import com.genersoft.iot.vmp.service.bean.ThirdPartyGB; import com.genersoft.iot.vmp.service.bean.ThirdPartyGB;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage; import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import com.genersoft.iot.vmp.storager.dao.DeviceChannelMapper; import com.genersoft.iot.vmp.storager.dao.DeviceChannelMapper;
@ -48,6 +51,18 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage {
return result; return result;
} }
@Override
public Long getSN(String method) {
String key = VideoManagerConstants.SIP_SN_PREFIX + userSetup.getServerId() + "_" + method;
long result = redis.incr(key, 1L);
if (result > Integer.MAX_VALUE) {
redis.set(key, 1);
result = 1;
}
return result;
}
@Override @Override
public void resetAllCSEQ() { public void resetAllCSEQ() {
String scanKey = VideoManagerConstants.SIP_CSEQ_PREFIX + userSetup.getServerId() + "_*"; String scanKey = VideoManagerConstants.SIP_CSEQ_PREFIX + userSetup.getServerId() + "_*";
@ -58,6 +73,16 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage {
} }
} }
@Override
public void resetAllSN() {
String scanKey = VideoManagerConstants.SIP_SN_PREFIX + userSetup.getServerId() + "_*";
List<Object> keys = redis.scan(scanKey);
for (int i = 0; i < keys.size(); i++) {
String key = (String) keys.get(i);
redis.set(key, 1);
}
}
/** /**
* 开始播放时将流存入redis * 开始播放时将流存入redis
* *
@ -225,7 +250,7 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage {
@Override @Override
public void updatePlatformRegisterInfo(String callId, String platformGbId) { public void updatePlatformRegisterInfo(String callId, String platformGbId) {
String key = VideoManagerConstants.PLATFORM_REGISTER_INFO_PREFIX + userSetup.getServerId() + "_" + callId; String key = VideoManagerConstants.PLATFORM_REGISTER_INFO_PREFIX + userSetup.getServerId() + "_" + callId;
redis.set(key, platformGbId); redis.set(key, platformGbId, 30);
} }
@ -363,9 +388,9 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage {
} }
@Override @Override
public void addStream(MediaServerItem mediaServerItem, String type, String app, String streamId, StreamInfo streamInfo) { public void addStream(MediaServerItem mediaServerItem, String type, String app, String streamId, MediaItem mediaItem) {
String key = VideoManagerConstants.WVP_SERVER_STREAM_PREFIX + userSetup.getServerId() + "_" + type + "_" + app + "_" + streamId + "_" + mediaServerItem.getId(); String key = VideoManagerConstants.WVP_SERVER_STREAM_PREFIX + userSetup.getServerId() + "_" + type + "_" + app + "_" + streamId + "_" + mediaServerItem.getId();
redis.set(key, streamInfo); redis.set(key, mediaItem);
} }
@Override @Override
@ -398,13 +423,13 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage {
} }
@Override @Override
public List<StreamInfo> getStreams(String mediaServerId, String type) { public List<MediaItem> getStreams(String mediaServerId, String type) {
List<StreamInfo> result = new ArrayList<>(); List<MediaItem> result = new ArrayList<>();
String key = VideoManagerConstants.WVP_SERVER_STREAM_PREFIX + userSetup.getServerId() + "_" + type + "_*_*_" + mediaServerId; String key = VideoManagerConstants.WVP_SERVER_STREAM_PREFIX + userSetup.getServerId() + "_" + type + "_*_*_" + mediaServerId;
List<Object> streams = redis.scan(key); List<Object> streams = redis.scan(key);
for (Object stream : streams) { for (Object stream : streams) {
StreamInfo streamInfo = (StreamInfo)redis.get((String) stream); MediaItem mediaItem = (MediaItem)redis.get((String) stream);
result.add(streamInfo); result.add(mediaItem);
} }
return result; return result;
} }
@ -415,9 +440,98 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage {
redis.set(key, device); redis.set(key, device);
} }
@Override
public void removeDevice(String deviceId) {
String key = VideoManagerConstants.DEVICE_PREFIX + userSetup.getServerId() + "_" + deviceId;
redis.del(key);
}
@Override @Override
public Device getDevice(String deviceId) { public Device getDevice(String deviceId) {
String key = VideoManagerConstants.DEVICE_PREFIX + userSetup.getServerId() + "_" + deviceId; String key = VideoManagerConstants.DEVICE_PREFIX + userSetup.getServerId() + "_" + deviceId;
return (Device)redis.get(key); return (Device)redis.get(key);
} }
@Override
public void updateGpsMsgInfo(GPSMsgInfo gpsMsgInfo) {
String key = VideoManagerConstants.WVP_STREAM_GPS_MSG_PREFIX + userSetup.getServerId() + "_" + gpsMsgInfo.getId();
redis.set(key, gpsMsgInfo, 60); // 默认GPS消息保存1分钟
}
@Override
public GPSMsgInfo getGpsMsgInfo(String gbId) {
String key = VideoManagerConstants.WVP_STREAM_GPS_MSG_PREFIX + userSetup.getServerId() + "_" + gbId;
return (GPSMsgInfo)redis.get(key);
}
@Override
public void updateSubscribe(String key, SubscribeInfo subscribeInfo) {
redis.set(key, subscribeInfo, subscribeInfo.getExpires());
}
@Override
public SubscribeInfo getSubscribe(String key) {
return (SubscribeInfo)redis.get(key);
}
@Override
public void delSubscribe(String key) {
redis.del(key);
}
@Override
public List<GPSMsgInfo> getAllGpsMsgInfo() {
String scanKey = VideoManagerConstants.WVP_STREAM_GPS_MSG_PREFIX + userSetup.getServerId() + "_*";
List<GPSMsgInfo> result = new ArrayList<>();
List<Object> keys = redis.scan(scanKey);
for (int i = 0; i < keys.size(); i++) {
String key = (String) keys.get(i);
GPSMsgInfo gpsMsgInfo = (GPSMsgInfo) redis.get(key);
if (!gpsMsgInfo.isStored()) { // 只取没有存过得
result.add((GPSMsgInfo)redis.get(key));
}
}
return result;
}
@Override
public MediaItem getStreamInfo(String app, String streamId, String mediaServerId) {
String scanKey = VideoManagerConstants.WVP_SERVER_STREAM_PREFIX + userSetup.getServerId() + "_*_" + app + "_" + streamId + "_" + mediaServerId;
MediaItem result = null;
List<Object> keys = redis.scan(scanKey);
if (keys.size() > 0) {
String key = (String) keys.get(0);
result = (MediaItem)redis.get(key);
}
return result;
}
@Override
public List<SubscribeInfo> getAllSubscribe() {
String scanKey = VideoManagerConstants.SIP_SUBSCRIBE_PREFIX + userSetup.getServerId() + "_Catalog_*";
List<SubscribeInfo> result = new ArrayList<>();
List<Object> keys = redis.scan(scanKey);
for (int i = 0; i < keys.size(); i++) {
String key = (String) keys.get(i);
SubscribeInfo subscribeInfo = (SubscribeInfo) redis.get(key);
result.add(subscribeInfo);
}
return result;
}
@Override
public List<String> getAllSubscribePlatform() {
String scanKey = VideoManagerConstants.SIP_SUBSCRIBE_PREFIX + userSetup.getServerId() + "_Catalog_*";
List<String> result = new ArrayList<>();
List<Object> keys = redis.scan(scanKey);
for (int i = 0; i < keys.size(); i++) {
String key = (String) keys.get(i);
String platformId = key.substring(scanKey.length() - 1);
result.add(platformId);
}
return result;
}
} }

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

@ -1,11 +1,15 @@
package com.genersoft.iot.vmp.storager.impl; package com.genersoft.iot.vmp.storager.impl;
import com.genersoft.iot.vmp.conf.SipConfig;
import com.genersoft.iot.vmp.gb28181.bean.*; import com.genersoft.iot.vmp.gb28181.bean.*;
import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent;
import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager; import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem; import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem;
import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem; import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem;
import com.genersoft.iot.vmp.service.IGbStreamService; import com.genersoft.iot.vmp.service.IGbStreamService;
import com.genersoft.iot.vmp.service.bean.GPSMsgInfo;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage; import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import com.genersoft.iot.vmp.storager.IVideoManagerStorager; import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
import com.genersoft.iot.vmp.storager.dao.*; import com.genersoft.iot.vmp.storager.dao.*;
@ -23,15 +27,12 @@ import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.ArrayList; import java.util.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/** /**
* @description:视频设备数据存储-jdbc实现 * 视频设备数据存储-jdbc实现
* @author: swwheihei * swwheihei
* @date: 2020年5月6日 下午2:31:42 * 2020年5月6日 下午2:31:42
*/ */
@SuppressWarnings("rawtypes") @SuppressWarnings("rawtypes")
@Component @Component
@ -39,6 +40,12 @@ public class VideoManagerStoragerImpl implements IVideoManagerStorager {
private Logger logger = LoggerFactory.getLogger(VideoManagerStoragerImpl.class); private Logger logger = LoggerFactory.getLogger(VideoManagerStoragerImpl.class);
@Autowired
EventPublisher eventPublisher;
@Autowired
SipConfig sipConfig;
@Autowired @Autowired
DataSourceTransactionManager dataSourceTransactionManager; DataSourceTransactionManager dataSourceTransactionManager;
@ -71,6 +78,9 @@ public class VideoManagerStoragerImpl implements IVideoManagerStorager {
@Autowired @Autowired
private GbStreamMapper gbStreamMapper; private GbStreamMapper gbStreamMapper;
@Autowired
private PlatformCatalogMapper catalogMapper;
; ;
@Autowired @Autowired
@ -133,6 +143,7 @@ public class VideoManagerStoragerImpl implements IVideoManagerStorager {
return deviceMapper.add(device) > 0; return deviceMapper.add(device) > 0;
}else { }else {
redisCatchStorage.updateDevice(device); redisCatchStorage.updateDevice(device);
return deviceMapper.update(device) > 0; return deviceMapper.update(device) > 0;
} }
@ -223,21 +234,41 @@ public class VideoManagerStoragerImpl implements IVideoManagerStorager {
@Override @Override
public boolean resetChannels(String deviceId, List<DeviceChannel> deviceChannelList) { public boolean resetChannels(String deviceId, List<DeviceChannel> deviceChannelList) {
TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition); TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition);
// 数据去重
List<DeviceChannel> channels = new ArrayList<>();
StringBuilder stringBuilder = new StringBuilder();
if (deviceChannelList.size() > 1) {
// 数据去重
Set<String> gbIdSet = new HashSet<>();
for (DeviceChannel deviceChannel : deviceChannelList) {
if (!gbIdSet.contains(deviceChannel.getChannelId())) {
gbIdSet.add(deviceChannel.getChannelId());
channels.add(deviceChannel);
}else {
stringBuilder.append(deviceChannel.getChannelId() + ",");
}
}
}else {
channels = deviceChannelList;
}
if (stringBuilder.length() > 0) {
logger.debug("[目录查询]收到的数据存在重复: {}" , stringBuilder);
}
try { try {
int cleanChannelsResult = deviceChannelMapper.cleanChannelsByDeviceId(deviceId); int cleanChannelsResult = deviceChannelMapper.cleanChannelsByDeviceId(deviceId);
int limitCount = 300; int limitCount = 300;
boolean result = cleanChannelsResult <0; boolean result = cleanChannelsResult < 0;
if (!result && deviceChannelList.size() > 0) { if (!result && channels.size() > 0) {
if (deviceChannelList.size() > limitCount) { if (channels.size() > limitCount) {
for (int i = 0; i < deviceChannelList.size(); i += limitCount) { for (int i = 0; i < channels.size(); i += limitCount) {
int toIndex = i + limitCount; int toIndex = i + limitCount;
if (i + limitCount > deviceChannelList.size()) { if (i + limitCount > channels.size()) {
toIndex = deviceChannelList.size(); toIndex = channels.size();
} }
result = result || deviceChannelMapper.batchAdd(deviceChannelList.subList(i, toIndex)) < 0; result = result || deviceChannelMapper.batchAdd(channels.subList(i, toIndex)) < 0;
} }
}else { }else {
result = result || deviceChannelMapper.batchAdd(deviceChannelList) < 0; result = result || deviceChannelMapper.batchAdd(channels) < 0;
} }
} }
if (result) { if (result) {
@ -387,6 +418,8 @@ public class VideoManagerStoragerImpl implements IVideoManagerStorager {
device.setOnline(1); device.setOnline(1);
logger.info("更新设备在线: " + deviceId); logger.info("更新设备在线: " + deviceId);
redisCatchStorage.updateDevice(device); redisCatchStorage.updateDevice(device);
List<DeviceChannel> deviceChannelList = deviceChannelMapper.queryOnlineChannelsByDeviceId(deviceId);
eventPublisher.catalogEventPublish(null, deviceChannelList, CatalogEvent.ON);
return deviceMapper.update(device) > 0; return deviceMapper.update(device) > 0;
} }
@ -449,6 +482,9 @@ public class VideoManagerStoragerImpl implements IVideoManagerStorager {
@Override @Override
public boolean addParentPlatform(ParentPlatform parentPlatform) { public boolean addParentPlatform(ParentPlatform parentPlatform) {
if (parentPlatform.getCatalogId() == null) {
parentPlatform.setCatalogId(parentPlatform.getServerGBId());
}
int result = platformMapper.addParentPlatform(parentPlatform); int result = platformMapper.addParentPlatform(parentPlatform);
return result > 0; return result > 0;
} }
@ -458,6 +494,9 @@ public class VideoManagerStoragerImpl implements IVideoManagerStorager {
int result = 0; int result = 0;
ParentPlatformCatch parentPlatformCatch = redisCatchStorage.queryPlatformCatchInfo(parentPlatform.getServerGBId()); // .getDeviceGBId()); ParentPlatformCatch parentPlatformCatch = redisCatchStorage.queryPlatformCatchInfo(parentPlatform.getServerGBId()); // .getDeviceGBId());
if (parentPlatform.getId() == null ) { if (parentPlatform.getId() == null ) {
if (parentPlatform.getCatalogId() == null) {
parentPlatform.setCatalogId(parentPlatform.getServerGBId());
}
result = platformMapper.addParentPlatform(parentPlatform); result = platformMapper.addParentPlatform(parentPlatform);
if (parentPlatformCatch == null) { if (parentPlatformCatch == null) {
parentPlatformCatch = new ParentPlatformCatch(); parentPlatformCatch = new ParentPlatformCatch();
@ -477,15 +516,21 @@ public class VideoManagerStoragerImpl implements IVideoManagerStorager {
// 更新缓存 // 更新缓存
parentPlatformCatch.setParentPlatform(parentPlatform); parentPlatformCatch.setParentPlatform(parentPlatform);
redisCatchStorage.updatePlatformCatchInfo(parentPlatformCatch); redisCatchStorage.updatePlatformCatchInfo(parentPlatformCatch);
// 共享所有视频流,需要将现有视频流添加到此平台 if (parentPlatform.isEnable()) {
List<GbStream> gbStreams = gbStreamMapper.selectAll(); // 共享所有视频流,需要将现有视频流添加到此平台
if (gbStreams.size() > 0) { List<GbStream> gbStreams = gbStreamMapper.queryStreamNotInPlatform();
if (parentPlatform.isShareAllLiveStream()) { if (gbStreams.size() > 0) {
gbStreamService.addPlatformInfo(gbStreams, parentPlatform.getServerGBId()); for (GbStream gbStream : gbStreams) {
}else { gbStream.setCatalogId(parentPlatform.getCatalogId());
gbStreamService.delPlatformInfo(gbStreams); }
if (parentPlatform.isShareAllLiveStream()) {
gbStreamService.addPlatformInfo(gbStreams, parentPlatform.getServerGBId(), parentPlatform.getCatalogId());
}else {
gbStreamService.delPlatformInfo(parentPlatform.getServerGBId(), gbStreams);
}
} }
} }
return result > 0; return result > 0;
} }
@ -536,10 +581,11 @@ public class VideoManagerStoragerImpl implements IVideoManagerStorager {
} }
@Override @Override
public int updateChannelForGB(String platformId, List<ChannelReduce> channelReduces) { public int updateChannelForGB(String platformId, List<ChannelReduce> channelReduces, String catalogId) {
Map<String, ChannelReduce> deviceAndChannels = new HashMap<>(); Map<String, ChannelReduce> deviceAndChannels = new HashMap<>();
for (ChannelReduce channelReduce : channelReduces) { for (ChannelReduce channelReduce : channelReduces) {
channelReduce.setCatalogId(catalogId);
deviceAndChannels.put(channelReduce.getDeviceId() + "_" + channelReduce.getChannelId(), channelReduce); deviceAndChannels.put(channelReduce.getDeviceId() + "_" + channelReduce.getChannelId(), channelReduce);
} }
List<String> deviceAndChannelList = new ArrayList<>(deviceAndChannels.keySet()); List<String> deviceAndChannelList = new ArrayList<>(deviceAndChannels.keySet());
@ -556,6 +602,9 @@ public class VideoManagerStoragerImpl implements IVideoManagerStorager {
int result = 0; int result = 0;
if (channelReducesToAdd.size() > 0) { if (channelReducesToAdd.size() > 0) {
result = platformChannelMapper.addChannels(platformId, channelReducesToAdd); result = platformChannelMapper.addChannels(platformId, channelReducesToAdd);
// TODO 后续给平台增加控制开关以控制是否响应目录订阅
List<DeviceChannel> deviceChannelList = getDeviceChannelListByChannelReduceList(channelReducesToAdd, catalogId);
eventPublisher.catalogEventPublish(platformId, deviceChannelList, CatalogEvent.ADD);
} }
return result; return result;
@ -566,7 +615,13 @@ public class VideoManagerStoragerImpl implements IVideoManagerStorager {
public int delChannelForGB(String platformId, List<ChannelReduce> channelReduces) { public int delChannelForGB(String platformId, List<ChannelReduce> channelReduces) {
int result = platformChannelMapper.delChannelForGB(platformId, channelReduces); int result = platformChannelMapper.delChannelForGB(platformId, channelReduces);
List<DeviceChannel> deviceChannelList = new ArrayList<>();
for (ChannelReduce channelReduce : channelReduces) {
DeviceChannel deviceChannel = new DeviceChannel();
deviceChannel.setChannelId(channelReduce.getChannelId());
deviceChannelList.add(deviceChannel);
}
eventPublisher.catalogEventPublish(platformId, deviceChannelList, CatalogEvent.DEL);
return result; return result;
} }
@ -576,6 +631,18 @@ public class VideoManagerStoragerImpl implements IVideoManagerStorager {
return channel; return channel;
} }
@Override
public List<PlatformCatalog> queryChannelInParentPlatformAndCatalog(String platformId, String catalogId) {
List<PlatformCatalog> catalogs = platformChannelMapper.queryChannelInParentPlatformAndCatalog(platformId, catalogId);
return catalogs;
}
@Override
public List<PlatformCatalog> queryStreamInParentPlatformAndCatalog(String platformId, String catalogId) {
List<PlatformCatalog> catalogs = platformGbStreamMapper.queryChannelInParentPlatformAndCatalogForCatalog(platformId, catalogId);
return catalogs;
}
@Override @Override
public Device queryVideoDeviceByPlatformIdAndChannelId(String platformId, String channelId) { public Device queryVideoDeviceByPlatformIdAndChannelId(String platformId, String channelId) {
Device device = platformChannelMapper.queryVideoDeviceByPlatformIdAndChannelId(platformId, channelId); Device device = platformChannelMapper.queryVideoDeviceByPlatformIdAndChannelId(platformId, channelId);
@ -693,7 +760,7 @@ public class VideoManagerStoragerImpl implements IVideoManagerStorager {
* @return * @return
*/ */
@Override @Override
public List<GbStream> queryStreamInParentPlatform(String platformId, String gbId) { public GbStream queryStreamInParentPlatform(String platformId, String gbId) {
return gbStreamMapper.queryStreamInPlatform(platformId, gbId); return gbStreamMapper.queryStreamInPlatform(platformId, gbId);
} }
@ -725,7 +792,11 @@ public class VideoManagerStoragerImpl implements IVideoManagerStorager {
streamPushMapper.addAll(streamPushItems); streamPushMapper.addAll(streamPushItems);
// TODO 待优化 // TODO 待优化
for (int i = 0; i < streamPushItems.size(); i++) { for (int i = 0; i < streamPushItems.size(); i++) {
gbStreamMapper.setStatus(streamPushItems.get(i).getApp(), streamPushItems.get(i).getStream(), true); int onlineResult = gbStreamMapper.setStatus(streamPushItems.get(i).getApp(), streamPushItems.get(i).getStream(), true);
if (onlineResult > 0) {
// 发送上线通知
eventPublisher.catalogEventPublishForStream(null, streamPushItems.get(i), CatalogEvent.ON);
}
} }
} }
@ -734,16 +805,20 @@ public class VideoManagerStoragerImpl implements IVideoManagerStorager {
streamPushMapper.del(streamPushItem.getApp(), streamPushItem.getStream()); streamPushMapper.del(streamPushItem.getApp(), streamPushItem.getStream());
streamPushMapper.add(streamPushItem); streamPushMapper.add(streamPushItem);
gbStreamMapper.setStatus(streamPushItem.getApp(), streamPushItem.getStream(), true); gbStreamMapper.setStatus(streamPushItem.getApp(), streamPushItem.getStream(), true);
if(!StringUtils.isEmpty(streamPushItem.getGbId() )){ if(!StringUtils.isEmpty(streamPushItem.getGbId() )){
// 查找开启了全部直播流共享的上级平台 // 查找开启了全部直播流共享的上级平台
List<ParentPlatform> parentPlatforms = parentPlatformMapper.selectAllAhareAllLiveStream(); List<ParentPlatform> parentPlatforms = parentPlatformMapper.selectAllAhareAllLiveStream();
if (parentPlatforms.size() > 0) { if (parentPlatforms.size() > 0) {
for (ParentPlatform parentPlatform : parentPlatforms) { for (ParentPlatform parentPlatform : parentPlatforms) {
streamPushItem.setCatalogId(parentPlatform.getCatalogId());
streamPushItem.setPlatformId(parentPlatform.getServerGBId()); streamPushItem.setPlatformId(parentPlatform.getServerGBId());
String stream = streamPushItem.getStream(); String stream = streamPushItem.getStream();
StreamProxyItem streamProxyItems = platformGbStreamMapper.selectOne(streamPushItem.getApp(), stream, parentPlatform.getServerGBId()); StreamProxyItem streamProxyItems = platformGbStreamMapper.selectOne(streamPushItem.getApp(), stream,
parentPlatform.getServerGBId());
if (streamProxyItems == null) { if (streamProxyItems == null) {
platformGbStreamMapper.add(streamPushItem); platformGbStreamMapper.add(streamPushItem);
eventPublisher.catalogEventPublishForStream(parentPlatform.getServerGBId(), streamPushItem, CatalogEvent.ADD);
} }
} }
} }
@ -804,4 +879,182 @@ public class VideoManagerStoragerImpl implements IVideoManagerStorager {
return streamProxyMapper.selectOne(app, streamId); return streamProxyMapper.selectOne(app, streamId);
} }
@Override
public List<PlatformCatalog> getChildrenCatalogByPlatform(String platformId, String parentId) {
return catalogMapper.selectByParentId(platformId, parentId);
}
@Override
public int addCatalog(PlatformCatalog platformCatalog) {
int result = catalogMapper.add(platformCatalog);
if (result > 0) {
DeviceChannel deviceChannel = getDeviceChannelByCatalog(platformCatalog);
eventPublisher.catalogEventPublish(platformCatalog.getPlatformId(), deviceChannel, CatalogEvent.ADD);
}
return result;
}
@Override
public PlatformCatalog getCatalog(String id) {
return catalogMapper.select(id);
}
@Override
public int delCatalog(String id) {
PlatformCatalog platformCatalog = catalogMapper.select(id);
if (platformCatalog.getChildrenCount() > 0) {
List<PlatformCatalog> platformCatalogList = catalogMapper.selectByParentId(platformCatalog.getPlatformId(), platformCatalog.getId());
for (PlatformCatalog catalog : platformCatalogList) {
if (catalog.getChildrenCount() == 0) {
delCatalogExecute(catalog.getId(), catalog.getPlatformId());
}else {
delCatalog(catalog.getId());
}
}
}
return delCatalogExecute(id, platformCatalog.getPlatformId());
}
private int delCatalogExecute(String id, String platformId) {
int delresult = catalogMapper.del(id);
DeviceChannel deviceChannelForCatalog = new DeviceChannel();
if (delresult > 0){
deviceChannelForCatalog.setChannelId(id);
eventPublisher.catalogEventPublish(platformId, deviceChannelForCatalog, CatalogEvent.DEL);
}
List<GbStream> gbStreams = platformGbStreamMapper.queryChannelInParentPlatformAndCatalog(platformId, id);
if (gbStreams.size() > 0){
List<DeviceChannel> deviceChannelList = new ArrayList<>();
for (GbStream gbStream : gbStreams) {
DeviceChannel deviceChannel = new DeviceChannel();
deviceChannel.setChannelId(gbStream.getGbId());
deviceChannelList.add(deviceChannel);
}
eventPublisher.catalogEventPublish(platformId, deviceChannelList, CatalogEvent.DEL);
}
int delStreamresult = platformGbStreamMapper.delByCatalogId(id);
List<PlatformCatalog> platformCatalogs = platformChannelMapper.queryChannelInParentPlatformAndCatalog(platformId, id);
if (platformCatalogs.size() > 0){
List<DeviceChannel> deviceChannelList = new ArrayList<>();
for (PlatformCatalog platformCatalog : platformCatalogs) {
DeviceChannel deviceChannel = new DeviceChannel();
deviceChannel.setChannelId(platformCatalog.getId());
deviceChannelList.add(deviceChannel);
}
eventPublisher.catalogEventPublish(platformId, deviceChannelList, CatalogEvent.DEL);
}
int delChannelresult = platformChannelMapper.delByCatalogId(id);
return delresult + delChannelresult + delStreamresult;
}
@Override
public int updateCatalog(PlatformCatalog platformCatalog) {
int result = catalogMapper.update(platformCatalog);
if (result > 0) {
DeviceChannel deviceChannel = getDeviceChannelByCatalog(platformCatalog);
eventPublisher.catalogEventPublish(platformCatalog.getPlatformId(), deviceChannel, CatalogEvent.UPDATE);
}
return result;
}
@Override
public int setDefaultCatalog(String platformId, String catalogId) {
return platformMapper.setDefaultCatalog(platformId, catalogId);
}
@Override
public List<PlatformCatalog> queryCatalogInPlatform(String platformId) {
return catalogMapper.selectByPlatForm(platformId);
}
@Override
public int delRelation(PlatformCatalog platformCatalog) {
if (platformCatalog.getType() == 1) {
DeviceChannel deviceChannel = new DeviceChannel();
deviceChannel.setChannelId(platformCatalog.getId());
eventPublisher.catalogEventPublish(platformCatalog.getPlatformId(), deviceChannel, CatalogEvent.DEL);
return platformChannelMapper.delByCatalogIdAndChannelIdAndPlatformId(platformCatalog);
}else if (platformCatalog.getType() == 2) {
List<GbStream> gbStreams = platformGbStreamMapper.queryChannelInParentPlatformAndCatalog(platformCatalog.getPlatformId(), platformCatalog.getParentId());
for (GbStream gbStream : gbStreams) {
if (gbStream.getGbId().equals(platformCatalog.getId())) {
DeviceChannel deviceChannel = new DeviceChannel();
deviceChannel.setChannelId(gbStream.getGbId());
eventPublisher.catalogEventPublish(platformCatalog.getPlatformId(), deviceChannel, CatalogEvent.DEL);
return platformGbStreamMapper.delByAppAndStream(gbStream.getApp(), gbStream.getStream());
}
}
}
return 0;
}
@Override
public int updateStreamGPS(List<GPSMsgInfo> gpsMsgInfos) {
return gbStreamMapper.updateStreamGPS(gpsMsgInfos);
}
private List<DeviceChannel> getDeviceChannelListByChannelReduceList(List<ChannelReduce> channelReduces, String catalogId) {
List<DeviceChannel> deviceChannelList = new ArrayList<>();
if (channelReduces.size() > 0){
for (ChannelReduce channelReduce : channelReduces) {
DeviceChannel deviceChannel = queryChannel(channelReduce.getDeviceId(), channelReduce.getChannelId());
deviceChannel.setParental(1);
deviceChannel.setParentId(catalogId);
deviceChannelList.add(deviceChannel);
}
}
return deviceChannelList;
}
private DeviceChannel getDeviceChannelByCatalog(PlatformCatalog catalog) {
ParentPlatform parentPlatByServerGBId = platformMapper.getParentPlatByServerGBId(catalog.getPlatformId());
DeviceChannel deviceChannel = new DeviceChannel();
deviceChannel.setChannelId(catalog.getId());
deviceChannel.setName(catalog.getName());
deviceChannel.setLongitude(0.0);
deviceChannel.setLatitude(0.0);
deviceChannel.setDeviceId(parentPlatByServerGBId.getDeviceGBId());
deviceChannel.setManufacture("wvp-pro");
deviceChannel.setStatus(1);
deviceChannel.setParental(1);
deviceChannel.setParentId(catalog.getParentId());
deviceChannel.setRegisterWay(1);
deviceChannel.setCivilCode(sipConfig.getDomain());
deviceChannel.setModel("live");
deviceChannel.setOwner("wvp-pro");
deviceChannel.setSecrecy("0");
return deviceChannel;
}
@Override
public List<DeviceChannel> queryOnlineChannelsByDeviceId(String deviceId) {
return deviceChannelMapper.queryOnlineChannelsByDeviceId(deviceId);
}
@Override
public List<ParentPlatform> queryPlatFormListForGBWithGBId(String channelId, List<String> platforms) {
return platformChannelMapper.queryPlatFormListForGBWithGBId(channelId, platforms);
}
@Override
public List<ParentPlatform> queryPlatFormListForStreamWithGBId(String app, String stream, List<String> platforms) {
return platformGbStreamMapper.queryPlatFormListForGBWithGBId(app, stream, platforms);
}
@Override
public GbStream getGbStream(String app, String streamId) {
return gbStreamMapper.selectOne(app, streamId);
}
@Override
public void delCatalogByPlatformId(String serverGBId) {
catalogMapper.delByPlatformId(serverGBId);
}
@Override
public void delRelationByPlatformId(String serverGBId) {
platformGbStreamMapper.delByPlatformId(serverGBId);
platformChannelMapper.delByPlatformId(serverGBId);
}
} }

50
src/main/java/com/genersoft/iot/vmp/vmanager/bean/StreamPushExcelDto.java

@ -0,0 +1,50 @@
package com.genersoft.iot.vmp.vmanager.bean;
import com.alibaba.excel.annotation.ExcelProperty;
public class StreamPushExcelDto {
@ExcelProperty("名称")
private String name;
@ExcelProperty("应用名")
private String app;
@ExcelProperty("流ID")
private String stream;
@ExcelProperty("国标ID")
private String gbId;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getApp() {
return app;
}
public void setApp(String app) {
this.app = app;
}
public String getStream() {
return stream;
}
public void setStream(String stream) {
this.stream = stream;
}
public String getGbId() {
return gbId;
}
public void setGbId(String gbId) {
this.gbId = gbId;
}
}

99
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceControl.java

@ -296,4 +296,103 @@ public class DeviceControl {
resultHolder.put(key, uuid, result); resultHolder.put(key, uuid, result);
return result; return result;
} }
/**
* 拉框放大
* @param deviceId 设备id
* @param channelId 通道id
* @param length 播放窗口长度像素值
* @param width 播放窗口宽度像素值
* @param midpointx 拉框中心的横轴坐标像素值
* @param midpointy 拉框中心的纵轴坐标像素值
* @param lengthx 拉框长度像素值
* @param lengthy 拉框宽度像素值
* @return
*/
@ApiOperation("拉框放大")
@ApiImplicitParams({
@ApiImplicitParam(name = "deviceId", value = "设备ID", required = true, dataTypeClass = String.class),
@ApiImplicitParam(name = "channelId", value = "通道ID", dataTypeClass = String.class),
@ApiImplicitParam(name = "length", value = "播放窗口长度像素值", required = true, dataTypeClass = Integer.class),
@ApiImplicitParam(name = "width", value = "播放窗口宽度像素值", required = true, dataTypeClass = Integer.class),
@ApiImplicitParam(name = "midpointx", value = "拉框中心的横轴坐标像素值", required = true, dataTypeClass = Integer.class),
@ApiImplicitParam(name = "midpointy", value = "拉框中心的纵轴坐标像素值", required = true, dataTypeClass = Integer.class),
@ApiImplicitParam(name = "lengthx", value = "拉框长度像素值", required = true, dataTypeClass = Integer.class),
@ApiImplicitParam(name = "lengthy", value = "拉框宽度像素值", required = true, dataTypeClass = Integer.class),
})
@GetMapping("drag_zoom/zoom_in")
public ResponseEntity<String> dragZoomIn(@RequestParam String deviceId,
@RequestParam(required = false) String channelId,
@RequestParam int length,
@RequestParam int width,
@RequestParam int midpointx,
@RequestParam int midpointy,
@RequestParam int lengthx,
@RequestParam int lengthy){
if (logger.isDebugEnabled()) {
logger.debug(String.format("设备拉框放大 API调用,deviceId:%s ,channelId:%s ,length:%d ,width:%d ,midpointx:%d ,midpointy:%d ,lengthx:%d ,lengthy:%d",deviceId, channelId, length, width, midpointx, midpointy,lengthx, lengthy));
}
Device device = storager.queryVideoDevice(deviceId);
StringBuffer cmdXml = new StringBuffer(200);
cmdXml.append("<DragZoomIn>\r\n");
cmdXml.append("<Length>" + length+ "</Length>\r\n");
cmdXml.append("<Width>" + width+ "</Width>\r\n");
cmdXml.append("<MidPointX>" + midpointx+ "</MidPointX>\r\n");
cmdXml.append("<MidPointY>" + midpointy+ "</MidPointY>\r\n");
cmdXml.append("<LengthX>" + lengthx+ "</LengthX>\r\n");
cmdXml.append("<LengthY>" + lengthy+ "</LengthY>\r\n");
cmdXml.append("</DragZoomIn>\r\n");
cmder.dragZoomCmd(device, channelId, cmdXml.toString());
return new ResponseEntity<String>("success", HttpStatus.OK);
}
/**
* 拉框缩小
* @param deviceId 设备id
* @param channelId 通道id
* @param length 播放窗口长度像素值
* @param width 播放窗口宽度像素值
* @param midpointx 拉框中心的横轴坐标像素值
* @param midpointy 拉框中心的纵轴坐标像素值
* @param lengthx 拉框长度像素值
* @param lengthy 拉框宽度像素值
* @return
*/
@ApiOperation("拉框缩小")
@ApiImplicitParams({
@ApiImplicitParam(name = "deviceId", value = "设备ID", required = true, dataTypeClass = String.class),
@ApiImplicitParam(name = "channelId", value = "通道ID", dataTypeClass = String.class),
@ApiImplicitParam(name = "length", value = "播放窗口长度像素值", required = true, dataTypeClass = Integer.class),
@ApiImplicitParam(name = "width", value = "播放窗口宽度像素值", required = true, dataTypeClass = Integer.class),
@ApiImplicitParam(name = "midpointx", value = "拉框中心的横轴坐标像素值", required = true, dataTypeClass = Integer.class),
@ApiImplicitParam(name = "midpointy", value = "拉框中心的纵轴坐标像素值", required = true, dataTypeClass = Integer.class),
@ApiImplicitParam(name = "lengthx", value = "拉框长度像素值", required = true, dataTypeClass = Integer.class),
@ApiImplicitParam(name = "lengthy", value = "拉框宽度像素值", required = true, dataTypeClass = Integer.class),
})
@GetMapping("/drag_zoom/zoom_out")
public ResponseEntity<String> dragZoomOut(@RequestParam String deviceId,
@RequestParam(required = false) String channelId,
@RequestParam int length,
@RequestParam int width,
@RequestParam int midpointx,
@RequestParam int midpointy,
@RequestParam int lengthx,
@RequestParam int lengthy){
if (logger.isDebugEnabled()) {
logger.debug(String.format("设备拉框缩小 API调用,deviceId:%s ,channelId:%s ,length:%d ,width:%d ,midpointx:%d ,midpointy:%d ,lengthx:%d ,lengthy:%d",deviceId, channelId, length, width, midpointx, midpointy,lengthx, lengthy));
}
Device device = storager.queryVideoDevice(deviceId);
StringBuffer cmdXml = new StringBuffer(200);
cmdXml.append("<DragZoomOut>\r\n");
cmdXml.append("<Length>" + length+ "</Length>\r\n");
cmdXml.append("<Width>" + width+ "</Width>\r\n");
cmdXml.append("<MidPointX>" + midpointx+ "</MidPointX>\r\n");
cmdXml.append("<MidPointY>" + midpointy+ "</MidPointY>\r\n");
cmdXml.append("<LengthX>" + lengthx+ "</LengthX>\r\n");
cmdXml.append("<LengthY>" + lengthy+ "</LengthY>\r\n");
cmdXml.append("</DragZoomOut>\r\n");
cmder.dragZoomCmd(device, channelId, cmdXml.toString());
return new ResponseEntity<String>("success",HttpStatus.OK);
}
} }

21
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceQuery.java

@ -150,15 +150,21 @@ public class DeviceQuery {
Device device = storager.queryVideoDevice(deviceId); Device device = storager.queryVideoDevice(deviceId);
String key = DeferredResultHolder.CALLBACK_CMD_CATALOG + deviceId; String key = DeferredResultHolder.CALLBACK_CMD_CATALOG + deviceId;
String uuid = UUID.randomUUID().toString(); String uuid = UUID.randomUUID().toString();
DeferredResult<ResponseEntity<Device>> result = new DeferredResult<ResponseEntity<Device>>(15*1000L); // 默认超时时间为30分钟
DeferredResult<ResponseEntity<Device>> result = new DeferredResult<ResponseEntity<Device>>(30*60*1000L);
result.onTimeout(()->{ result.onTimeout(()->{
logger.warn(String.format("设备通道信息同步超时")); logger.warn("设备[{}]通道信息同步超时", deviceId);
// 释放rtpserver // 释放rtpserver
RequestMessage msg = new RequestMessage(); RequestMessage msg = new RequestMessage();
msg.setKey(key); msg.setKey(key);
msg.setId(uuid); msg.setId(uuid);
msg.setData("Timeout"); WVPResult<Object> wvpResult = new WVPResult<>();
wvpResult.setCode(-1);
wvpResult.setData(device);
wvpResult.setMsg("更新超时");
msg.setData(wvpResult);
resultHolder.invokeAllResult(msg); resultHolder.invokeAllResult(msg);
}); });
// 等待其他相同请求返回时一起返回 // 等待其他相同请求返回时一起返回
if (resultHolder.exist(key, null)) { if (resultHolder.exist(key, null)) {
@ -168,7 +174,11 @@ public class DeviceQuery {
RequestMessage msg = new RequestMessage(); RequestMessage msg = new RequestMessage();
msg.setKey(key); msg.setKey(key);
msg.setId(uuid); msg.setId(uuid);
msg.setData(String.format("同步通道失败,错误码: %s, %s", event.statusCode, event.msg)); WVPResult<Object> wvpResult = new WVPResult<>();
wvpResult.setCode(-1);
wvpResult.setData(device);
wvpResult.setMsg(String.format("同步通道失败,错误码: %s, %s", event.statusCode, event.msg));
msg.setData(wvpResult);
resultHolder.invokeAllResult(msg); resultHolder.invokeAllResult(msg);
}); });
@ -306,7 +316,8 @@ public class DeviceQuery {
if (!StringUtils.isEmpty(device.getCharset())) deviceInStore.setCharset(device.getCharset()); if (!StringUtils.isEmpty(device.getCharset())) deviceInStore.setCharset(device.getCharset());
if (!StringUtils.isEmpty(device.getMediaServerId())) deviceInStore.setMediaServerId(device.getMediaServerId()); if (!StringUtils.isEmpty(device.getMediaServerId())) deviceInStore.setMediaServerId(device.getMediaServerId());
if (deviceInStore.getSubscribeCycleForCatalog() <=0 && device.getSubscribeCycleForCatalog() > 0) { if ((deviceInStore.getSubscribeCycleForCatalog() <=0 && device.getSubscribeCycleForCatalog() > 0)
|| deviceInStore.getSubscribeCycleForCatalog() != device.getSubscribeCycleForCatalog()) {
deviceInStore.setSubscribeCycleForCatalog(device.getSubscribeCycleForCatalog()); deviceInStore.setSubscribeCycleForCatalog(device.getSubscribeCycleForCatalog());
// 开启订阅 // 开启订阅
deviceService.addCatalogSubscribe(deviceInStore); deviceService.addCatalogSubscribe(deviceInStore);

13
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/gbStream/GbStreamController.java

@ -33,19 +33,22 @@ public class GbStreamController {
* 查询国标通道 * 查询国标通道
* @param page 当前页 * @param page 当前页
* @param count 每页条数 * @param count 每页条数
* @param platformId 平台ID
* @return * @return
*/ */
@ApiOperation("查询国标通道") @ApiOperation("查询国标通道")
@ApiImplicitParams({ @ApiImplicitParams({
@ApiImplicitParam(name = "page", value = "当前页", required = true , dataTypeClass = Integer.class), @ApiImplicitParam(name = "page", value = "当前页", required = true , dataTypeClass = Integer.class),
@ApiImplicitParam(name = "count", value = "每页条数", required = true , dataTypeClass = Integer.class), @ApiImplicitParam(name = "count", value = "每页条数", required = true , dataTypeClass = Integer.class),
@ApiImplicitParam(name = "platformId", value = "平台ID", required = true , dataTypeClass = Integer.class),
}) })
@GetMapping(value = "/list") @GetMapping(value = "/list")
@ResponseBody @ResponseBody
public PageInfo<GbStream> list(@RequestParam(required = false)Integer page, public PageInfo<GbStream> list(@RequestParam(required = true)Integer page,
@RequestParam(required = false)Integer count){ @RequestParam(required = true)Integer count,
@RequestParam(required = true)String platformId){
return gbStreamService.getAll(page, count); return gbStreamService.getAll(page, count, platformId);
} }
@ -62,7 +65,7 @@ public class GbStreamController {
@DeleteMapping(value = "/del") @DeleteMapping(value = "/del")
@ResponseBody @ResponseBody
public Object del(@RequestBody GbStreamParam gbStreamParam){ public Object del(@RequestBody GbStreamParam gbStreamParam){
if (gbStreamService.delPlatformInfo(gbStreamParam.getGbStreams())) { if (gbStreamService.delPlatformInfo(gbStreamParam.getPlatformId(), gbStreamParam.getGbStreams())) {
return "success"; return "success";
}else { }else {
return "fail"; return "fail";
@ -82,7 +85,7 @@ public class GbStreamController {
@PostMapping(value = "/add") @PostMapping(value = "/add")
@ResponseBody @ResponseBody
public Object add(@RequestBody GbStreamParam gbStreamParam){ public Object add(@RequestBody GbStreamParam gbStreamParam){
if (gbStreamService.addPlatformInfo(gbStreamParam.getGbStreams(), gbStreamParam.getPlatformId())) { if (gbStreamService.addPlatformInfo(gbStreamParam.getGbStreams(), gbStreamParam.getPlatformId(), gbStreamParam.getCatalogId())) {
return "success"; return "success";
}else { }else {
return "fail"; return "fail";

10
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/gbStream/bean/GbStreamParam.java

@ -8,12 +8,22 @@ public class GbStreamParam {
private String platformId; private String platformId;
private String catalogId;
private List<GbStream> gbStreams; private List<GbStream> gbStreams;
public String getPlatformId() { public String getPlatformId() {
return platformId; return platformId;
} }
public String getCatalogId() {
return catalogId;
}
public void setCatalogId(String catalogId) {
this.catalogId = catalogId;
}
public void setPlatformId(String platformId) { public void setPlatformId(String platformId) {
this.platformId = platformId; this.platformId = platformId;
} }

204
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/platform/PlatformController.java

@ -1,10 +1,15 @@
package com.genersoft.iot.vmp.vmanager.gb28181.platform; package com.genersoft.iot.vmp.vmanager.gb28181.platform;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import com.genersoft.iot.vmp.gb28181.bean.CatalogData;
import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
import com.genersoft.iot.vmp.gb28181.bean.PlatformCatalog;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform; import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage; import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import com.genersoft.iot.vmp.storager.IVideoManagerStorager; import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
import com.genersoft.iot.vmp.vmanager.gb28181.platform.bean.ChannelReduce; import com.genersoft.iot.vmp.vmanager.gb28181.platform.bean.ChannelReduce;
import com.genersoft.iot.vmp.vmanager.gb28181.platform.bean.UpdateChannelParam; import com.genersoft.iot.vmp.vmanager.gb28181.platform.bean.UpdateChannelParam;
import com.github.pagehelper.PageInfo; import com.github.pagehelper.PageInfo;
@ -21,6 +26,8 @@ import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import com.genersoft.iot.vmp.conf.SipConfig; import com.genersoft.iot.vmp.conf.SipConfig;
import java.util.List;
/** /**
* 级联平台管理 * 级联平台管理
*/ */
@ -165,6 +172,8 @@ public class PlatformController {
})); }));
boolean deleteResult = storager.deleteParentPlatform(parentPlatform); boolean deleteResult = storager.deleteParentPlatform(parentPlatform);
storager.delCatalogByPlatformId(parentPlatform.getServerGBId());
storager.delRelationByPlatformId(parentPlatform.getServerGBId());
if (deleteResult) { if (deleteResult) {
@ -253,7 +262,7 @@ public class PlatformController {
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {
logger.debug("给上级平台添加国标通道API调用"); logger.debug("给上级平台添加国标通道API调用");
} }
int result = storager.updateChannelForGB(param.getPlatformId(), param.getChannelReduces()); int result = storager.updateChannelForGB(param.getPlatformId(), param.getChannelReduces(), param.getCatalogId());
return new ResponseEntity<>(String.valueOf(result > 0), HttpStatus.OK); return new ResponseEntity<>(String.valueOf(result > 0), HttpStatus.OK);
} }
@ -279,5 +288,198 @@ public class PlatformController {
return new ResponseEntity<>(String.valueOf(result > 0), HttpStatus.OK); return new ResponseEntity<>(String.valueOf(result > 0), HttpStatus.OK);
} }
/**
* 获取目录
* @param platformId 平台ID
* @param parentId 目录父ID
* @return
*/
@ApiOperation("获取目录")
@ApiImplicitParams({
@ApiImplicitParam(name = "platformId", value = "平台ID", dataTypeClass = String.class, required = true),
@ApiImplicitParam(name = "parentId", value = "目录父ID", dataTypeClass = String.class, required = true),
})
@GetMapping("/catalog")
@ResponseBody
public ResponseEntity<WVPResult<List<PlatformCatalog>>> getCatalogByPlatform(String platformId, String parentId){
if (logger.isDebugEnabled()) {
logger.debug("查询目录,platformId: {}, parentId: {}", platformId, parentId);
}
List<PlatformCatalog> platformCatalogList = storager.getChildrenCatalogByPlatform(platformId, parentId);
// 查询下属的国标通道
List<PlatformCatalog> catalogsForChannel = storager.queryChannelInParentPlatformAndCatalog(platformId, parentId);
// 查询下属的直播流通道
List<PlatformCatalog> catalogsForStream = storager.queryStreamInParentPlatformAndCatalog(platformId, parentId);
platformCatalogList.addAll(catalogsForChannel);
platformCatalogList.addAll(catalogsForStream);
WVPResult<List<PlatformCatalog>> result = new WVPResult<>();
result.setCode(0);
result.setMsg("success");
result.setData(platformCatalogList);
return new ResponseEntity<>(result, HttpStatus.OK);
}
/**
* 添加目录
* @param platformCatalog 目录
* @return
*/
@ApiOperation("添加目录")
@ApiImplicitParams({
@ApiImplicitParam(name = "platformCatalog", value = "目录信息", dataTypeClass = PlatformCatalog.class, required = true),
})
@PostMapping("/catalog/add")
@ResponseBody
public ResponseEntity<WVPResult<List<PlatformCatalog>>> addCatalog(@RequestBody PlatformCatalog platformCatalog){
if (logger.isDebugEnabled()) {
logger.debug("添加目录,{}", JSON.toJSONString(platformCatalog));
}
PlatformCatalog platformCatalogInStore = storager.getCatalog(platformCatalog.getId());
WVPResult<List<PlatformCatalog>> result = new WVPResult<>();
if (platformCatalogInStore != null) {
result.setCode(-1);
result.setMsg( platformCatalog.getId() + " already exists");
return new ResponseEntity<>(result, HttpStatus.OK);
}
int addResult = storager.addCatalog(platformCatalog);
if (addResult > 0) {
result.setCode(0);
result.setMsg("success");
return new ResponseEntity<>(result, HttpStatus.OK);
}else {
result.setCode(-500);
result.setMsg("save error");
return new ResponseEntity<>(result, HttpStatus.OK);
}
}
/**
* 编辑目录
* @param platformCatalog 目录
* @return
*/
@ApiOperation("编辑目录")
@ApiImplicitParams({
@ApiImplicitParam(name = "platformCatalog", value = "目录信息", dataTypeClass = PlatformCatalog.class, required = true),
})
@PostMapping("/catalog/edit")
@ResponseBody
public ResponseEntity<WVPResult<List<PlatformCatalog>>> editCatalog(@RequestBody PlatformCatalog platformCatalog){
if (logger.isDebugEnabled()) {
logger.debug("编辑目录,{}", JSON.toJSONString(platformCatalog));
}
PlatformCatalog platformCatalogInStore = storager.getCatalog(platformCatalog.getId());
WVPResult<List<PlatformCatalog>> result = new WVPResult<>();
result.setCode(0);
if (platformCatalogInStore == null) {
result.setMsg( platformCatalog.getId() + " not exists");
return new ResponseEntity<>(result, HttpStatus.OK);
}
int addResult = storager.updateCatalog(platformCatalog);
if (addResult > 0) {
result.setMsg("success");
return new ResponseEntity<>(result, HttpStatus.OK);
}else {
result.setMsg("save error");
return new ResponseEntity<>(result, HttpStatus.OK);
}
}
/**
* 删除目录
* @param id 目录Id
* @return
*/
@ApiOperation("删除目录")
@ApiImplicitParams({
@ApiImplicitParam(name = "id", value = "目录Id", dataTypeClass = String.class, required = true),
})
@DeleteMapping("/catalog/del")
@ResponseBody
public ResponseEntity<WVPResult<List<PlatformCatalog>>> delCatalog(String id){
if (logger.isDebugEnabled()) {
logger.debug("删除目录,{}", id);
}
int delResult = storager.delCatalog(id);
WVPResult<List<PlatformCatalog>> result = new WVPResult<>();
result.setCode(0);
if (delResult > 0) {
result.setMsg("success");
return new ResponseEntity<>(result, HttpStatus.OK);
}else {
result.setMsg("save error");
return new ResponseEntity<>(result, HttpStatus.OK);
}
}
/**
* 删除关联
* @param platformCatalog 关联的信息
* @return
*/
@ApiOperation("删除关联")
@ApiImplicitParams({
@ApiImplicitParam(name = "platformCatalog", value = "关联的信息", dataTypeClass = PlatformCatalog.class, required = true),
})
@DeleteMapping("/catalog/relation/del")
@ResponseBody
public ResponseEntity<WVPResult<List<PlatformCatalog>>> delRelation(@RequestBody PlatformCatalog platformCatalog){
if (logger.isDebugEnabled()) {
logger.debug("删除关联,{}", JSON.toJSONString(platformCatalog));
}
int delResult = storager.delRelation(platformCatalog);
WVPResult<List<PlatformCatalog>> result = new WVPResult<>();
result.setCode(0);
if (delResult > 0) {
result.setMsg("success");
return new ResponseEntity<>(result, HttpStatus.OK);
}else {
result.setMsg("save error");
return new ResponseEntity<>(result, HttpStatus.OK);
}
}
/**
* 修改默认目录
* @param platformId 平台Id
* @param catalogId 目录Id
* @return
*/
@ApiOperation("修改默认目录")
@ApiImplicitParams({
@ApiImplicitParam(name = "platformId", value = "平台Id", dataTypeClass = String.class, required = true),
@ApiImplicitParam(name = "catalogId", value = "目录Id", dataTypeClass = String.class, required = true),
})
@PostMapping("/catalog/default/update")
@ResponseBody
public ResponseEntity<WVPResult<String>> setDefaultCatalog(String platformId, String catalogId){
if (logger.isDebugEnabled()) {
logger.debug("修改默认目录,{},{}", platformId, catalogId);
}
int updateResult = storager.setDefaultCatalog(platformId, catalogId);
WVPResult<String> result = new WVPResult<>();
result.setCode(0);
if (updateResult > 0) {
result.setMsg("success");
return new ResponseEntity<>(result, HttpStatus.OK);
}else {
result.setMsg("save error");
return new ResponseEntity<>(result, HttpStatus.OK);
}
}
} }

13
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/platform/bean/ChannelReduce.java

@ -40,6 +40,11 @@ public class ChannelReduce {
*/ */
private String platformId; private String platformId;
/**
* 目录Id
*/
private String catalogId;
public String getChannelId() { public String getChannelId() {
return channelId; return channelId;
@ -96,4 +101,12 @@ public class ChannelReduce {
public void setPlatformId(String platformId) { public void setPlatformId(String platformId) {
this.platformId = platformId; this.platformId = platformId;
} }
public String getCatalogId() {
return catalogId;
}
public void setCatalogId(String catalogId) {
this.catalogId = catalogId;
}
} }

9
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/platform/bean/UpdateChannelParam.java

@ -4,6 +4,7 @@ import java.util.List;
public class UpdateChannelParam { public class UpdateChannelParam {
private String platformId; private String platformId;
private String catalogId;
private List<ChannelReduce> channelReduces; private List<ChannelReduce> channelReduces;
public String getPlatformId() { public String getPlatformId() {
@ -21,4 +22,12 @@ public class UpdateChannelParam {
public void setChannelReduces(List<ChannelReduce> channelReduces) { public void setChannelReduces(List<ChannelReduce> channelReduces) {
this.channelReduces = channelReduces; this.channelReduces = channelReduces;
} }
public String getCatalogId() {
return catalogId;
}
public void setCatalogId(String catalogId) {
this.catalogId = catalogId;
}
} }

44
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/platformGbStream/PlatformGbStreamController.java

@ -1,44 +0,0 @@
package com.genersoft.iot.vmp.vmanager.gb28181.platformGbStream;
import com.genersoft.iot.vmp.gb28181.bean.GbStream;
import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
import com.genersoft.iot.vmp.service.IGbStreamService;
import com.github.pagehelper.PageInfo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@Api(tags = "级联平台关联视频流")
@CrossOrigin
@RestController
@RequestMapping("/api/platform_gb_stream")
public class PlatformGbStreamController {
private final static Logger logger = LoggerFactory.getLogger(PlatformGbStreamController.class);
@Autowired
private IGbStreamService gbStreamService;
@Autowired
private IVideoManagerStorager storager;
@ApiOperation("分页查询级联平台关联的视频流")
@ApiImplicitParams({
@ApiImplicitParam(name = "page", value = "当前页", dataTypeClass = Integer.class),
@ApiImplicitParam(name = "count", value = "每页条数", dataTypeClass = Integer.class),
})
@GetMapping(value = "/list")
@ResponseBody
public PageInfo<GbStream> list(@RequestParam(required = false)Integer page,
@RequestParam(required = false)Integer count){
return gbStreamService.getAll(page, count);
}
}

101
src/main/java/com/genersoft/iot/vmp/vmanager/streamPush/StreamPushController.java

@ -1,19 +1,39 @@
package com.genersoft.iot.vmp.vmanager.streamPush; package com.genersoft.iot.vmp.vmanager.streamPush;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelReader;
import com.alibaba.excel.read.metadata.ReadSheet;
import com.genersoft.iot.vmp.gb28181.bean.GbStream; import com.genersoft.iot.vmp.gb28181.bean.GbStream;
import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem; import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem;
import com.genersoft.iot.vmp.service.IMediaServerService;
import com.genersoft.iot.vmp.service.IStreamPushService; import com.genersoft.iot.vmp.service.IStreamPushService;
import com.genersoft.iot.vmp.service.impl.StreamPushUploadFileHandler;
import com.genersoft.iot.vmp.vmanager.bean.StreamPushExcelDto;
import com.genersoft.iot.vmp.vmanager.bean.WVPResult; import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
import com.github.pagehelper.PageInfo; import com.github.pagehelper.PageInfo;
import io.swagger.annotations.Api; import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam; import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams; import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
import org.apache.poi.sl.usermodel.Sheet;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.request.async.DeferredResult;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
@Api(tags = "推流信息管理") @Api(tags = "推流信息管理")
@Controller @Controller
@ -26,6 +46,12 @@ public class StreamPushController {
@Autowired @Autowired
private IStreamPushService streamPushService; private IStreamPushService streamPushService;
@Autowired
private IMediaServerService mediaServerService;
@Autowired
private DeferredResultHolder resultHolder;
@ApiOperation("推流列表查询") @ApiOperation("推流列表查询")
@ApiImplicitParams({ @ApiImplicitParams({
@ApiImplicitParam(name="page", value = "当前页", required = true, dataTypeClass = Integer.class), @ApiImplicitParam(name="page", value = "当前页", required = true, dataTypeClass = Integer.class),
@ -88,5 +114,80 @@ public class StreamPushController {
return "fail"; return "fail";
} }
} }
@PostMapping(value = "upload")
@ResponseBody
public DeferredResult<ResponseEntity<WVPResult<Object>>> uploadChannelFile(@RequestParam(value = "file") MultipartFile file){
// 最多处理文件一个小时
DeferredResult<ResponseEntity<WVPResult<Object>>> result = new DeferredResult<>(60*60*1000L);
// 录像查询以channelId作为deviceId查询
String key = DeferredResultHolder.UPLOAD_FILE_CHANNEL;
String uuid = UUID.randomUUID().toString();
if (file.isEmpty()) {
logger.warn("通道导入文件为空");
WVPResult<Object> wvpResult = new WVPResult<>();
wvpResult.setCode(-1);
wvpResult.setMsg("文件为空");
result.setResult(ResponseEntity.status(HttpStatus.BAD_REQUEST).body(wvpResult));
return result;
}
// 同时只处理一个文件
if (resultHolder.exist(key, null)) {
logger.warn("已有导入任务正在执行");
WVPResult<Object> wvpResult = new WVPResult<>();
wvpResult.setCode(-1);
wvpResult.setMsg("已有导入任务正在执行");
result.setResult(ResponseEntity.status(HttpStatus.TOO_MANY_REQUESTS).body(wvpResult));
return result;
}
resultHolder.put(key, uuid, result);
result.onTimeout(()->{
logger.warn("通道导入超时,可能文件过大");
RequestMessage msg = new RequestMessage();
msg.setKey(key);
WVPResult<Object> wvpResult = new WVPResult<>();
wvpResult.setCode(-1);
wvpResult.setMsg("导入超时,可能文件过大");
msg.setData(wvpResult);
resultHolder.invokeAllResult(msg);
});
//获取文件流
InputStream inputStream = null;
try {
String name = file.getName();
inputStream = file.getInputStream();
} catch (IOException e) {
e.printStackTrace();
}
//传入参数
ExcelReader excelReader = EasyExcel.read(inputStream, StreamPushExcelDto.class,
new StreamPushUploadFileHandler(streamPushService, mediaServerService.getDefaultMediaServer().getId(), (errorStreams, errorGBs)->{
logger.info("通道导入成功,存在重复App+Stream为{}个,存在国标ID为{}个", errorStreams.size(), errorGBs.size());
RequestMessage msg = new RequestMessage();
msg.setKey(key);
WVPResult<Map<String, List<String>>> wvpResult = new WVPResult<>();
if (errorStreams.size() == 0 && errorGBs.size() == 0) {
wvpResult.setCode(0);
wvpResult.setMsg("成功");
}else {
wvpResult.setCode(1);
wvpResult.setMsg("导入成功。但是存在重复数据");
Map<String, List<String>> errorData = new HashMap<>();
errorData.put("gbId", errorGBs);
errorData.put("stream", errorStreams);
wvpResult.setData(errorData);
}
msg.setData(wvpResult);
resultHolder.invokeAllResult(msg);
})).build();
ReadSheet readSheet = EasyExcel.readSheet(0).build();
excelReader.read(readSheet);
excelReader.finish();
return result;
}
} }

2
src/main/resources/all-application.yml

@ -27,7 +27,7 @@ spring:
datasource: datasource:
# 使用mysql 打开23-28行注释, 删除29-36行 # 使用mysql 打开23-28行注释, 删除29-36行
# name: wvp # name: wvp
# url: jdbc:mysql://127.0.0.1:3306/wvp?useUnicode=true&characterEncoding=UTF8&rewriteBatchedStatements=true # url: jdbc:mysql://127.0.0.1:3306/wvp?useUnicode=true&characterEncoding=UTF8&rewriteBatchedStatements=true&allowMultiQueries=true
# username: # username:
# password: # password:
# type: com.alibaba.druid.pool.DruidDataSource # type: com.alibaba.druid.pool.DruidDataSource

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

@ -15,7 +15,7 @@ spring:
datasource: datasource:
# 使用mysql 打开23-28行注释, 删除29-36行 # 使用mysql 打开23-28行注释, 删除29-36行
# name: wvp # name: wvp
# url: jdbc:mysql://127.0.0.1:3306/wvp?useUnicode=true&characterEncoding=UTF8&rewriteBatchedStatements=true # url: jdbc:mysql://127.0.0.1:3306/wvp?useUnicode=true&characterEncoding=UTF8&rewriteBatchedStatements=true&allowMultiQueries=true
# username: # username:
# password: # password:
# type: com.alibaba.druid.pool.DruidDataSource # type: com.alibaba.druid.pool.DruidDataSource

2
src/main/resources/application-docker.yml

@ -15,7 +15,7 @@ spring:
datasource: datasource:
# 使用mysql 打开23-28行注释, 删除29-36行 # 使用mysql 打开23-28行注释, 删除29-36行
# name: wvp # name: wvp
# url: jdbc:mysql://127.0.0.1:3306/wvp?useUnicode=true&characterEncoding=UTF8&rewriteBatchedStatements=true # url: jdbc:mysql://127.0.0.1:3306/wvp?useUnicode=true&characterEncoding=UTF8&rewriteBatchedStatements=true&allowMultiQueries=true
# username: # username:
# password: # password:
# type: com.alibaba.druid.pool.DruidDataSource # type: com.alibaba.druid.pool.DruidDataSource

BIN
src/main/resources/wvp.sqlite

Binary file not shown.

14469
web_src/package-lock.json

File diff suppressed because it is too large

3
web_src/package.json

@ -10,7 +10,7 @@
"build": "node build/build.js" "build": "node build/build.js"
}, },
"dependencies": { "dependencies": {
"axios": "^0.19.2", "axios": "^0.24.0",
"core-js": "^2.6.5", "core-js": "^2.6.5",
"echarts": "^4.9.0", "echarts": "^4.9.0",
"element-ui": "^2.15.1", "element-ui": "^2.15.1",
@ -21,6 +21,7 @@
"vue-baidu-map": "^0.21.22", "vue-baidu-map": "^0.21.22",
"vue-clipboard2": "^0.3.1", "vue-clipboard2": "^0.3.1",
"vue-clipboards": "^1.3.0", "vue-clipboards": "^1.3.0",
"vue-contextmenujs": "^1.3.13",
"vue-cookies": "^1.7.4", "vue-cookies": "^1.7.4",
"vue-router": "^3.1.6" "vue-router": "^3.1.6"
}, },

7
web_src/src/components/DeviceList.vue

@ -213,8 +213,13 @@
that.$refs[itemData.deviceId + 'refbtn' ].loading = false; that.$refs[itemData.deviceId + 'refbtn' ].loading = false;
}).catch(function(e) { }).catch(function(e) {
console.error(e) console.error(e)
that.$message({
showClose: true,
message: e,
type: 'error'
});
that.$refs[itemData.deviceId + 'refbtn' ].loading = false; that.$refs[itemData.deviceId + 'refbtn' ].loading = false;
});; });
}, },
// //
sendDevicePush: function(itemData) { sendDevicePush: function(itemData) {

2
web_src/src/components/ParentPlatformList.vue

@ -138,7 +138,7 @@ export default {
}); });
}, },
chooseChannel: function(platform) { chooseChannel: function(platform) {
this.$refs.chooseChannelDialog.openDialog(platform.serverGBId, this.initData) this.$refs.chooseChannelDialog.openDialog(platform.serverGBId, platform.name, platform.catalogId, this.initData)
}, },
initData: function() { initData: function() {
this.getPlatformList(); this.getPlatformList();

20
web_src/src/components/PushVideoList.vue

@ -8,6 +8,13 @@
<div style="background-color: #FFFFFF; margin-bottom: 1rem; position: relative; padding: 0.5rem; text-align: left;"> <div style="background-color: #FFFFFF; margin-bottom: 1rem; position: relative; padding: 0.5rem; text-align: left;">
<span style="font-size: 1rem; font-weight: bold;">推流列表</span> <span style="font-size: 1rem; font-weight: bold;">推流列表</span>
</div> </div>
<div style="background-color: #FFFFFF; margin-bottom: 1rem; position: relative; padding: 0.5rem; text-align: left;font-size: 14px;">
<el-button icon="el-icon-upload2" size="mini" style="margin-right: 1rem;" type="primary" @click="importChannel">通道导入</el-button>
<el-button icon="el-icon-download" size="mini" style="margin-right: 1rem;" type="primary" >
<a style="color: #FFFFFF; text-align: center; text-decoration: none" href="/static/file/推流通道导入.zip" download='推流通道导入.zip' >下载模板</a>
</el-button>
</div>
<devicePlayer ref="devicePlayer"></devicePlayer> <devicePlayer ref="devicePlayer"></devicePlayer>
<addStreamTOGB ref="addStreamTOGB"></addStreamTOGB> <addStreamTOGB ref="addStreamTOGB"></addStreamTOGB>
<el-table :data="pushList" border style="width: 100%" :height="winHeight"> <el-table :data="pushList" border style="width: 100%" :height="winHeight">
@ -54,6 +61,7 @@
:total="total"> :total="total">
</el-pagination> </el-pagination>
<streamProxyEdit ref="streamProxyEdit" ></streamProxyEdit> <streamProxyEdit ref="streamProxyEdit" ></streamProxyEdit>
<importChannel ref="importChannel" ></importChannel>
</el-main> </el-main>
</el-container> </el-container>
</div> </div>
@ -64,13 +72,15 @@
import devicePlayer from './dialog/devicePlayer.vue' import devicePlayer from './dialog/devicePlayer.vue'
import addStreamTOGB from './dialog/addStreamTOGB.vue' import addStreamTOGB from './dialog/addStreamTOGB.vue'
import uiHeader from './UiHeader.vue' import uiHeader from './UiHeader.vue'
import importChannel from './dialog/importChannel.vue'
export default { export default {
name: 'pushVideoList', name: 'pushVideoList',
components: { components: {
devicePlayer, devicePlayer,
addStreamTOGB, addStreamTOGB,
streamProxyEdit, streamProxyEdit,
uiHeader uiHeader,
importChannel,
}, },
data() { data() {
return { return {
@ -117,8 +127,6 @@
count: that.count count: that.count
} }
}).then(function (res) { }).then(function (res) {
console.log(res);
console.log(res.data.list);
that.total = res.data.total; that.total = res.data.total;
that.pushList = res.data.list; that.pushList = res.data.list;
that.getDeviceListLoading = false; that.getDeviceListLoading = false;
@ -196,8 +204,12 @@
s = t.getSeconds(); s = t.getSeconds();
// //
return y+'-'+(m<10?'0'+m:m)+'-'+(d<10?'0'+d:d)+' '+(h<10?'0'+h:h)+':'+(i<10?'0'+i:i)+':'+(s<10?'0'+s:s); return y+'-'+(m<10?'0'+m:m)+'-'+(d<10?'0'+d:d)+' '+(h<10?'0'+h:h)+':'+(i<10?'0'+i:i)+':'+(s<10?'0'+s:s);
} },
importChannel: function () {
this.$refs.importChannel.openDialog(()=>{
})
},
} }
}; };
</script> </script>

101
web_src/src/components/dialog/catalogEdit.vue

@ -0,0 +1,101 @@
<template>
<div id="catalogEdit" v-loading="isLoging">
<el-dialog
title="节点编辑"
width="40%"
top="2rem"
:append-to-body="true"
:close-on-click-modal="false"
:visible.sync="showDialog"
:destroy-on-close="true"
@close="close()"
>
<div id="shared" style="margin-top: 1rem;margin-right: 100px;">
<el-form ref="form" :rules="rules" :model="form" label-width="140px" >
<el-form-item label="节点编号" prop="id" >
<el-input v-model="form.id" :disabled="isEdit"></el-input>
</el-form-item>
<el-form-item label="节点名称" prop="name">
<el-input v-model="form.name" clearable></el-input>
</el-form-item>
<el-form-item>
<div style="float: right;">
<el-button type="primary" @click="onSubmit" >确认</el-button>
<el-button @click="close">取消</el-button>
</div>
</el-form-item>
</el-form>
</div>
</el-dialog>
</div>
</template>
<script>
export default {
name: "catalogEdit",
computed: {},
props: ['platformId'],
created() {},
data() {
return {
submitCallback: null,
showDialog: false,
isLoging: false,
isEdit: false,
form: {
id: null,
name: null,
platformId: null,
parentId: null,
},
rules: {
name: [{ required: true, message: "请输入名称", trigger: "blur" }],
id: [{ required: true, message: "请输入id", trigger: "blur" }]
},
};
},
methods: {
openDialog: function (isEdit, id, name, parentId, callback) {
console.log("parentId: " + parentId)
this.isEdit = isEdit;
this.form.id = id;
this.form.name = name;
this.form.platformId = this.platformId;
this.form.parentId = parentId;
this.showDialog = true;
this.submitCallback = callback;
},
onSubmit: function () {
console.log("onSubmit");
console.log(this.form);
this.$axios({
method:"post",
url:`/api/platform/catalog/${!this.isEdit? "add":"edit"}`,
data: this.form
})
.then((res)=> {
if (res.data.code === 0) {
console.log("添加/修改成功")
if (this.submitCallback)this.submitCallback()
}else {
this.$message({
showClose: true,
message: res.data.msg,
type: "error",
});
}
this.close();
})
.catch((error)=> {
console.log(error);
});
},
close: function () {
this.showDialog = false;
this.$refs.form.resetFields();
},
},
};
</script>

84
web_src/src/components/dialog/chooseChannel.vue

@ -1,25 +1,40 @@
<template> <template>
<div id="chooseChannel" v-loading="isLoging"> <div id="chooseChannel" v-loading="isLoging">
<el-dialog title="选择通道" v-if="showDialog" top="2rem" width="70%" :close-on-click-modal="false" :visible.sync="showDialog" :destroy-on-close="true" @close="close()"> <el-dialog title="选择通道" v-if="showDialog" top="2rem" width="90%" :close-on-click-modal="false" :visible.sync="showDialog" :destroy-on-close="true" @close="close()">
<el-tabs v-model="tabActiveName" > <el-row>
<el-tab-pane label="国标通道" name="gbChannel"> <el-col :span="10">
<el-container> <el-tabs v-model="catalogTabActiveName" >
<el-main style="background-color: #FFF;"> <el-tab-pane label="目录结构" name="catalog">
<chooseChannelForGb :platformId=platformId ></chooseChannelForGb> <el-container>
</el-main> <el-main v-bind:style="{backgroundColor: '#FFF', maxHeight: winHeight + 'px'}">
</el-container> <chooseChannelForCatalog ref="chooseChannelForCatalog" :platformId=platformId :platformName=platformName :defaultCatalogId=defaultCatalogId :catalogIdChange="catalogIdChange"></chooseChannelForCatalog>
</el-main>
</el-container>
</el-tab-pane>
</el-tabs>
</el-col>
<el-col :span="14">
<el-tabs v-model="tabActiveName" @tab-click="tabClick">
<el-tab-pane label="国标通道" name="gbChannel">
<el-container>
<el-main style="background-color: #FFF;">
<chooseChannelForGb ref="chooseChannelForGb" :catalogId="catalogId" :platformId=platformId :updateChoosedCallback="updateChooseChannelCallback"></chooseChannelForGb>
</el-main>
</el-container>
</el-tab-pane> </el-tab-pane>
<el-tab-pane label="直播流通道" name="streamchannel"> <el-tab-pane label="直播流通道" name="streamchannel">
<el-container> <el-container>
<el-main style="background-color: #FFF;"> <el-main style="background-color: #FFF;">
<chooseChannelFoStream :platformId=platformId ></chooseChannelFoStream> <chooseChannelFoStream ref="chooseChannelFoStream" :catalogId="catalogId" :platformId=platformId :updateChoosedCallback="updateChooseChannelCallback"></chooseChannelFoStream>
</el-main> </el-main>
</el-container> </el-container>
</el-tab-pane> </el-tab-pane>
</el-tabs> </el-tabs>
</el-col>
</el-row>
</el-dialog> </el-dialog>
</div> </div>
</template> </template>
@ -27,12 +42,14 @@
<script> <script>
import chooseChannelForGb from '../dialog/chooseChannelForGb.vue' import chooseChannelForGb from '../dialog/chooseChannelForGb.vue'
import chooseChannelFoStream from '../dialog/chooseChannelForStream.vue' import chooseChannelFoStream from '../dialog/chooseChannelForStream.vue'
import chooseChannelForCatalog from '../dialog/chooseChannelForCatalog.vue'
export default { export default {
name: 'chooseChannel', name: 'chooseChannel',
props: {}, props: {},
components: { components: {
chooseChannelForGb, chooseChannelForGb,
chooseChannelFoStream, chooseChannelFoStream,
chooseChannelForCatalog,
}, },
computed: { computed: {
// getPlayerShared: function () { // getPlayerShared: function () {
@ -47,20 +64,36 @@ export default {
return { return {
isLoging: false, isLoging: false,
tabActiveName: "gbChannel", tabActiveName: "gbChannel",
catalogTabActiveName: "catalog",
platformId: "", platformId: "",
isLoging: false, catalogId: "",
platformName: "",
defaultCatalogId: "",
showDialog: false, showDialog: false,
chooseData: {} chooseData: {},
winHeight: window.innerHeight - 250,
}; };
}, },
methods: { methods: {
openDialog: function (platformId, closeCallback) { openDialog(platformId, platformName, defaultCatalogId, closeCallback) {
console.log(platformId)
this.platformId = platformId this.platformId = platformId
this.platformName = platformName
this.defaultCatalogId = defaultCatalogId
this.showDialog = true this.showDialog = true
this.closeCallback = closeCallback this.closeCallback = closeCallback
}, },
tabClick (tab, event){
console.log(tab.label)
if (tab.label === "gbChannel") {
this.$refs.chooseChannelForGb.catalogIdChange(this.catalogId);
this.$refs.chooseChannelForGb.initData();
}else {
this.$refs.chooseChannelFoStream.catalogIdChange(this.catalogId);
this.$refs.chooseChannelFoStream.initData();
}
},
close: function() { close: function() {
this.closeCallback() this.closeCallback()
}, },
@ -88,6 +121,19 @@ export default {
}).catch(function (error) { }).catch(function (error) {
console.log(error); console.log(error);
}); });
},
catalogIdChange: function (id) {
console.log("中间模块收到: " + id)
this.catalogId = id;
if (this.tabActiveName === "gbChannel") {
this.$refs.chooseChannelForGb.catalogIdChange(id);
}else {
this.$refs.chooseChannelFoStream.catalogIdChange(id);
}
},
updateChooseChannelCallback (id){
console.log("中间模块收到选择通道变化: " + id)
this.$refs.chooseChannelForCatalog.refreshCatalogById(id)
} }
} }
}; };

309
web_src/src/components/dialog/chooseChannelForCatalog.vue

@ -0,0 +1,309 @@
<template>
<div id="chooseChannelForCatalog" >
<div style="background-color: #FFFFFF; margin-bottom: 1rem; position: relative; padding: 0.5rem; text-align: left;font-size: 14px;">
<el-tree class="el-scrollbar"
ref="tree"
id="catalogTree"
empty-text="未知节点"
node-key="id"
default-expand-all
:highlight-current="true"
:expand-on-click-node="false"
:props="props"
:load="loadNode"
@node-contextmenu="contextmenuEventHandler"
lazy>
<span class="custom-tree-node" slot-scope="{ node, data }" style="width: 100%">
<el-radio v-if="node.data.type === 0" style="margin-right: 0" v-model="chooseId" :label="node.data.id">{{''}}</el-radio>
<span v-if="node.data.type === 0 && node.level === 1" class="el-icon-s-home"></span>
<span v-if="node.data.type === 0 && node.level > 1" class="el-icon-folder-opened"></span>
<span v-if="node.data.type === 1" class="iconfont icon-shexiangtou"></span>
<span v-if="node.data.type === 2" class="iconfont icon-zhibo"></span>
<span style="padding-left: 1px">{{ node.label }}</span>
<span>
<i style="margin-left: 5rem; color: #9d9d9d; padding-right: 20px" v-if="node.data.id === defaultCatalogId">默认</i>
</span>
</span>
</el-tree>
</div>
<catalogEdit ref="catalogEdit" :platformId="platformId"></catalogEdit>
</div>
</template>
<script>
import catalogEdit from './catalogEdit.vue'
export default {
name: 'chooseChannelForCatalog',
props: ['platformId', 'platformName', 'defaultCatalogId', 'catalogIdChange'],
created() {
this.initData();
setTimeout(()=>{
if (this.catalogIdChange)this.catalogIdChange(this.defaultCatalogId);
}, 100)
},
components: {
catalogEdit,
},
data() {
return {
props: {
label: 'name',
children: 'children',
isLeaf: 'leaf'
},
chooseNode: null,
chooseId: this.defaultCatalogId,
catalogTree: null,
contextmenuShow: false
};
},
watch:{
platformId(newData, oldData){
console.log(newData)
this.initData()
},
chooseId(newData, oldData){
console.log("发送: " + newData)
if (this.catalogIdChange)this.catalogIdChange(newData);
},
},
methods: {
initData: function () {
this.getCatalog();
},
getCatalog: function(parentId, callback) {
let that = this;
this.$axios({
method:"get",
url:`/api/platform/catalog`,
params: {
platformId: that.platformId,
parentId: parentId
}
})
.then((res)=> {
if (res.data.code === 0) {
if (typeof(callback) === 'function') {
callback(res.data.data)
}
//
// if (typeof (this.$refs.tree.setCurrentKey) == "undefined") {
// this.$refs.tree.setCurrentKey(this.defaultCatalogId)
// let data = this.$refs.tree.getCurrentNode()
// if (data != null && data.id === this.defaultCatalogId) {
// this.currentCatalogChange(data, this.$refs.tree.getNode(data.id))
// }
// }
}
})
.catch(function (error) {
console.log(error);
});
},
addCatalog: function (parentId, node){
let that = this;
//
that.$refs.catalogEdit.openDialog(false, null, null, parentId, ()=>{
node.loaded = false
node.expand();
});
},
refreshCatalog: function (node){
node.loaded = false
node.expand();
},
refreshCatalogById: function (id) {
if (id) {
let node = this.$refs.tree.getNode(id);
this.refreshCatalog(node);
}
// if (nodeIds !== null) {
// let refreshNode = {}
// for (let i = 0; i < nodeIds.length; i++) {
// let node = this.$refs.tree.getNode(nodeIds[i]);
// refreshNode[node.parent.data.id] = node.parent
// }
// if (Object.values(refreshNode).length > 0) {
// for (let j = 0; j < Object.values(refreshNode).length; j++) {
// this.refreshCatalog(Object.values(refreshNode)[j]);
// }
// }
// }
},
editCatalog: function (data, node){
let that = this;
//
that.$refs.catalogEdit.openDialog(true, data.id, data.name, data.parentId, (data)=>{
node.parent.loaded = false
node.parent.expand();
});
},
removeCatalog: function (id, node){
this.$axios({
method:"delete",
url:`/api/platform/catalog/del`,
params: {
id: id,
}
})
.then((res) => {
if (res.data.code === 0) {
console.log("移除成功")
node.parent.loaded = false
node.parent.expand();
}
})
.catch(function (error) {
console.log(error);
});
},
setDefaultCatalog: function (id){
this.$axios({
method:"post",
url:`/api/platform/catalog/default/update`,
params: {
platformId: this.platformId,
catalogId: id,
}
})
.then((res)=> {
if (res.data.code === 0) {
this.defaultCatalogId = id;
}
})
.catch(function (error) {
console.log(error);
});
},
loadNode: function(node, resolve){
if (node.level === 0) {
resolve([{
name: this.platformName,
id: this.platformId,
type: 0
}]);
}
if (node.level >= 1){
this.getCatalog(node.data.id, resolve)
}
},
contextmenuEventHandler: function (event,data,node,element){
if (node.data.type !== 0) {
data.parentId = node.parent.data.id;
this.$contextmenu({
items: [
{
label: "移除通道",
icon: "el-icon-delete",
disabled: false,
onClick: () => {
this.$axios({
method:"delete",
url:"/api/platform/catalog/relation/del",
data: data
}).then((res)=>{
console.log("移除成功")
node.parent.loaded = false
node.parent.expand();
}).catch(function (error) {
console.log(error);
});
}
}
],
event, //
customClass: "custom-class", // class
zIndex: 3000, // z-index
});
}else {
this.$contextmenu({
items: [
{
label: "刷新节点",
icon: "el-icon-refresh",
disabled: false,
onClick: () => {
this.refreshCatalog(node);
}
},
{
label: "新建节点",
icon: "el-icon-plus",
disabled: false,
onClick: () => {
this.addCatalog(data.id, node);
}
},
{
label: "修改节点",
icon: "el-icon-edit",
disabled: node.level === 1,
onClick: () => {
this.editCatalog(data, node);
}
},
{
label: "删除节点",
icon: "el-icon-delete",
disabled: node.level === 1,
divided: true,
onClick: () => {
this.removeCatalog(data.id, node)
}
},
{
label: "设为默认",
icon: "el-icon-folder-checked",
disabled: node.data.id === this.defaultCatalogId,
onClick: () => {
this.setDefaultCatalog(data.id)
},
},
// {
// label: "",
// icon: "el-icon-download",
// disabled: false,
// children: [
// {
// label: "",
// onClick: () => {
//
// },
// },
// {
// label: "",
// onClick: () => {
//
// },
// }
// ]
// },
],
event, //
customClass: "custom-class", // class
zIndex: 3000, // z-index
});
}
return false;
},
}
};
</script>
<style>
#catalogTree{
display: inline-block;
}
</style>

108
web_src/src/components/dialog/chooseChannelForGb.vue

@ -21,15 +21,14 @@
<el-option label="离线" value="false"></el-option> <el-option label="离线" value="false"></el-option>
</el-select> </el-select>
<el-checkbox @change="shareAllCheckedChanage">全部共享</el-checkbox> <!-- <el-checkbox @change="shareAllCheckedChange">全部共享</el-checkbox>-->
</div> </div>
<el-table ref="gbChannelsTable" :data="gbChannels" border style="width: 100%" @selection-change="checkedChanage" > <el-table ref="gbChannelsTable" :data="gbChannels" border style="width: 100%" :height="winHeight">
<el-table-column type="selection" width="55" align="center" fixed > </el-table-column> <el-table-column prop="channelId" label="通道编号" width="180" align="center">
<el-table-column prop="channelId" label="通道编号" width="210">
</el-table-column> </el-table-column>
<el-table-column prop="name" label="通道名称" show-overflow-tooltip> <el-table-column prop="name" label="通道名称" show-overflow-tooltip align="center">
</el-table-column> </el-table-column>
<el-table-column prop="deviceId" label="设备编号" width="210" > <el-table-column prop="deviceId" label="设备编号" width="180" align="center">
</el-table-column> </el-table-column>
<el-table-column label="设备地址" width="180" align="center"> <el-table-column label="设备地址" width="180" align="center">
<template slot-scope="scope"> <template slot-scope="scope">
@ -40,6 +39,14 @@
</el-table-column> </el-table-column>
<el-table-column prop="manufacturer" label="厂家" align="center"> <el-table-column prop="manufacturer" label="厂家" align="center">
</el-table-column> </el-table-column>
<el-table-column label="操作" width="100" align="center" fixed="right">
<template slot-scope="scope">
<el-button-group>
<el-button size="mini" icon="el-icon-plus" v-if="!scope.row.platformId" @click="add(scope.row)">添加</el-button>
<el-button size="mini" icon="el-icon-delete" v-if="scope.row.platformId" type="danger" @click="remove(scope.row)">移除</el-button>
</el-button-group>
</template>
</el-table-column>
</el-table> </el-table>
<el-pagination style="float: right;margin-top: 1rem;" @size-change="handleSizeChange" @current-change="currentChange" :current-page="currentPage" :page-size="count" :page-sizes="[10, 20, 30, 50]" layout="total, sizes, prev, pager, next" :total="total"> <el-pagination style="float: right;margin-top: 1rem;" @size-change="handleSizeChange" @current-change="currentChange" :current-page="currentPage" :page-size="count" :page-sizes="[10, 20, 30, 50]" layout="total, sizes, prev, pager, next" :total="total">
</el-pagination> </el-pagination>
@ -49,7 +56,6 @@
<script> <script>
export default { export default {
name: 'chooseChannelForGb', name: 'chooseChannelForGb',
props: {},
computed: { computed: {
// getPlayerShared: function () { // getPlayerShared: function () {
// return { // return {
@ -59,7 +65,7 @@ export default {
// }; // };
// } // }
}, },
props: ['platformId'], props: ['platformId','catalogId', 'updateChoosedCallback'],
created() { created() {
this.initData(); this.initData();
}, },
@ -74,7 +80,8 @@ export default {
currentPage: 1, currentPage: 1,
count: 10, count: 10,
total: 0, total: 0,
eventEnanle: false eventEnanle: false,
winHeight: window.innerHeight - 400,
}; };
}, },
@ -97,28 +104,61 @@ export default {
this.count = val; this.count = val;
console.log(val) console.log(val)
this.initData(); this.initData();
}, },
rowcheckedChanage: function (val, row) { rowcheckedChange: function (val, row) {
console.log(val) console.log(val)
console.log(row) console.log(row)
}, },
checkedChanage: function (val) { add: function (row) {
var that = this; console.log(row)
row.catalogId = this.catalogId
row.platformId = this.platformId
this.$axios({
method:"post",
url:"/api/platform/update_channel_for_gb",
data:{
platformId: this.platformId,
channelReduces: [row],
catalogId: this.catalogId
}
}).then((res)=>{
console.log("保存成功")
if(this.updateChoosedCallback)this.updateChoosedCallback(this.catalogId)
}).catch(function (error) {
console.log(error);
});
},
remove: function (row) {
console.log(row)
this.$axios({
method:"delete",
url:"/api/platform/del_channel_for_gb",
data:{
platformId: this.platformId,
channelReduces: [row]
}
}).then((res)=>{
console.log("移除成功")
if(this.updateChoosedCallback)this.updateChoosedCallback(row.catalogId)
row.platformId = null;
row.catalogId = null
}).catch(function (error) {
console.log(error);
});
},
checkedChange: function (val) {
let that = this;
if (!that.eventEnanle) { if (!that.eventEnanle) {
return; return;
} }
var tabelData = JSON.parse(JSON.stringify(this.$refs.gbChannelsTable.data)); let newData = {};
console.log("checkedChanage") let addData = [];
console.log(val) let delData = [];
var newData = {};
var addData = [];
var delData = [];
if (val.length > 0) { if (val.length > 0) {
for (let i = 0; i < val.length; i++) { for (let i = 0; i < val.length; i++) {
const element = val[i]; const element = val[i];
var key = element.deviceId + "_" + element.channelId; let key = element.deviceId + "_" + element.channelId;
newData[key] = element; newData[key] = element;
if (!!!that.gbChoosechannel[key]){ if (!!!that.gbChoosechannel[key]){
addData.push(element) addData.push(element)
@ -127,7 +167,7 @@ export default {
} }
} }
var oldKeys = Object.keys(that.gbChoosechannel); let oldKeys = Object.keys(that.gbChoosechannel);
if (oldKeys.length > 0) { if (oldKeys.length > 0) {
for (let i = 0; i < oldKeys.length; i++) { for (let i = 0; i < oldKeys.length; i++) {
const key = oldKeys[i]; const key = oldKeys[i];
@ -136,7 +176,7 @@ export default {
} }
}else{ }else{
var oldKeys = Object.keys(that.gbChoosechannel); let oldKeys = Object.keys(that.gbChoosechannel);
if (oldKeys.length > 0) { if (oldKeys.length > 0) {
for (let i = 0; i < oldKeys.length; i++) { for (let i = 0; i < oldKeys.length; i++) {
const key = oldKeys[i]; const key = oldKeys[i];
@ -152,15 +192,17 @@ export default {
url:"/api/platform/update_channel_for_gb", url:"/api/platform/update_channel_for_gb",
data:{ data:{
platformId: that.platformId, platformId: that.platformId,
channelReduces: addData channelReduces: addData,
catalogId: that.catalogId
} }
}).then((res)=>{ }).then((res)=>{
console.log("保存成功") console.log("保存成功")
if(that.updateChoosedCallback)that.updateChoosedCallback(that.catalogId)
}).catch(function (error) { }).catch(function (error) {
console.log(error); console.log(error);
}); });
} }
if (Object.keys(delData).length >0) { if (delData.length >0) {
that.$axios({ that.$axios({
method:"delete", method:"delete",
url:"/api/platform/del_channel_for_gb", url:"/api/platform/del_channel_for_gb",
@ -170,14 +212,18 @@ export default {
} }
}).then((res)=>{ }).then((res)=>{
console.log("移除成功") console.log("移除成功")
let nodeIds = new Array();
for (let i = 0; i < delData.length; i++) {
nodeIds.push(delData[i].channelId)
}
if(that.updateChoosedCallback)that.updateChoosedCallback(null, nodeIds)
}).catch(function (error) { }).catch(function (error) {
console.log(error); console.log(error);
}); });
} }
}, },
shareAllCheckedChanage: function (val) { shareAllCheckedChange: function (val) {
this.chooseChanage(null, val)
}, },
getChannelList: function () { getChannelList: function () {
let that = this; let that = this;
@ -215,7 +261,7 @@ export default {
} }
} }
that.eventEnanle = true; that.eventEnanle = true;
// that.checkedChanage(chooseGBS) // that.checkedChange(chooseGBS)
}) })
console.log(that.gbChoosechannel) console.log(that.gbChoosechannel)
}) })
@ -230,6 +276,10 @@ export default {
handleGBSelectionChange: function() { handleGBSelectionChange: function() {
this.initData(); this.initData();
}, },
// catalogIdChange: function(id) {
// this.catalogId = id;
// console.log(" " + id)
// },
} }
}; };
</script> </script>

74
web_src/src/components/dialog/chooseChannelForStream.vue

@ -1,14 +1,13 @@
<template> <template>
<div id="chooseChannelFoStream" > <div id="chooseChannelFoStream" >
<el-table ref="gbStreamsTable" :data="gbStreams" border style="width: 100%" @selection-change="checkedChanage" > <el-table ref="gbStreamsTable" :data="gbStreams" border style="width: 100%" :height="winHeight">
<el-table-column type="selection" width="55" align="center" fixed > </el-table-column> <el-table-column prop="name" label="名称" show-overflow-tooltip align="center">
<el-table-column prop="name" label="名称" show-overflow-tooltip>
</el-table-column> </el-table-column>
<el-table-column prop="app" label="应用名" show-overflow-tooltip> <el-table-column prop="app" label="应用名" show-overflow-tooltip align="center">
</el-table-column> </el-table-column>
<el-table-column prop="stream" label="流ID" show-overflow-tooltip> <el-table-column prop="stream" label="流ID" show-overflow-tooltip align="center">
</el-table-column> </el-table-column>
<el-table-column prop="gbId" label="国标编码" show-overflow-tooltip> <el-table-column prop="gbId" label="国标编码" show-overflow-tooltip align="center">
</el-table-column> </el-table-column>
<el-table-column label="流来源" width="100" align="center"> <el-table-column label="流来源" width="100" align="center">
<template slot-scope="scope"> <template slot-scope="scope">
@ -18,6 +17,14 @@
</div> </div>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="操作" width="100" align="center" fixed="right" >
<template slot-scope="scope">
<el-button-group>
<el-button size="mini" icon="el-icon-plus" v-if="!scope.row.platformId" @click="add(scope.row)">添加</el-button>
<el-button size="mini" icon="el-icon-delete" v-if="scope.row.platformId" type="danger" @click="remove(scope.row)">移除</el-button>
</el-button-group>
</template>
</el-table-column>
</el-table> </el-table>
<el-pagination style="float: right;margin-top: 1rem;" @size-change="handleSizeChange" @current-change="currentChange" :current-page="currentPage" :page-size="count" :page-sizes="[10, 20, 30, 50]" layout="total, sizes, prev, pager, next" :total="total"> <el-pagination style="float: right;margin-top: 1rem;" @size-change="handleSizeChange" @current-change="currentChange" :current-page="currentPage" :page-size="count" :page-sizes="[10, 20, 30, 50]" layout="total, sizes, prev, pager, next" :total="total">
</el-pagination> </el-pagination>
@ -27,7 +34,6 @@
<script> <script>
export default { export default {
name: 'chooseChannelFoStream', name: 'chooseChannelFoStream',
props: {},
computed: { computed: {
// getPlayerShared: function () { // getPlayerShared: function () {
// return { // return {
@ -37,7 +43,7 @@ export default {
// }; // };
// } // }
}, },
props: ['platformId'], props: ['platformId', 'catalogId', 'updateChoosedCallback'],
created() { created() {
this.initData(); this.initData();
}, },
@ -52,7 +58,8 @@ export default {
currentPage: 1, currentPage: 1,
count: 10, count: 10,
total: 0, total: 0,
eventEnanle: false eventEnanle: false,
winHeight: window.innerHeight - 350,
}; };
}, },
@ -81,14 +88,49 @@ export default {
console.log(val) console.log(val)
console.log(row) console.log(row)
}, },
add: function (row) {
console.log(row)
row.catalogId = this.catalogId
row.platformId = this.platformId
this.$axios({
method:"post",
url:"/api/gbStream/add",
data:{
platformId: this.platformId,
catalogId: this.catalogId,
gbStreams: [row],
}
}).then((res)=>{
console.log("保存成功")
if(this.updateChoosedCallback)this.updateChoosedCallback(this.catalogId)
}).catch(function (error) {
console.log(error);
});
},
remove: function (row) {
console.log(row)
this.$axios({
method:"delete",
url:"/api/gbStream/del",
data:{
platformId: this.platformId,
gbStreams: [row],
}
}).then((res)=>{
console.log("移除成功")
if(this.updateChoosedCallback)this.updateChoosedCallback(row.catalogId)
row.platformId = null;
row.catalogId = null
}).catch(function (error) {
console.log(error);
});
},
checkedChanage: function (val) { checkedChanage: function (val) {
var that = this; var that = this;
if (!that.eventEnanle) { if (!that.eventEnanle) {
return; return;
} }
var tabelData = JSON.parse(JSON.stringify(this.$refs.gbStreamsTable.data));
console.log("checkedChanage")
console.log(val)
var newData = {}; var newData = {};
var addData = []; var addData = [];
@ -131,10 +173,12 @@ export default {
url:"/api/gbStream/add", url:"/api/gbStream/add",
data:{ data:{
platformId: that.platformId, platformId: that.platformId,
catalogId: that.catalogId,
gbStreams: addData, gbStreams: addData,
} }
}).then((res)=>{ }).then((res)=>{
console.log("保存成功") console.log("保存成功")
if(this.updateChoosedCallback)this.updateChoosedCallback(this.catalogId)
}).catch(function (error) { }).catch(function (error) {
console.log(error); console.log(error);
}); });
@ -145,10 +189,12 @@ export default {
method:"delete", method:"delete",
url:"/api/gbStream/del", url:"/api/gbStream/del",
data:{ data:{
platformId: that.platformId,
gbStreams: delData, gbStreams: delData,
} }
}).then((res)=>{ }).then((res)=>{
console.log("移除成功") console.log("移除成功")
if(this.updateChoosedCallback)this.updateChoosedCallback(this.catalogId)
}).catch(function (error) { }).catch(function (error) {
console.log(error); console.log(error);
}); });
@ -207,6 +253,10 @@ export default {
handleGBSelectionChange: function() { handleGBSelectionChange: function() {
this.initData(); this.initData();
}, },
// catalogIdChange: function(id) {
// this.catalogId = id;
// console.log(" " + id)
// },
} }
}; };
</script> </script>

6
web_src/src/components/dialog/deviceEdit.vue

@ -10,7 +10,7 @@
@close="close()" @close="close()"
> >
<div id="shared" style="margin-top: 1rem;margin-right: 100px;"> <div id="shared" style="margin-top: 1rem;margin-right: 100px;">
<el-form ref="form" :rules="rules" :model="form" label-width="140px" > <el-form ref="form" :rules="rules" :model="form" label-width="240px" >
<el-form-item label="设备编号" > <el-form-item label="设备编号" >
<el-input v-model="form.deviceId" disabled></el-input> <el-input v-model="form.deviceId" disabled></el-input>
</el-form-item> </el-form-item>
@ -36,8 +36,8 @@
<el-option key="UTF-8" label="UTF-8" value="utf-8"></el-option> <el-option key="UTF-8" label="UTF-8" value="utf-8"></el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="目录订阅周期" prop="subscribeCycleForCatalog" > <el-form-item label="目录订阅周期(0为停用订阅)" prop="subscribeCycleForCatalog" >
<el-input v-model="form.subscribeCycleForCatalog" clearable></el-input> <el-input v-model="form.subscribeCycleForCatalog" clearable ></el-input>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<div style="float: right;"> <div style="float: right;">

125
web_src/src/components/dialog/importChannel.vue

@ -0,0 +1,125 @@
<template>
<div id="importChannel" v-loading="isLoging">
<el-dialog
title="导入通道数据"
width="30rem"
top="2rem"
:append-to-body="true"
:close-on-click-modal="false"
:visible.sync="showDialog"
:destroy-on-close="true"
@close="close()"
>
<div>
<el-upload
class="upload-box"
drag
:action="uploadUrl"
name="file"
:on-success="successHook"
:on-error="errorHook"
>
<i class="el-icon-upload"></i>
<div class="el-upload__text">将文件拖到此处<em>点击上传</em></div>
<div class="el-upload__tip" slot="tip">只能上传 csv / xls / xlsx 文件</div>
</el-upload>
</div>
</el-dialog>
<ShowErrorData ref="showErrorData" :gbIds="errorGBIds" :streams="errorStreams" ></ShowErrorData>
</div>
</template>
<script>
import ShowErrorData from './importChannelShowErrorData.vue'
export default {
name: "importChannel",
components: {
ShowErrorData,
},
created() {},
data() {
return {
submitCallback: null,
showDialog: false,
isLoging: false,
isEdit: false,
errorStreams: null,
errorGBIds: null,
uploadUrl: process.env.NODE_ENV === 'development'?`debug/api/push/upload`:`api/push/upload`,
};
},
methods: {
openDialog: function (callback) {
this.showDialog = true;
this.submitCallback = callback;
},
onSubmit: function () {
console.log("onSubmit");
console.log(this.form);
this.$axios({
method:"post",
url:`/api/platform/catalog/${!this.isEdit? "add":"edit"}`,
data: this.form
})
.then((res)=> {
if (res.data.code === 0) {
console.log("添加/修改成功")
if (this.submitCallback)this.submitCallback()
}else {
this.$message({
showClose: true,
message: res.data.msg,
type: "error",
});
}
this.close();
})
.catch((error)=> {
console.log(error);
});
},
close: function () {
this.showDialog = false;
},
successHook: function(response, file, fileList){
if (response.code === 0) {
this.$message({
showClose: true,
message: response.msg,
type: "success",
});
}else if (response.code === 1) {
this.errorGBIds = response.data.gbId
this.errorStreams = response.data.stream
console.log(this.$refs)
console.log(this.$refs.showErrorData)
this.$refs.showErrorData.openDialog()
}else {
this.$message({
showClose: true,
message: response.msg,
type: "error",
});
}
},
errorHook: function (err, file, fileList) {
this.$message({
showClose: true,
message: err,
type: "error",
});
}
},
};
</script>
<style>
.upload-box{
text-align: center;
}
.errDataBox{
max-height: 15rem;
overflow: auto;
}
</style>

64
web_src/src/components/dialog/importChannelShowErrorData.vue

@ -0,0 +1,64 @@
<template>
<div id="importChannelShowErrorData" v-loading="isLoging">
<el-dialog
title="导入通道数据成功,但数据存在重复"
width="30rem"
top="2rem"
:append-to-body="true"
:close-on-click-modal="false"
:visible.sync="showDialog"
:destroy-on-close="true"
@close="close()"
>
<div >
重复国标ID:
<el-button style="float: right;" type="primary" size="mini" icon="el-icon-document-copy" title="点击拷贝" v-clipboard="gbIds.join(',')" @success="$message({type:'success', message:'成功拷贝到粘贴板'})">复制</el-button>
<ul class="errDataBox">
<li v-for="id in gbIds" >
{{ id }}
</li>
</ul>
</div>
<div >
重复App/stream:
<el-button style="float: right;" type="primary" size="mini" icon="el-icon-document-copy" title="点击拷贝" v-clipboard="streams.join(',')" @success="$message({type:'success', message:'成功拷贝到粘贴板'})">复制</el-button>
<ul class="errDataBox">
<li v-for="id in streams" >
{{ id }}
</li>
</ul>
</div>
</el-dialog>
</div>
</template>
<script>
export default {
name: "importChannelShowErrorData",
computed: {},
created() {},
props: ['gbIds', 'streams'],
data() {
return {
isLoging: false,
showDialog: false,
};
},
methods: {
openDialog: function () {
this.showDialog = true;
},
close: function () {
this.showDialog = false;
},
},
};
</script>
<style>
.errDataBox{
max-height: 15rem;
overflow: auto;
}
</style>

2
web_src/src/components/dialog/jessibuca.vue

@ -78,7 +78,7 @@ export default {
this.jessibuca = new window.Jessibuca(Object.assign( this.jessibuca = new window.Jessibuca(Object.assign(
{ {
container: this.$refs.container, container: this.$refs.container,
videoBuffer: 0.5, // videoBuffer: 0.2, //
isResize: true, isResize: true,
isFlv: true, isFlv: true,
decoder: "./static/js/jessibuca/index.js", decoder: "./static/js/jessibuca/index.js",

1
web_src/src/components/dialog/platformEdit.vue

@ -196,6 +196,7 @@ export default {
this.platform.transport = platform.transport; this.platform.transport = platform.transport;
this.platform.characterSet = platform.characterSet; this.platform.characterSet = platform.characterSet;
this.platform.shareAllLiveStream = platform.shareAllLiveStream; this.platform.shareAllLiveStream = platform.shareAllLiveStream;
this.platform.catalogId = platform.catalogId;
this.onSubmit_text = "保存"; this.onSubmit_text = "保存";
} }
this.showDialog = true; this.showDialog = true;

2
web_src/src/main.js

@ -12,6 +12,7 @@ import VueClipboard from 'vue-clipboard2';
import { Notification } from 'element-ui'; import { Notification } from 'element-ui';
import Fingerprint2 from 'fingerprintjs2'; import Fingerprint2 from 'fingerprintjs2';
import VueClipboards from 'vue-clipboards'; import VueClipboards from 'vue-clipboards';
import Contextmenu from "vue-contextmenujs"
// 生成唯一ID // 生成唯一ID
@ -37,6 +38,7 @@ Vue.use(VueCookies);
Vue.use(VueClipboards); Vue.use(VueClipboards);
Vue.prototype.$axios = axios; Vue.prototype.$axios = axios;
Vue.prototype.$notify = Notification; Vue.prototype.$notify = Notification;
Vue.use(Contextmenu);
axios.defaults.baseURL = (process.env.NODE_ENV === 'development') ? process.env.BASE_API : ""; axios.defaults.baseURL = (process.env.NODE_ENV === 'development') ? process.env.BASE_API : "";

26
web_src/static/css/iconfont.css

@ -1,8 +1,8 @@
@font-face { @font-face {
font-family: "iconfont"; /* Project id 1291092 */ font-family: "iconfont"; /* Project id 1291092 */
src: url('iconfont.woff2?t=1637741914969') format('woff2'), src: url('iconfont.woff2?t=1640922722742') format('woff2'),
url('iconfont.woff?t=1637741914969') format('woff'), url('iconfont.woff?t=1640922722742') format('woff'),
url('iconfont.ttf?t=1637741914969') format('truetype'); url('iconfont.ttf?t=1640922722742') format('truetype');
} }
.iconfont { .iconfont {
@ -13,6 +13,22 @@
-moz-osx-font-smoothing: grayscale; -moz-osx-font-smoothing: grayscale;
} }
.icon-wxbzhuye:before {
content: "\e7d1";
}
.icon-mulu:before {
content: "\e7d2";
}
.icon-zhibo:before {
content: "\e8c1";
}
.icon-shexiangtou:before {
content: "\e7d3";
}
.icon-suoxiao:before { .icon-suoxiao:before {
content: "\e79a"; content: "\e79a";
} }
@ -49,7 +65,7 @@
content: "\e7a2"; content: "\e7a2";
} }
.icon-kuaijin:before { .icon-houtui:before {
content: "\e7a3"; content: "\e7a3";
} }
@ -57,7 +73,7 @@
content: "\e7a4"; content: "\e7a4";
} }
.icon-kuaitui:before { .icon-kuaijin:before {
content: "\e7a5"; content: "\e7a5";
} }

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save