diff --git a/README.md b/README.md index e7645c60..cc295d5a 100644 --- a/README.md +++ b/README.md @@ -95,15 +95,13 @@ https://gitee.com/pan648540858/wvp-GB28181-pro.git - [X] 平台状态查询 - [X] 平台信息查询 - [X] 平台远程启动 + - [X] 每个级联平台可自定义的虚拟目录 - [X] 添加RTSP视频 - [X] 添加接口鉴权 -- [ ] 添加ONVIF探测局域网内的设备 - [X] 添加RTMP视频 - [X] 云端录像(需要部署单独服务配合使用) - [X] 多流媒体节点,自动选择负载最低的节点使用。 - [X] 支持使用mysql作为数据库,默认sqlite3,开箱即用。 -- [ ] 添加系统配置 -- [ ] 添加用户管理 - [X] WEB端支持播放H264与H265,音频支持G.711A/G.711U/AAC,覆盖国标常用编码格式。 # docker快速体验 @@ -118,7 +116,7 @@ docker使用详情查看:[https://hub.docker.com/r/648540858/wvp_pro](https:// 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。 diff --git a/pom.xml b/pom.xml index 2a67fb52..991abc68 100644 --- a/pom.xml +++ b/pom.xml @@ -161,7 +161,7 @@ 2.1.3 - + com.alibaba fastjson @@ -203,6 +203,13 @@ 1.12 + + + com.alibaba + easyexcel + 3.0.4 + + org.springframework.session spring-session-core diff --git a/sql/dump-wvp-202201051515.sql b/sql/dump-wvp-202201051515.sql new file mode 100644 index 00000000..84590e49 --- /dev/null +++ b/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 diff --git a/sql/mysql.sql b/sql/mysql.sql index 57243420..8cbd4934 100644 --- a/sql/mysql.sql +++ b/sql/mysql.sql @@ -171,6 +171,7 @@ create table parent_platform keepTimeout varchar(50) null, transport varchar(50) null, characterSet varchar(50) null, + catalogId varchar(50) not null, ptz int null, rtcp int null, status bit null, @@ -178,12 +179,22 @@ create table parent_platform 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 ( 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) ); @@ -192,6 +203,7 @@ 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) ); diff --git a/src/main/java/com/genersoft/iot/vmp/common/VideoManagerConstants.java b/src/main/java/com/genersoft/iot/vmp/common/VideoManagerConstants.java index 35025255..ffbed508 100644 --- a/src/main/java/com/genersoft/iot/vmp/common/VideoManagerConstants.java +++ b/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_SN_PREFIX = "VMP_SIP_SN_"; + + public static final String SIP_SUBSCRIBE_PREFIX = "SIP_SUBSCRIBE_"; + //************************** redis 消息********************************* 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_GPS_MSG_PREFIX = "WVP_STREAM_GPS_MSG_"; } diff --git a/src/main/java/com/genersoft/iot/vmp/conf/DynamicTask.java b/src/main/java/com/genersoft/iot/vmp/conf/DynamicTask.java index 10dfc086..c9572ae5 100644 --- a/src/main/java/com/genersoft/iot/vmp/conf/DynamicTask.java +++ b/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.context.annotation.Bean; import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; -import org.springframework.scheduling.support.CronTrigger; import org.springframework.stereotype.Component; import java.util.Map; @@ -40,4 +39,8 @@ public class DynamicTask { } } + public boolean contains(String key) { + return futureMap.get(key) != null; + } + } diff --git a/src/main/java/com/genersoft/iot/vmp/conf/RedisConfig.java b/src/main/java/com/genersoft/iot/vmp/conf/RedisConfig.java index dcb0e811..5f04a083 100644 --- a/src/main/java/com/genersoft/iot/vmp/conf/RedisConfig.java +++ b/src/main/java/com/genersoft/iot/vmp/conf/RedisConfig.java @@ -1,12 +1,16 @@ 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.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.cache.annotation.CachingConfigurerSupport; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.listener.PatternTopic; import org.springframework.data.redis.listener.RedisMessageListenerContainer; import org.springframework.data.redis.serializer.StringRedisSerializer; @@ -41,6 +45,9 @@ public class RedisConfig extends CachingConfigurerSupport { @Value("${spring.redis.poolMaxWait:5}") private int poolMaxWait; + @Autowired + private RedisGPSMsgListener redisGPSMsgListener; + @Bean public JedisPool jedisPool() { if (StringUtils.isBlank(password)) { @@ -85,6 +92,7 @@ public class RedisConfig extends CachingConfigurerSupport { RedisMessageListenerContainer container = new RedisMessageListenerContainer(); container.setConnectionFactory(connectionFactory); + container.addMessageListener(redisGPSMsgListener, new PatternTopic(VideoManagerConstants.WVP_MSG_GPS_PREFIX)); return container; } diff --git a/src/main/java/com/genersoft/iot/vmp/conf/RedisKeyExpirationEventMessageListener.java b/src/main/java/com/genersoft/iot/vmp/conf/RedisKeyExpirationEventMessageListener.java new file mode 100644 index 00000000..a2281ab0 --- /dev/null +++ b/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(); + } +} diff --git a/src/main/java/com/genersoft/iot/vmp/conf/runner/SipDeviceRunner.java b/src/main/java/com/genersoft/iot/vmp/conf/runner/SipDeviceRunner.java index 26b0a5cd..da4e2eda 100644 --- a/src/main/java/com/genersoft/iot/vmp/conf/runner/SipDeviceRunner.java +++ b/src/main/java/com/genersoft/iot/vmp/conf/runner/SipDeviceRunner.java @@ -1,7 +1,8 @@ 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.gb28181.bean.Device; +import com.genersoft.iot.vmp.service.IDeviceService; import com.genersoft.iot.vmp.storager.IRedisCatchStorage; import com.genersoft.iot.vmp.storager.IVideoManagerStorager; import org.springframework.beans.factory.annotation.Autowired; @@ -28,6 +29,9 @@ public class SipDeviceRunner implements CommandLineRunner { @Autowired private UserSetup userSetup; + @Autowired + private IDeviceService deviceService; + @Override public void run(String... args) throws Exception { // 读取redis没有心跳信息的则设置为离线,等收到下次心跳设置为在线 @@ -36,9 +40,15 @@ public class SipDeviceRunner implements CommandLineRunner { List onlineForAll = redisCatchStorage.getOnlineForAll(); for (String deviceId : onlineForAll) { storager.online(deviceId); + Device device = redisCatchStorage.getDevice(deviceId); + if (device != null && device.getSubscribeCycleForCatalog() > 0) { + // 查询在线设备那些开启了订阅,为设备开启定时的目录订阅 + deviceService.addCatalogSubscribe(device); + } } // 重置cseq计数 redisCatchStorage.resetAllCSEQ(); - // TODO 查询在线设备那些开启了订阅,为设备开启定时的目录订阅 + + } } diff --git a/src/main/java/com/genersoft/iot/vmp/conf/security/AnonymousAuthenticationEntryPoint.java b/src/main/java/com/genersoft/iot/vmp/conf/security/AnonymousAuthenticationEntryPoint.java index ebfac955..2356b57b 100644 --- a/src/main/java/com/genersoft/iot/vmp/conf/security/AnonymousAuthenticationEntryPoint.java +++ b/src/main/java/com/genersoft/iot/vmp/conf/security/AnonymousAuthenticationEntryPoint.java @@ -21,7 +21,7 @@ public class AnonymousAuthenticationEntryPoint implements AuthenticationEntryPoi @Override 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", "*"); // 允许自定义请求头token(允许head跨域) diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/CmdType.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/CmdType.java new file mode 100644 index 00000000..ed5cad6c --- /dev/null +++ b/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"; +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/DeviceNotFoundEvent.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/DeviceNotFoundEvent.java new file mode 100644 index 00000000..4e55011f --- /dev/null +++ b/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(); + } +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/ParentPlatform.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/ParentPlatform.java index fabae8a1..0c061450 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/ParentPlatform.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/ParentPlatform.java @@ -109,6 +109,11 @@ public class ParentPlatform { */ private boolean shareAllLiveStream; + /** + * 默认目录Id,自动添加的通道多放在这个目录下 + */ + private String catalogId; + public Integer getId() { return id; } @@ -277,4 +282,12 @@ public class ParentPlatform { public void setShareAllLiveStream(boolean shareAllLiveStream) { this.shareAllLiveStream = shareAllLiveStream; } + + public String getCatalogId() { + return catalogId; + } + + public void setCatalogId(String catalogId) { + this.catalogId = catalogId; + } } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/PlatformCatalog.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/PlatformCatalog.java new file mode 100644 index 00000000..065971dd --- /dev/null +++ b/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; + } + +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/PlatformGbStream.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/PlatformGbStream.java index a4f7730d..1ab38148 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/PlatformGbStream.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/PlatformGbStream.java @@ -4,6 +4,7 @@ public class PlatformGbStream { private String app; private String stream; private String platformId; + private String catalogId; public String getApp() { return app; @@ -29,4 +30,11 @@ public class PlatformGbStream { this.platformId = platformId; } + public String getCatalogId() { + return catalogId; + } + + public void setCatalogId(String catalogId) { + this.catalogId = catalogId; + } } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/SubscribeInfo.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/SubscribeInfo.java new file mode 100644 index 00000000..60418f2c --- /dev/null +++ b/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; + } +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/event/EventPublisher.java b/src/main/java/com/genersoft/iot/vmp/gb28181/event/EventPublisher.java index 9495e9de..76b44271 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/event/EventPublisher.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/event/EventPublisher.java @@ -1,19 +1,28 @@ package com.genersoft.iot.vmp.gb28181.event; 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.platformKeepaliveExpire.PlatformKeepaliveExpireEvent; 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.ZLMOnlineEvent; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationEventPublisher; +import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Component; import com.genersoft.iot.vmp.gb28181.bean.DeviceAlarm; import com.genersoft.iot.vmp.gb28181.event.alarm.AlarmEvent; 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事件通知推送器,支持推送在线事件、离线事件 * @author: swwheihei @@ -80,4 +89,49 @@ public class EventPublisher { outEvent.setMediaServerId(mediaServerId); applicationEventPublisher.publishEvent(outEvent); } + + @Async + public void catalogEventPublish(String platformId, DeviceChannel deviceChannel, String type) { + List deviceChannelList = new ArrayList<>(); + deviceChannelList.add(deviceChannel); + catalogEventPublish(platformId, deviceChannelList, type); + } + + @Async + public void catalogEventPublish(String platformId, List deviceChannels, String type) { + CatalogEvent outEvent = new CatalogEvent(this); + List channels = new ArrayList<>(); + if (deviceChannels.size() > 1) { + // 数据去重 + Set 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 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 gbStreamList = new ArrayList<>(); + gbStreamList.add(gbStream); + catalogEventPublishForStream(platformId, gbStreamList, type); + } } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/event/SipSubscribe.java b/src/main/java/com/genersoft/iot/vmp/gb28181/event/SipSubscribe.java index f341548e..a00ac630 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/event/SipSubscribe.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/event/SipSubscribe.java @@ -1,5 +1,6 @@ package com.genersoft.iot.vmp.gb28181.event; +import com.genersoft.iot.vmp.gb28181.bean.DeviceNotFoundEvent; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.scheduling.annotation.Scheduled; @@ -91,6 +92,13 @@ public class SipSubscribe { this.statusCode = -1024; this.callId = dialogTerminatedEvent.getDialog().getCallId().getCallId(); 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(); } } } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/event/offline/KeepaliveTimeoutListenerForPlatform.java b/src/main/java/com/genersoft/iot/vmp/gb28181/event/offline/KeepaliveTimeoutListenerForPlatform.java index 8bbf03ee..ea322d12 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/event/offline/KeepaliveTimeoutListenerForPlatform.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/event/offline/KeepaliveTimeoutListenerForPlatform.java @@ -1,18 +1,24 @@ 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.gb28181.event.SipSubscribe; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.DependsOn; 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.RedisMessageListenerContainer; import org.springframework.stereotype.Component; import com.genersoft.iot.vmp.common.VideoManagerConstants; import com.genersoft.iot.vmp.gb28181.event.EventPublisher; +import org.springframework.util.StringUtils; + +import java.util.Properties; /** * @description:设备心跳超时监听,借助redis过期特性,进行监听,监听到说明设备心跳超时,发送离线事件 @@ -20,7 +26,7 @@ import com.genersoft.iot.vmp.gb28181.event.EventPublisher; * @date: 2020年5月6日 上午11:35:46 */ @Component -public class KeepaliveTimeoutListenerForPlatform extends KeyExpirationEventMessageListener { +public class KeepaliveTimeoutListenerForPlatform extends RedisKeyExpirationEventMessageListener { private Logger logger = LoggerFactory.getLogger(KeepaliveTimeoutListenerForPlatform.class); @@ -30,17 +36,11 @@ public class KeepaliveTimeoutListenerForPlatform extends KeyExpirationEventMessa @Autowired private UserSetup userSetup; - @Override - public void init() { - if (!userSetup.getRedisConfig()) { - // 配置springboot默认Config为空,即不让应用去修改redis的默认配置,因为Redis服务出于安全会禁用CONFIG命令给远程用户使用 - setKeyspaceNotificationsConfigParameter(""); - } - super.init(); - } + @Autowired + private SipSubscribe sipSubscribe; - public KeepaliveTimeoutListenerForPlatform(RedisMessageListenerContainer listenerContainer) { - super(listenerContainer); + public KeepaliveTimeoutListenerForPlatform(RedisMessageListenerContainer listenerContainer, UserSetup userSetup) { + super(listenerContainer, userSetup); } @@ -58,6 +58,7 @@ public class KeepaliveTimeoutListenerForPlatform extends KeyExpirationEventMessa String PLATFORM_KEEPLIVEKEY_PREFIX = VideoManagerConstants.PLATFORM_KEEPALIVE_PREFIX + userSetup.getServerId() + "_"; String PLATFORM_REGISTER_PREFIX = VideoManagerConstants.PLATFORM_REGISTER_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)) { 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)){ String deviceId = expiredKey.substring(KEEPLIVEKEY_PREFIX.length(),expiredKey.length()); 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); } } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/event/offline/KeepliveTimeoutListener.java b/src/main/java/com/genersoft/iot/vmp/gb28181/event/offline/KeepliveTimeoutListener.java index 7b3cb589..151b68dc 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/event/offline/KeepliveTimeoutListener.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/event/offline/KeepliveTimeoutListener.java @@ -1,5 +1,6 @@ package com.genersoft.iot.vmp.gb28181.event.offline; +import com.genersoft.iot.vmp.conf.RedisKeyExpirationEventMessageListener; import com.genersoft.iot.vmp.conf.UserSetup; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -20,7 +21,7 @@ import com.genersoft.iot.vmp.gb28181.event.EventPublisher; * @date: 2020年5月6日 上午11:35:46 */ @Component -public class KeepliveTimeoutListener extends KeyExpirationEventMessageListener { +public class KeepliveTimeoutListener extends RedisKeyExpirationEventMessageListener { private Logger logger = LoggerFactory.getLogger(KeepliveTimeoutListener.class); @@ -30,6 +31,10 @@ public class KeepliveTimeoutListener extends KeyExpirationEventMessageListener { @Autowired private UserSetup userSetup; + public KeepliveTimeoutListener(RedisMessageListenerContainer listenerContainer, UserSetup userSetup) { + super(listenerContainer, userSetup); + } + @Override public void init() { if (!userSetup.getRedisConfig()) { @@ -39,9 +44,6 @@ public class KeepliveTimeoutListener extends KeyExpirationEventMessageListener { super.init(); } - public KeepliveTimeoutListener(RedisMessageListenerContainer listenerContainer) { - super(listenerContainer); - } /** * 监听失效的key,key格式为keeplive_deviceId diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/event/offline/OfflineEventListener.java b/src/main/java/com/genersoft/iot/vmp/gb28181/event/offline/OfflineEventListener.java index 9751915e..aa87728d 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/event/offline/OfflineEventListener.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/event/offline/OfflineEventListener.java @@ -1,6 +1,9 @@ package com.genersoft.iot.vmp.gb28181.event.offline; 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.LoggerFactory; 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.utils.redis.RedisUtil; +import java.util.List; + /** * @description: 离线事件监听器,监听到离线后,修改设备离在线状态。 设备离线有两个来源: * 1、设备主动注销,发送注销指令,{@link com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.RegisterRequestProcessor} @@ -34,6 +39,9 @@ public class OfflineEventListener implements ApplicationListener { @Autowired private UserSetup userSetup; + @Autowired + private EventPublisher eventPublisher; + @Override public void onApplicationEvent(OfflineEvent event) { @@ -58,6 +66,8 @@ public class OfflineEventListener implements ApplicationListener { } } + List deviceChannelList = storager.queryOnlineChannelsByDeviceId(event.getDeviceId()); + eventPublisher.catalogEventPublish(null, deviceChannelList, CatalogEvent.OFF); // 处理离线监听 storager.outline(event.getDeviceId()); diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/event/online/OnlineEventListener.java b/src/main/java/com/genersoft/iot/vmp/gb28181/event/online/OnlineEventListener.java index a62c76d5..c0de8de3 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/event/online/OnlineEventListener.java +++ b/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.UserSetup; 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 org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -15,6 +19,7 @@ import com.genersoft.iot.vmp.storager.IVideoManagerStorager; import com.genersoft.iot.vmp.utils.redis.RedisUtil; import java.text.SimpleDateFormat; +import java.util.List; /** * @description: 在线事件监听器,监听到离线后,修改设备离在线状态。 设备在线有两个来源: @@ -30,6 +35,9 @@ public class OnlineEventListener implements ApplicationListener { @Autowired private IVideoManagerStorager storager; + + @Autowired + private IDeviceService deviceService; @Autowired private RedisUtil redis; @@ -40,6 +48,9 @@ public class OnlineEventListener implements ApplicationListener { @Autowired private UserSetup userSetup; + @Autowired + private EventPublisher eventPublisher; + private SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); @Override @@ -49,6 +60,7 @@ public class OnlineEventListener implements ApplicationListener { logger.debug("设备上线事件触发,deviceId:" + event.getDevice().getDeviceId() + ",from:" + event.getFrom()); } Device device = event.getDevice(); + if (device == null) return; String key = VideoManagerConstants.KEEPLIVEKEY_PREFIX + userSetup.getServerId() + "_" + event.getDevice().getDeviceId(); switch (event.getFrom()) { @@ -76,10 +88,18 @@ public class OnlineEventListener implements ApplicationListener { } device.setOnline(1); + Device deviceInStore = storager.queryVideoDevice(device.getDeviceId()); + if (deviceInStore != null && deviceInStore.getOnline() == 0) { + List deviceChannelList = storager.queryOnlineChannelsByDeviceId(device.getDeviceId()); + eventPublisher.catalogEventPublish(null, deviceChannelList, CatalogEvent.ON); + } // 处理上线监听 storager.updateDevice(device); - // TODO 上线添加订阅 + // 上线添加订阅 + if (device.getSubscribeCycleForCatalog() > 0) { + deviceService.addCatalogSubscribe(device); + } } } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/event/subscribe/SubscribeListenerForPlatform.java b/src/main/java/com/genersoft/iot/vmp/gb28181/event/subscribe/SubscribeListenerForPlatform.java new file mode 100644 index 00000000..bac8e3dd --- /dev/null +++ b/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); + } + } +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/event/subscribe/catalog/CatalogEvent.java b/src/main/java/com/genersoft/iot/vmp/gb28181/event/subscribe/catalog/CatalogEvent.java new file mode 100644 index 00000000..c035b808 --- /dev/null +++ b/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 deviceChannels; + private List gbStreams; + private String type; + private String platformId; + + public List getDeviceChannels() { + return deviceChannels; + } + + public void setDeviceChannels(List 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 getGbStreams() { + return gbStreams; + } + + public void setGbStreams(List gbStreams) { + this.gbStreams = gbStreams; + } +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/event/subscribe/catalog/CatalogEventLister.java b/src/main/java/com/genersoft/iot/vmp/gb28181/event/subscribe/catalog/CatalogEventLister.java new file mode 100644 index 00000000..52442cc7 --- /dev/null +++ b/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 { + + 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> 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 platforms = redisCatchStorage.getAllSubscribePlatform(); + if (event.getDeviceChannels() != null) { + if (platforms.size() > 0) { + for (DeviceChannel deviceChannel : event.getDeviceChannels()) { + List 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 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 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 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 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 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 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 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; + } + } +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/task/GPSSubscribeTask.java b/src/main/java/com/genersoft/iot/vmp/gb28181/task/GPSSubscribeTask.java new file mode 100644 index 00000000..0d56bd58 --- /dev/null +++ b/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 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); + } + } + + } + } + } + } + + + } +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPProcessorObserver.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPProcessorObserver.java index 116236f5..71025c00 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPProcessorObserver.java +++ b/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.header.CSeqHeader; import javax.sip.header.CallIdHeader; +import javax.sip.header.Header; import javax.sip.message.Response; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -94,7 +95,6 @@ public class SIPProcessorObserver implements ISIPProcessorObserver { logger.debug(responseEvent.getResponse().toString()); int status = response.getStatusCode(); if (((status >= 200) && (status < 300)) || status == 401) { // Success! -// ISIPResponseProcessor processor = processorFactory.createResponseProcessor(evt); CSeqHeader cseqHeader = (CSeqHeader) responseEvent.getResponse().getHeader(CSeqHeader.NAME); String method = cseqHeader.getMethod(); ISIPResponseProcessor sipRequestProcessor = responseProcessorMap.get(method); @@ -108,6 +108,7 @@ public class SIPProcessorObserver implements ISIPProcessorObserver { if (subscribe != null) { SipSubscribe.EventResult eventResult = new SipSubscribe.EventResult(responseEvent); subscribe.response(eventResult); + sipSubscribe.removeOkSubscribe(callIdHeader.getCallId()); } } } @@ -122,6 +123,7 @@ public class SIPProcessorObserver implements ISIPProcessorObserver { if (subscribe != null) { SipSubscribe.EventResult eventResult = new SipSubscribe.EventResult(responseEvent); subscribe.response(eventResult); + sipSubscribe.removeErrorSubscribe(callIdHeader.getCallId()); } } } @@ -139,6 +141,7 @@ public class SIPProcessorObserver implements ISIPProcessorObserver { */ @Override public void processTimeout(TimeoutEvent timeoutEvent) { + System.out.println("processTimeout"); if(timeoutProcessor != null) { timeoutProcessor.process(timeoutEvent); } @@ -146,14 +149,31 @@ public class SIPProcessorObserver implements ISIPProcessorObserver { @Override public void processIOException(IOExceptionEvent exceptionEvent) { + System.out.println("processIOException"); } @Override 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 terminatedEventEventResult = new SipSubscribe.EventResult<>(transactionTerminatedEvent); + +// sipSubscribe.getErrorSubscribe(header.getCallId()).response(terminatedEventEventResult); } @Override public void processDialogTerminated(DialogTerminatedEvent dialogTerminatedEvent) { + System.out.println("processDialogTerminated"); CallIdHeader callId = dialogTerminatedEvent.getDialog().getCallId(); } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/callback/DeferredResultHolder.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/callback/DeferredResultHolder.java index 48c4939a..ac77f7b9 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/callback/DeferredResultHolder.java +++ b/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 UPLOAD_FILE_CHANNEL = "UPLOAD_FILE_CHANNEL"; + public static final String CALLBACK_CMD_MOBILEPOSITION = "CALLBACK_MOBILEPOSITION"; public static final String CALLBACK_CMD_PRESETQUERY = "CALLBACK_PRESETQUERY"; diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java index 6e96dac3..8be07ca1 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java @@ -328,4 +328,13 @@ public interface ISIPCommander { * @return true = 命令发送成功 */ 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); } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommanderForPlatform.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommanderForPlatform.java index fe302938..7325889f 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommanderForPlatform.java +++ b/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.ParentPlatform; +import com.genersoft.iot.vmp.gb28181.bean.SubscribeInfo; import com.genersoft.iot.vmp.gb28181.event.SipSubscribe; +import com.genersoft.iot.vmp.service.bean.GPSMsgInfo; import javax.sip.header.WWWAuthenticateHeader; +import java.util.List; public interface ISIPCommanderForPlatform { @@ -61,4 +64,27 @@ public interface ISIPCommanderForPlatform { */ 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 deviceChannels, SubscribeInfo subscribeInfo); + + /** + * 回复catalog事件-删除 + * @param parentPlatform + * @param deviceChannels + */ + boolean sendNotifyForCatalogOther(String type, ParentPlatform parentPlatform, List deviceChannels, SubscribeInfo subscribeInfo); + } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderPlarformProvider.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderPlarformProvider.java index cc41af7c..27125e1e 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderPlarformProvider.java +++ b/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.gb28181.bean.ParentPlatform; +import com.genersoft.iot.vmp.storager.IRedisCatchStorage; import gov.nist.javax.sip.message.MessageFactoryImpl; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -32,6 +33,9 @@ public class SIPRequestHeaderPlarformProvider { @Autowired 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 { Request request = null; @@ -57,7 +61,7 @@ public class SIPRequestHeaderPlarformProvider { // Forwards MaxForwardsHeader maxForwards = sipFactory.createHeaderFactory().createMaxForwardsHeader(70); // 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, toHeader, viaHeaders, maxForwards); @@ -122,7 +126,7 @@ public class SIPRequestHeaderPlarformProvider { 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 nonce = www.getNonce(); @@ -208,7 +212,7 @@ public class SIPRequestHeaderPlarformProvider { // Forwards MaxForwardsHeader maxForwards = sipFactory.createHeaderFactory().createMaxForwardsHeader(70); // 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(); // 设置编码, 防止中文乱码 messageFactory.setDefaultContentEncodingCharset("gb2312"); @@ -223,4 +227,43 @@ public class SIPRequestHeaderPlarformProvider { request.setContent(content, contentTypeHeader); 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 viaHeaders = new ArrayList(); + 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 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; + } } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java index 59e21925..cb4cbd74 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java +++ b/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() : 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); 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("\r\n"); + dragXml.append("\r\n"); + dragXml.append("DeviceControl\r\n"); + dragXml.append("" + (int) ((Math.random() * 9 + 1) * 100000) + "\r\n"); + if (StringUtils.isEmpty(channelId)) { + dragXml.append("" + device.getDeviceId() + "\r\n"); + } else { + dragXml.append("" + channelId + "\r\n"); + } + dragXml.append(cmdString); + dragXml.append("\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 { return transmitRequest(device, request, null, null); diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java index cf8b0a56..e15853db 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java +++ b/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.ParentPlatform; 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.transmit.cmd.ISIPCommanderForPlatform; 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 org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -21,6 +23,7 @@ import javax.sip.header.CallIdHeader; import javax.sip.header.WWWAuthenticateHeader; import javax.sip.message.Request; import java.text.ParseException; +import java.util.List; import java.util.UUID; @Component @@ -92,9 +95,10 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { 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 写入缓存, 等注册成功可以更新状态 - redisCatchStorage.updatePlatformRegisterInfo(callIdHeader.getCallId(), parentPlatform.getServerGBId()); + String callIdFromHeader = callIdHeader.getCallId(); + redisCatchStorage.updatePlatformRegisterInfo(callIdFromHeader, parentPlatform.getServerGBId()); sipSubscribe.addErrorSubscribe(callIdHeader.getCallId(), (event)->{ if (event != null) { @@ -102,6 +106,7 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { parentPlatform.getServerGBId(), event.msg); } + redisCatchStorage.delPlatformRegisterInfo(callIdFromHeader); if (errorEvent != null ) { errorEvent.response(event); } @@ -217,8 +222,8 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { catalogXml.append("" + channel.getOwner() + "\r\n"); catalogXml.append("" + channel.getCivilCode() + "\r\n"); catalogXml.append("
" + channel.getAddress() + "
\r\n"); - catalogXml.append("" + channel.getParental() + "\r\n");// TODO 当前不能添加分组, 所以暂时没有父节点 - catalogXml.append("" + channel.getParentId() + "\r\n"); // TODO 当前不能添加分组, 所以暂时没有父节点 + catalogXml.append("" + channel.getParental() + "\r\n"); + catalogXml.append("" + channel.getParentId() + "\r\n"); catalogXml.append("" + channel.getSecrecy() + "\r\n"); catalogXml.append("" + channel.getRegisterWay() + "\r\n"); catalogXml.append("" + (channel.getStatus() == 0?"OFF":"ON") + "\r\n"); @@ -325,4 +330,144 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { } 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("\r\n"); + deviceStatusXml.append("\r\n"); + deviceStatusXml.append("MobilePosition\r\n"); + deviceStatusXml.append("" + (int)((Math.random()*9+1)*100000) + "\r\n"); + deviceStatusXml.append("" + gpsMsgInfo.getId() + "\r\n"); + deviceStatusXml.append("\r\n"); + deviceStatusXml.append("" + gpsMsgInfo.getLng() + "\r\n"); + deviceStatusXml.append("" + gpsMsgInfo.getLat() + "\r\n"); + deviceStatusXml.append("" + gpsMsgInfo.getSpeed() + "\r\n"); + deviceStatusXml.append("" + gpsMsgInfo.getDirection() + "\r\n"); + deviceStatusXml.append("" + gpsMsgInfo.getAltitude() + "\r\n"); + deviceStatusXml.append("\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 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("\r\n"); + catalogXml.append("\r\n"); + catalogXml.append("Catalog\r\n"); + catalogXml.append("" + (int) ((Math.random() * 9 + 1) * 100000) + "\r\n"); + catalogXml.append("" + deviceChannels.size() + "\r\n"); + catalogXml.append("\r\n"); + catalogXml.append("\r\n"); + catalogXml.append("" + channel.getChannelId() + "\r\n"); + catalogXml.append("" + type + "\r\n"); + catalogXml.append("" + channel.getName() + "\r\n"); + catalogXml.append("" + channel.getManufacture() + "\r\n"); + catalogXml.append("" + channel.getModel() + "\r\n"); + catalogXml.append("" + channel.getOwner() + "\r\n"); + catalogXml.append("" + channel.getCivilCode() + "\r\n"); + catalogXml.append("
" + channel.getAddress() + "
\r\n"); + catalogXml.append("" + channel.getParental() + "\r\n"); + catalogXml.append("" + channel.getParentId() + "\r\n"); + catalogXml.append("" + channel.getSecrecy() + "\r\n"); + catalogXml.append("" + channel.getRegisterWay() + "\r\n"); + catalogXml.append("" + (channel.getStatus() == 0 ? "OFF" : "ON") + "\r\n"); + catalogXml.append("" + channel.getLongitude() + "\r\n"); + catalogXml.append("" + channel.getLatitude() + "\r\n"); + catalogXml.append("" + channel.getIpAddress() + "\r\n"); + catalogXml.append("" + channel.getPort() + "\r\n"); + catalogXml.append("\r\n"); + catalogXml.append("" + channel.getPTZType() + "\r\n"); + catalogXml.append("\r\n"); + catalogXml.append("
\r\n"); + catalogXml.append("
\r\n"); + catalogXml.append("
\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 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("\r\n"); + catalogXml.append("\r\n"); + catalogXml.append("Catalog\r\n"); + catalogXml.append("" + (int) ((Math.random() * 9 + 1) * 100000) + "\r\n"); + catalogXml.append("" + deviceChannels.size() + "\r\n"); + catalogXml.append("\r\n"); + catalogXml.append("\r\n"); + catalogXml.append("" + channel.getChannelId() + "\r\n"); + catalogXml.append("" + type + "\r\n"); + catalogXml.append("\r\n"); + catalogXml.append("\r\n"); + catalogXml.append("\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; + } + } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/SIPRequestProcessorParent.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/SIPRequestProcessorParent.java index e7f8f727..d4de725d 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/SIPRequestProcessorParent.java +++ b/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.SipURI; import javax.sip.header.ContentTypeHeader; +import javax.sip.header.ExpiresHeader; import javax.sip.header.HeaderFactory; import javax.sip.header.ViaHeader; import javax.sip.message.MessageFactory; @@ -153,7 +154,7 @@ public abstract class SIPRequestProcessorParent { * @throws InvalidArgumentException * @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()); SipFactory sipFactory = SipFactory.getInstance(); ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader("APPLICATION", "SDP"); @@ -168,6 +169,31 @@ public abstract class SIPRequestProcessorParent { 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 { return getRootElement(evt, "gb2312"); } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java index aee414f5..ae2819ca 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java +++ b/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) { // 查询平台下是否有该通道 DeviceChannel channel = storager.queryChannelInParentPlatform(requesterId, channelId); - List gbStreams = storager.queryStreamInParentPlatform(requesterId, channelId); - GbStream gbStream = gbStreams.size() > 0? gbStreams.get(0):null; + GbStream gbStream = storager.queryStreamInParentPlatform(requesterId, channelId); + PlatformCatalog catalog = storager.getCatalog(channelId); MediaServerItem mediaServerItem = null; // 不是通道可能是直播流 if (channel != null && gbStream == null ) { @@ -132,7 +132,10 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements return; } 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"); responseAck(evt, Response.NOT_FOUND); // 通道不存在,发404,资源不存在 return; @@ -249,7 +252,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements content.append("f=\r\n"); try { - responseAck(evt, content.toString()); + responseSdpAck(evt, content.toString()); } catch (SipException e) { e.printStackTrace(); } catch (InvalidArgumentException e) { @@ -306,7 +309,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements content.append("f=\r\n"); try { - responseAck(evt, content.toString()); + responseSdpAck(evt, content.toString()); } catch (SipException e) { e.printStackTrace(); } catch (InvalidArgumentException e) { diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/NotifyRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/NotifyRequestProcessor.java index 2e58d9d3..c339598e 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/NotifyRequestProcessor.java +++ b/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.event.DeviceOffLineDetector; 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.callback.DeferredResultHolder; import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; @@ -50,6 +51,9 @@ public class NotifyRequestProcessor extends SIPRequestProcessorParent implements @Autowired private IVideoManagerStorager storager; + @Autowired + private EventPublisher eventPublisher; + @Autowired private SipConfig sipConfig; @@ -62,9 +66,7 @@ public class NotifyRequestProcessor extends SIPRequestProcessorParent implements @Autowired 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"; @Autowired @@ -82,13 +84,13 @@ public class NotifyRequestProcessor extends SIPRequestProcessorParent implements Element rootElement = getRootElement(evt); String cmd = XmlUtil.getText(rootElement, "CmdType"); - if (NOTIFY_CATALOG.equals(cmd)) { + if (CmdType.CATALOG.equals(cmd)) { logger.info("接收到Catalog通知"); processNotifyCatalogList(evt); - } else if (NOTIFY_ALARM.equals(cmd)) { + } else if (CmdType.ALARM.equals(cmd)) { logger.info("接收到Alarm通知"); processNotifyAlarm(evt); - } else if (NOTIFY_MOBILE_POSITION.equals(cmd)) { + } else if (CmdType.MOBILE_POSITION.equals(cmd)) { logger.info("接收到MobilePosition通知"); processNotifyMobilePosition(evt); } else { @@ -257,41 +259,43 @@ public class NotifyRequestProcessor extends SIPRequestProcessorParent implements continue; } 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()) { - case "ON" : // 上线 + case CatalogEvent.ON: // 上线 logger.info("收到来自设备【{}】的通道【{}】上线通知", device.getDeviceId(), channel.getChannelId()); storager.deviceChannelOnline(deviceId, channel.getChannelId()); // 回复200 OK responseAck(evt, Response.OK); break; - case "OFF" : // 离线 + case CatalogEvent.OFF : // 离线 logger.info("收到来自设备【{}】的通道【{}】离线通知", device.getDeviceId(), channel.getChannelId()); storager.deviceChannelOffline(deviceId, channel.getChannelId()); // 回复200 OK responseAck(evt, Response.OK); break; - case "VLOST" : // 视频丢失 + case CatalogEvent.VLOST: // 视频丢失 logger.info("收到来自设备【{}】的通道【{}】视频丢失通知", device.getDeviceId(), channel.getChannelId()); storager.deviceChannelOffline(deviceId, channel.getChannelId()); // 回复200 OK responseAck(evt, Response.OK); break; - case "DEFECT" : // 故障 + case CatalogEvent.DEFECT: // 故障 // 回复200 OK responseAck(evt, Response.OK); break; - case "ADD" : // 增加 + case CatalogEvent.ADD: // 增加 logger.info("收到来自设备【{}】的增加通道【{}】通知", device.getDeviceId(), channel.getChannelId()); storager.updateChannel(deviceId, channel); responseAck(evt, Response.OK); break; - case "DEL" : // 删除 + case CatalogEvent.DEL: // 删除 logger.info("收到来自设备【{}】的删除通道【{}】通知", device.getDeviceId(), channel.getChannelId()); storager.delChannel(deviceId, channel.getChannelId()); responseAck(evt, Response.OK); break; - case "UPDATE" : // 更新 + case CatalogEvent.UPDATE: // 更新 logger.info("收到来自设备【{}】的更新通道【{}】通知", device.getDeviceId(), channel.getChannelId()); storager.updateChannel(deviceId, channel); responseAck(evt, Response.OK); @@ -300,6 +304,8 @@ public class NotifyRequestProcessor extends SIPRequestProcessorParent implements 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) { } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/RegisterRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/RegisterRequestProcessor.java index 053bf9a9..d9bfb560 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/RegisterRequestProcessor.java +++ b/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(); SipUri uri = (SipUri) address.getURI(); String deviceId = uri.getUser(); - Device device = redisCatchStorage.getDevice(deviceId); - AuthorizationHeader authorhead = (AuthorizationHeader) request.getHeader(AuthorizationHeader.NAME); + Device deviceInRedis = redisCatchStorage.getDevice(deviceId); + Device device = storager.queryVideoDevice(deviceId); + if (deviceInRedis != null && device == null) { + // redis 存在脏数据 + redisCatchStorage.clearCatchByDeviceId(deviceId); + } + AuthorizationHeader authorhead = (AuthorizationHeader) request.getHeader(AuthorizationHeader.NAME); // 校验密码是否正确 if (authorhead != null) { passwordCorrect = new DigestServerAuthenticationHelper().doAuthenticatePlainTextPassword(request, diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/SubscribeRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/SubscribeRequestProcessor.java index be4b2ce9..8d0bdd2f 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/SubscribeRequestProcessor.java +++ b/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; +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.cmd.ISIPCommanderForPlatform; 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.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.LoggerFactory; import org.springframework.beans.factory.InitializingBean; @@ -13,7 +26,10 @@ import javax.sip.InvalidArgumentException; import javax.sip.RequestEvent; import javax.sip.ServerTransaction; import javax.sip.SipException; +import javax.sip.header.CallIdHeader; import javax.sip.header.ExpiresHeader; +import javax.sip.header.Header; +import javax.sip.header.ToHeader; import javax.sip.message.Request; import javax.sip.message.Response; import java.text.ParseException; @@ -30,6 +46,21 @@ public class SubscribeRequestProcessor extends SIPRequestProcessorParent impleme @Autowired private SIPProcessorObserver sipProcessorObserver; + @Autowired + private IRedisCatchStorage redisCatchStorage; + + @Autowired + private ISIPCommanderForPlatform sipCommanderForPlatform; + + @Autowired + private IVideoManagerStorager storager; + + @Autowired + private DynamicTask dynamicTask; + + @Autowired + private UserSetup userSetup; + @Override public void afterPropertiesSet() throws Exception { // 添加消息处理的订阅 @@ -46,30 +77,137 @@ public class SubscribeRequestProcessor extends SIPRequestProcessorParent impleme Request request = evt.getRequest(); try { - 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(); + Element rootElement = getRootElement(evt); + String cmd = XmlUtil.getText(rootElement, "CmdType"); + if (CmdType.MOBILE_POSITION.equals(cmd)) { + processNotifyMobilePosition(evt, rootElement); +// } else if (CmdType.ALARM.equals(cmd)) { +// logger.info("接收到Alarm订阅"); +// processNotifyAlarm(evt, rootElement); + } else if (CmdType.CATALOG.equals(cmd)) { + processNotifyCatalogList(evt, rootElement); } 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("\r\n") + .append("\r\n") + .append("MobilePosition\r\n") + .append("" + sn + "\r\n") + .append("" + deviceID + "\r\n") + .append("OK\r\n") + .append("\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) { 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("\r\n") + .append("\r\n") + .append("Catalog\r\n") + .append("" + sn + "\r\n") + .append("" + deviceID + "\r\n") + .append("OK\r\n") + .append("\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) { e.printStackTrace(); } catch (InvalidArgumentException e) { e.printStackTrace(); + } catch (ParseException e) { + e.printStackTrace(); } - } } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/MessageRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/MessageRequestProcessor.java index 0aab8716..bd053446 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/MessageRequestProcessor.java +++ b/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; 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.event.SipSubscribe; 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.SIPRequestProcessorParent; @@ -19,6 +21,7 @@ import org.springframework.stereotype.Component; import javax.sip.InvalidArgumentException; import javax.sip.RequestEvent; import javax.sip.SipException; +import javax.sip.header.CallIdHeader; import javax.sip.message.Response; import java.text.ParseException; import java.util.Map; @@ -39,6 +42,9 @@ public class MessageRequestProcessor extends SIPRequestProcessorParent implement @Autowired private IVideoManagerStorager storage; + @Autowired + private SipSubscribe sipSubscribe; + @Autowired private IRedisCatchStorage redisCatchStorage; @@ -56,6 +62,7 @@ public class MessageRequestProcessor extends SIPRequestProcessorParent implement public void process(RequestEvent evt) { logger.debug("接收到消息:" + evt.getRequest()); String deviceId = SipUtils.getUserIdFromFromHeader(evt.getRequest()); + CallIdHeader callIdHeader = (CallIdHeader)evt.getRequest().getHeader(CallIdHeader.NAME); // 查询设备是否存在 Device device = redisCatchStorage.getDevice(deviceId); // 查询上级平台是否存在 @@ -63,7 +70,12 @@ public class MessageRequestProcessor extends SIPRequestProcessorParent implement try { if (device == null && parentPlatform == null) { // 不存在则回复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 { Element rootElement = getRootElement(evt); String name = rootElement.getName(); diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/CatalogNotifyMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/CatalogNotifyMessageHandler.java index c6c1ab9c..0b1a5722 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/CatalogNotifyMessageHandler.java +++ b/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; import com.genersoft.iot.vmp.conf.SipConfig; -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.bean.ParentPlatform; +import com.genersoft.iot.vmp.gb28181.bean.*; import com.genersoft.iot.vmp.gb28181.event.EventPublisher; import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform; @@ -71,11 +68,41 @@ public class CatalogNotifyMessageHandler extends SIPRequestProcessorParent imple // 查询关联的直播通道 List gbStreams = storager.queryGbStreamListInPlatform(parentPlatform.getServerGBId()); int size = channelReduces.size() + gbStreams.size(); + // 回复目录信息 + List 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) { for (ChannelReduce channelReduce : channelReduces) { DeviceChannel deviceChannel = storager.queryChannel(channelReduce.getDeviceId(), channelReduce.getChannelId()); + // TODO 目前暂时认为这里只用通道没有目录 + deviceChannel.setParental(0); + deviceChannel.setParentId(channelReduce.getCatalogId()); + 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.setManufacture("wvp-pro"); deviceChannel.setStatus(gbStream.isStatus()?1:0); - // deviceChannel.setParentId(parentPlatform.getDeviceGBId()); + deviceChannel.setParentId(gbStream.getCatalogId()); deviceChannel.setRegisterWay(1); deviceChannel.setCivilCode(config.getDomain()); deviceChannel.setModel("live"); deviceChannel.setOwner("wvp-pro"); deviceChannel.setParental(0); deviceChannel.setSecrecy("0"); - deviceChannel.setSecrecy("0"); - cmderFroPlatform.catalogQuery(deviceChannel, parentPlatform, sn, fromHeader.getTag(), size); + // 防止发送过快 + Thread.sleep(10); } } if (size == 0) { @@ -111,6 +138,8 @@ public class CatalogNotifyMessageHandler extends SIPRequestProcessorParent imple e.printStackTrace(); } catch (ParseException e) { e.printStackTrace(); + } catch (InterruptedException e) { + e.printStackTrace(); } } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/CatalogQueryMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/CatalogQueryMessageHandler.java index 98ed2dc4..6ca608c3 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/CatalogQueryMessageHandler.java +++ b/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; import com.genersoft.iot.vmp.conf.SipConfig; -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.bean.ParentPlatform; +import com.genersoft.iot.vmp.gb28181.bean.*; import com.genersoft.iot.vmp.gb28181.event.EventPublisher; import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform; @@ -73,12 +70,41 @@ public class CatalogQueryMessageHandler extends SIPRequestProcessorParent implem List channelReduces = storager.queryChannelListInParentPlatform(parentPlatform.getServerGBId()); // 查询关联的直播通道 List gbStreams = storager.queryGbStreamListInPlatform(parentPlatform.getServerGBId()); - int size = channelReduces.size() + gbStreams.size(); + // 回复目录信息 + List 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) { for (ChannelReduce channelReduce : channelReduces) { DeviceChannel deviceChannel = storager.queryChannel(channelReduce.getDeviceId(), channelReduce.getChannelId()); + // TODO 目前暂时认为这里只用通道没有目录 + deviceChannel.setParental(0); + deviceChannel.setParentId(channelReduce.getCatalogId()); 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.setManufacture("wvp-pro"); deviceChannel.setStatus(gbStream.isStatus()?1:0); - // deviceChannel.setParentId(parentPlatform.getDeviceGBId()); + deviceChannel.setParentId(gbStream.getCatalogId()); deviceChannel.setRegisterWay(1); deviceChannel.setCivilCode(config.getDomain()); deviceChannel.setModel("live"); deviceChannel.setOwner("wvp-pro"); deviceChannel.setParental(0); deviceChannel.setSecrecy("0"); - deviceChannel.setSecrecy("0"); cmderFroPlatform.catalogQuery(deviceChannel, parentPlatform, sn, fromHeader.getTag(), size); } @@ -114,6 +139,8 @@ public class CatalogQueryMessageHandler extends SIPRequestProcessorParent implem e.printStackTrace(); } catch (ParseException e) { e.printStackTrace(); + } catch (InterruptedException e) { + e.printStackTrace(); } } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/CatalogResponseMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/CatalogResponseMessageHandler.java index 9e150689..dfd0eb25 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/CatalogResponseMessageHandler.java +++ b/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.response.ResponseMessageHandler; 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.vmanager.bean.WVPResult; import org.dom4j.DocumentException; @@ -94,85 +95,9 @@ public class CatalogResponseMessageHandler extends SIPRequestProcessorParent imp if (channelDeviceElement == null) { continue; } - String channelDeviceId = channelDeviceElement.getText(); - Element channdelNameElement = itemDevice.element("Name"); - String channelName = channdelNameElement != null ? channdelNameElement.getTextTrim().toString() : ""; - Element statusElement = itemDevice.element("Status"); - String status = statusElement != null ? statusElement.getText().toString() : "ON"; - DeviceChannel deviceChannel = new DeviceChannel(); - deviceChannel.setName(channelName); + DeviceChannel deviceChannel = XmlUtil.channelContentHander(itemDevice); deviceChannel.setDeviceId(device.getDeviceId()); - String now = this.format.format(new Date(System.currentTimeMillis())); - 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 + logger.debug("收到来自设备【{}】的通道: {}【{}】", device.getDeviceId(), deviceChannel.getName(), deviceChannel.getChannelId()); channelList.add(deviceChannel); } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/DeviceControlResponseMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/DeviceControlResponseMessageHandler.java index 69f664bb..0c9b8353 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/DeviceControlResponseMessageHandler.java +++ b/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.stereotype.Component; +import javax.sip.InvalidArgumentException; 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; @@ -40,17 +45,26 @@ public class DeviceControlResponseMessageHandler extends SIPRequestProcessorPare @Override public void handForDevice(RequestEvent evt, Device device, Element element) { // 此处是对本平台发出DeviceControl指令的应答 - JSONObject json = new JSONObject(); - String channelId = getText(element, "DeviceID"); - XmlUtil.node2Json(element, json); - if (logger.isDebugEnabled()) { - logger.debug(json.toJSONString()); + try { + responseAck(evt, Response.OK); + JSONObject json = new JSONObject(); + String channelId = getText(element, "DeviceID"); + 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 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/utils/XmlUtil.java b/src/main/java/com/genersoft/iot/vmp/gb28181/utils/XmlUtil.java index 079a78bb..94e0cd80 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/utils/XmlUtil.java +++ b/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.JSONObject; +import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; import org.dom4j.Attribute; import org.dom4j.Document; import org.dom4j.DocumentException; @@ -178,4 +179,89 @@ public class XmlUtil { Document xml = reader.read(new ByteArrayInputStream(content)); 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; + } } diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java index b6af955a..5919619f 100644 --- a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java +++ b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java @@ -1,14 +1,17 @@ package com.genersoft.iot.vmp.media.zlm; +import java.util.ArrayList; import java.util.List; import java.util.UUID; import com.alibaba.fastjson.JSON; -import com.alibaba.fastjson.JSONArray; import com.genersoft.iot.vmp.common.StreamInfo; import com.genersoft.iot.vmp.conf.MediaConfig; import com.genersoft.iot.vmp.conf.UserSetup; 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.service.*; import com.genersoft.iot.vmp.service.bean.SSRCInfo; @@ -66,7 +69,7 @@ public class ZLMHttpHookListener { private IMediaService mediaService; @Autowired - private ZLMRESTfulUtils zlmresTfulUtils; + private EventPublisher eventPublisher; @Autowired private ZLMMediaListManager zlmMediaListManager; @@ -302,7 +305,7 @@ public class ZLMHttpHookListener { @ResponseBody @PostMapping(value = "/on_stream_changed", produces = "application/json;charset=UTF-8") public ResponseEntity onStreamChanged(@RequestBody MediaItem item){ - + if (logger.isDebugEnabled()) { logger.debug("[ ZLM HOOK ]on_stream_changed API调用,参数:" + JSONObject.toJSONString(item)); } @@ -322,10 +325,8 @@ public class ZLMHttpHookListener { String schema = item.getSchema(); List tracks = item.getTracks(); boolean regist = item.isRegist(); - if (tracks != null) { - logger.info("[stream: " + streamId + "] on_stream_changed->>" + schema); - } if ("rtmp".equals(schema)){ + logger.info("on_stream_changed:注册->{}, app->{}, stream->{}", regist, app, streamId); if (regist) { mediaServerService.addCount(mediaServerId); }else { @@ -344,37 +345,52 @@ public class ZLMHttpHookListener { if (!"rtp".equals(app)){ String type = OriginType.values()[item.getOriginType()].getType(); MediaServerItem mediaServerItem = mediaServerService.getOne(mediaServerId); + if (mediaServerItem != null){ if (regist) { - StreamInfo streamInfo = mediaService.getStreamInfoByAppAndStream(mediaServerItem, app, streamId, tracks); - redisCatchStorage.addStream(mediaServerItem, type, app, streamId, streamInfo); + StreamPushItem streamPushItem = null; + redisCatchStorage.addStream(mediaServerItem, type, app, streamId, item); if (item.getOriginType() == OriginType.RTSP_PUSH.ordinal() || item.getOriginType() == OriginType.RTMP_PUSH.ordinal() || item.getOriginType() == OriginType.RTC_PUSH.ordinal() ) { - zlmMediaListManager.addPush(item); + streamPushItem = zlmMediaListManager.addPush(item); } - }else { - // 兼容流注销时类型错误的问题,等zlm更新后删除 - StreamPushItem streamPushItem = streamPushService.getPush(app, streamId); - if (streamPushItem != null) { - type = "PUSH"; + List gbStreams = new ArrayList<>(); + if (streamPushItem == null || streamPushItem.getGbId() == null) { + GbStream gbStream = storager.getGbStream(app, streamId); + gbStreams.add(gbStream); }else { - StreamProxyItem streamProxyByAppAndStream = streamProxyService.getStreamProxyByAppAndStream(app, streamId); - if (streamProxyByAppAndStream != null) { - type = "PULL"; + if (streamPushItem.getGbId() != null) { + gbStreams.add(streamPushItem); } } + 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); - redisCatchStorage.removeStream(mediaServerItem.getId(), type, app, streamId); } - // 发送流变化redis消息 - JSONObject jsonObject = new JSONObject(); - jsonObject.put("serverId", userSetup.getServerId()); - jsonObject.put("app", app); - jsonObject.put("stream", streamId); - jsonObject.put("register", regist); - jsonObject.put("mediaServerId", mediaServerId); - redisCatchStorage.sendStreamChangeMsg(type, jsonObject); + if (type != null) { + // 发送流变化redis消息 + JSONObject jsonObject = new JSONObject(); + jsonObject.put("serverId", userSetup.getServerId()); + jsonObject.put("app", app); + jsonObject.put("stream", streamId); + jsonObject.put("register", regist); + jsonObject.put("mediaServerId", mediaServerId); + redisCatchStorage.sendStreamChangeMsg(type, jsonObject); + } } } } diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMMediaListManager.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMMediaListManager.java index 5b7ba1cc..a6c30cf9 100644 --- a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMMediaListManager.java +++ b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMMediaListManager.java @@ -105,7 +105,7 @@ public class ZLMMediaListManager { updateMedia(mediaServerItem, app, streamId); } - public void addPush(MediaItem mediaItem) { + public StreamPushItem addPush(MediaItem mediaItem) { // 查找此直播流是否存在redis预设gbId StreamPushItem transform = streamPushService.transform(mediaItem); // 从streamId取出查询关键值 @@ -130,7 +130,6 @@ public class ZLMMediaListManager { for (GbStream gbStream : gbStreams) { // 出现使用相同国标Id的视频流时,使用新流替换旧流, gbStreamMapper.del(gbStream.getApp(), gbStream.getStream()); - platformGbStreamMapper.delByAppAndStream(gbStream.getApp(), gbStream.getStream()); if (!gbStream.isStatus()) { streamPushMapper.del(gbStream.getApp(), gbStream.getStream()); } @@ -142,6 +141,7 @@ public class ZLMMediaListManager { gbStreamMapper.add(transform); } } + return transform; } diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/event/ZLMKeepliveTimeoutListener.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/event/ZLMKeepliveTimeoutListener.java index 3fc6a3ca..16d8da73 100644 --- a/src/main/java/com/genersoft/iot/vmp/media/zlm/event/ZLMKeepliveTimeoutListener.java +++ b/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.genersoft.iot.vmp.common.VideoManagerConstants; +import com.genersoft.iot.vmp.conf.RedisKeyExpirationEventMessageListener; import com.genersoft.iot.vmp.conf.UserSetup; import com.genersoft.iot.vmp.gb28181.event.EventPublisher; import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils; @@ -21,7 +22,7 @@ import org.springframework.stereotype.Component; * @date: 2020年5月6日 上午11:35:46 */ @Component -public class ZLMKeepliveTimeoutListener extends KeyExpirationEventMessageListener { +public class ZLMKeepliveTimeoutListener extends RedisKeyExpirationEventMessageListener { private Logger logger = LoggerFactory.getLogger(ZLMKeepliveTimeoutListener.class); @@ -37,20 +38,12 @@ public class ZLMKeepliveTimeoutListener extends KeyExpirationEventMessageListene @Autowired private IMediaServerService mediaServerService; - @Override - public void init() { - if (!userSetup.getRedisConfig()) { - // 配置springboot默认Config为空,即不让应用去修改redis的默认配置,因为Redis服务出于安全会禁用CONFIG命令给远程用户使用 - setKeyspaceNotificationsConfigParameter(""); - } - super.init(); + public ZLMKeepliveTimeoutListener(RedisMessageListenerContainer listenerContainer, UserSetup userSetup) { + super(listenerContainer, userSetup); } - public ZLMKeepliveTimeoutListener(RedisMessageListenerContainer listenerContainer) { - super(listenerContainer); - } - /** + /** * 监听失效的key,key格式为keeplive_deviceId * @param message * @param pattern diff --git a/src/main/java/com/genersoft/iot/vmp/service/IGbStreamService.java b/src/main/java/com/genersoft/iot/vmp/service/IGbStreamService.java index 49ba7b7f..a48bfb50 100644 --- a/src/main/java/com/genersoft/iot/vmp/service/IGbStreamService.java +++ b/src/main/java/com/genersoft/iot/vmp/service/IGbStreamService.java @@ -1,5 +1,6 @@ package com.genersoft.iot.vmp.service; +import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; import com.genersoft.iot.vmp.gb28181.bean.GbStream; import com.github.pagehelper.PageInfo; @@ -16,7 +17,7 @@ public interface IGbStreamService { * @param count * @return */ - PageInfo getAll(Integer page, Integer count); + PageInfo getAll(Integer page, Integer count, String platFormId); /** @@ -30,11 +31,16 @@ public interface IGbStreamService { * 保存国标关联 * @param gbStreams */ - boolean addPlatformInfo(List gbStreams, String platformId); + boolean addPlatformInfo(List gbStreams, String platformId, String catalogId); /** * 移除国标关联 * @param gbStreams + * @param platformId */ - boolean delPlatformInfo(List gbStreams); + boolean delPlatformInfo(String platformId, List gbStreams); + + DeviceChannel getDeviceChannelListByStream(GbStream gbStream, String catalogId, String deviceGBId); + + void sendCatalogMsg(GbStream gbStream, String type); } diff --git a/src/main/java/com/genersoft/iot/vmp/service/IStreamPushService.java b/src/main/java/com/genersoft/iot/vmp/service/IStreamPushService.java index 06c8b732..8a09de7b 100644 --- a/src/main/java/com/genersoft/iot/vmp/service/IStreamPushService.java +++ b/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.MediaServerItem; import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem; +import com.genersoft.iot.vmp.vmanager.bean.StreamPushExcelDto; import com.github.pagehelper.PageInfo; import java.util.List; @@ -65,4 +66,6 @@ public interface IStreamPushService { void clean(); boolean saveToRandomGB(); + + void batchAdd(List streamPushExcelDtoList); } diff --git a/src/main/java/com/genersoft/iot/vmp/service/StreamGPSSubscribeTask.java b/src/main/java/com/genersoft/iot/vmp/service/StreamGPSSubscribeTask.java new file mode 100644 index 00000000..fd5bb060 --- /dev/null +++ b/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 = redisCatchStorage.getAllGpsMsgInfo(); + if (gpsMsgInfo.size() > 0) { + storager.updateStreamGPS(gpsMsgInfo); + for (GPSMsgInfo msgInfo : gpsMsgInfo) { + msgInfo.setStored(true); + redisCatchStorage.updateGpsMsgInfo(msgInfo); + } + } + + } +} diff --git a/src/main/java/com/genersoft/iot/vmp/service/bean/CatalogSubscribeTask.java b/src/main/java/com/genersoft/iot/vmp/service/bean/CatalogSubscribeTask.java index cfaef712..cb027c82 100644 --- a/src/main/java/com/genersoft/iot/vmp/service/bean/CatalogSubscribeTask.java +++ b/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; Element rootElement = null; if (event.getResponse().getRawContent() != null) { - try { - rootElement = XmlUtil.getRootElement(event.getResponse().getRawContent(), "gb2312"); - } 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); - } + // 成功 + logger.info("[目录订阅]成功: {}", device.getDeviceId()); }else { // 成功 logger.info("[目录订阅]成功: {}", device.getDeviceId()); diff --git a/src/main/java/com/genersoft/iot/vmp/service/bean/GPSMsgInfo.java b/src/main/java/com/genersoft/iot/vmp/service/bean/GPSMsgInfo.java new file mode 100644 index 00000000..b814c18f --- /dev/null +++ b/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; + } +} diff --git a/src/main/java/com/genersoft/iot/vmp/service/impl/DeviceServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/service/impl/DeviceServiceImpl.java index 11594847..66407a1c 100644 --- a/src/main/java/com/genersoft/iot/vmp/service/impl/DeviceServiceImpl.java +++ b/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) { return false; } + if (dynamicTask.contains(device.getDeviceId())) { + logger.info("[添加目录订阅] 设备{}的目录订阅以存在", device.getDeviceId()); + return false; + } + logger.info("[添加目录订阅] 设备{}", device.getDeviceId()); // 添加目录订阅 CatalogSubscribeTask catalogSubscribeTask = new CatalogSubscribeTask(device, sipCommander); catalogSubscribeTask.run(); // 提前开始刷新订阅 - // TODO 使用jain sip的当时刷新订阅 int subscribeCycleForCatalog = device.getSubscribeCycleForCatalog(); // 设置最小值为30 subscribeCycleForCatalog = Math.max(subscribeCycleForCatalog, 30); diff --git a/src/main/java/com/genersoft/iot/vmp/service/impl/GbStreamServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/service/impl/GbStreamServiceImpl.java index 5002d29d..79e0b7ab 100644 --- a/src/main/java/com/genersoft/iot/vmp/service/impl/GbStreamServiceImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/service/impl/GbStreamServiceImpl.java @@ -1,7 +1,14 @@ 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.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.ParentPlatformMapper; import com.genersoft.iot.vmp.storager.dao.PlatformGbStreamMapper; import com.genersoft.iot.vmp.service.IGbStreamService; import com.github.pagehelper.PageHelper; @@ -14,6 +21,7 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.TransactionDefinition; import org.springframework.transaction.TransactionStatus; +import java.util.ArrayList; import java.util.List; @Service @@ -33,10 +41,19 @@ public class GbStreamServiceImpl implements IGbStreamService { @Autowired private PlatformGbStreamMapper platformGbStreamMapper; + @Autowired + private ParentPlatformMapper platformMapper; + + @Autowired + private SipConfig sipConfig; + + @Autowired + private EventPublisher eventPublisher; + @Override - public PageInfo getAll(Integer page, Integer count) { + public PageInfo getAll(Integer page, Integer count, String platFormId) { PageHelper.startPage(page, count); - List all = gbStreamMapper.selectAll(); + List all = gbStreamMapper.selectAll(platFormId); return new PageInfo<>(all); } @@ -47,34 +64,66 @@ public class GbStreamServiceImpl implements IGbStreamService { @Override - public boolean addPlatformInfo(List gbStreams, String platformId) { + public boolean addPlatformInfo(List gbStreams, String platformId, String catalogId) { // 放在事务内执行 boolean result = false; TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition); + ParentPlatform parentPlatform = platformMapper.getParentPlatByServerGBId(platformId); try { + List deviceChannelList = new ArrayList<>(); for (GbStream gbStream : gbStreams) { + gbStream.setCatalogId(catalogId); gbStream.setPlatformId(platformId); + // TODO 修改为批量提交 platformGbStreamMapper.add(gbStream); + DeviceChannel deviceChannelListByStream = getDeviceChannelListByStream(gbStream, catalogId, parentPlatform.getDeviceGBId()); + deviceChannelList.add(deviceChannelListByStream); } dataSourceTransactionManager.commit(transactionStatus); //手动提交 + eventPublisher.catalogEventPublish(platformId, deviceChannelList, CatalogEvent.ADD); result = true; }catch (Exception e) { logger.error("批量保存流与平台的关系时错误", e); dataSourceTransactionManager.rollback(transactionStatus); } 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 - public boolean delPlatformInfo(List gbStreams) { + public boolean delPlatformInfo(String platformId, List gbStreams) { // 放在事务内执行 boolean result = false; TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition); try { + List deviceChannelList = new ArrayList<>(); for (GbStream gbStream : gbStreams) { 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); //手动提交 result = true; }catch (Exception e) { @@ -83,4 +132,27 @@ public class GbStreamServiceImpl implements IGbStreamService { } return result; } + + @Override + public void sendCatalogMsg(GbStream gbStream, String type) { + List 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 parentPlatforms = platformGbStreamMapper.selectByAppAndStream(gs.getApp(), gs.getStream()); + if (parentPlatforms.size() > 0) { + for (ParentPlatform parentPlatform : parentPlatforms) { + eventPublisher.catalogEventPublishForStream(parentPlatform.getServerGBId(), gs, type); + } + } + } + } + } } diff --git a/src/main/java/com/genersoft/iot/vmp/service/impl/RedisGPSMsgListener.java b/src/main/java/com/genersoft/iot/vmp/service/impl/RedisGPSMsgListener.java new file mode 100644 index 00000000..e3bfcde7 --- /dev/null +++ b/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); + } +} diff --git a/src/main/java/com/genersoft/iot/vmp/service/impl/StreamProxyServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/service/impl/StreamProxyServiceImpl.java index a972585a..1c8f191f 100644 --- a/src/main/java/com/genersoft/iot/vmp/service/impl/StreamProxyServiceImpl.java +++ b/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.genersoft.iot.vmp.common.StreamInfo; +import com.genersoft.iot.vmp.conf.SipConfig; 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.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.ZLMServerConfig; import com.genersoft.iot.vmp.media.zlm.dto.MediaItem; @@ -57,12 +61,18 @@ public class StreamProxyServiceImpl implements IStreamProxyService { @Autowired private UserSetup userSetup; + @Autowired + private SipConfig sipConfig; + @Autowired private GbStreamMapper gbStreamMapper; @Autowired private PlatformGbStreamMapper platformGbStreamMapper; + @Autowired + private EventPublisher eventPublisher; + @Autowired private ParentPlatformMapper parentPlatformMapper; @@ -130,7 +140,7 @@ public class StreamProxyServiceImpl implements IStreamProxyService { if ( !StringUtils.isEmpty(param.getPlatformGbId()) && streamLive) { List gbStreams = new ArrayList<>(); gbStreams.add(param); - if (gbStreamService.addPlatformInfo(gbStreams, param.getPlatformGbId())){ + if (gbStreamService.addPlatformInfo(gbStreams, param.getPlatformGbId(), param.getCatalogId())){ result.append(", 关联国标平台[ " + param.getPlatformGbId() + " ]成功"); }else { result.append(", 关联国标平台[ " + param.getPlatformGbId() + " ]失败"); @@ -141,10 +151,12 @@ public class StreamProxyServiceImpl implements IStreamProxyService { if (parentPlatforms.size() > 0) { for (ParentPlatform parentPlatform : parentPlatforms) { param.setPlatformId(parentPlatform.getServerGBId()); + param.setCatalogId(parentPlatform.getCatalogId()); String stream = param.getStream(); StreamProxyItem streamProxyItems = platformGbStreamMapper.selectOne(param.getApp(), stream, parentPlatform.getServerGBId()); if (streamProxyItems == null) { 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) { StreamProxyItem streamProxyItem = videoManagerStorager.queryStreamProxy(app, stream); if (streamProxyItem != null) { + gbStreamService.sendCatalogMsg(streamProxyItem, CatalogEvent.DEL); videoManagerStorager.deleteStreamProxy(app, stream); JSONObject jsonObject = removeStreamProxyFromZlm(streamProxyItem); if (jsonObject != null && jsonObject.getInteger("code") == 0) { @@ -278,18 +291,18 @@ public class StreamProxyServiceImpl implements IStreamProxyService { String type = "PULL"; // 发送redis消息 - List streamInfoList = redisCatchStorage.getStreams(mediaServerId, type); - if (streamInfoList.size() > 0) { - for (StreamInfo streamInfo : streamInfoList) { + List mediaItems = redisCatchStorage.getStreams(mediaServerId, type); + if (mediaItems.size() > 0) { + for (MediaItem mediaItem : mediaItems) { JSONObject jsonObject = new JSONObject(); jsonObject.put("serverId", userSetup.getServerId()); - jsonObject.put("app", streamInfo.getApp()); - jsonObject.put("stream", streamInfo.getStreamId()); + jsonObject.put("app", mediaItem.getApp()); + jsonObject.put("stream", mediaItem.getStream()); jsonObject.put("register", false); jsonObject.put("mediaServerId", mediaServerId); redisCatchStorage.sendStreamChangeMsg(type, jsonObject); // 移除redis内流的信息 - redisCatchStorage.removeStream(mediaServerId, type, streamInfo.getApp(), streamInfo.getStreamId()); + redisCatchStorage.removeStream(mediaServerId, type, mediaItem.getApp(), mediaItem.getStream()); } } } diff --git a/src/main/java/com/genersoft/iot/vmp/service/impl/StreamPushServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/service/impl/StreamPushServiceImpl.java index 5fef8cf5..ebfa124b 100644 --- a/src/main/java/com/genersoft/iot/vmp/service/impl/StreamPushServiceImpl.java +++ b/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.genersoft.iot.vmp.common.StreamInfo; 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.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.ZLMRESTfulUtils; import com.genersoft.iot.vmp.media.zlm.ZLMServerConfig; 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.IStreamPushService; 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.PlatformGbStreamMapper; 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.PageInfo; import org.springframework.beans.factory.annotation.Autowired; @@ -41,6 +46,12 @@ public class StreamPushServiceImpl implements IStreamPushService { @Autowired private PlatformGbStreamMapper platformGbStreamMapper; + @Autowired + private IGbStreamService gbStreamService; + + @Autowired + private EventPublisher eventPublisher; + @Autowired private ZLMRESTfulUtils zlmresTfulUtils; @@ -115,24 +126,38 @@ public class StreamPushServiceImpl implements IStreamPushService { stream.setStreamType("push"); stream.setStatus(true); int add = gbStreamMapper.add(stream); + // 查找开启了全部直播流共享的上级平台 List parentPlatforms = parentPlatformMapper.selectAllAhareAllLiveStream(); if (parentPlatforms.size() > 0) { for (ParentPlatform parentPlatform : parentPlatforms) { + stream.setCatalogId(parentPlatform.getCatalogId()); stream.setPlatformId(parentPlatform.getServerGBId()); String streamId = stream.getStream(); - StreamProxyItem streamProxyItems = platformGbStreamMapper.selectOne(stream.getApp(), streamId, parentPlatform.getServerGBId()); - if (streamProxyItems == null) { + 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); + } } } } + return add > 0; } @Override public boolean removeFromGB(GbStream stream) { + // 判断是否需要发送事件 + gbStreamService.sendCatalogMsg(stream, CatalogEvent.DEL); int del = gbStreamMapper.del(stream.getApp(), stream.getStream()); + platformGbStreamMapper.delByAppAndStream(stream.getApp(), stream.getStream()); MediaServerItem mediaInfo = mediaServerService.getOne(stream.getMediaServerId()); JSONObject mediaList = zlmresTfulUtils.getMediaList(mediaInfo, stream.getApp(), stream.getStream()); if (mediaList == null) { @@ -151,6 +176,8 @@ public class StreamPushServiceImpl implements IStreamPushService { @Override public boolean stop(String app, String streamId) { StreamPushItem streamPushItem = streamPushMapper.selectOne(app, streamId); + gbStreamService.sendCatalogMsg(streamPushItem, CatalogEvent.DEL); + int delStream = streamPushMapper.del(app, streamId); gbStreamMapper.del(app, streamId); platformGbStreamMapper.delByAppAndStream(app, streamId); @@ -172,16 +199,16 @@ public class StreamPushServiceImpl implements IStreamPushService { List pushList = getPushList(mediaServerId); Map pushItemMap = new HashMap<>(); // redis记录 - List streamInfoPushList = redisCatchStorage.getStreams(mediaServerId, "PUSH"); - Map streamInfoPushItemMap = new HashMap<>(); + List mediaItems = redisCatchStorage.getStreams(mediaServerId, "PUSH"); + Map streamInfoPushItemMap = new HashMap<>(); if (pushList.size() > 0) { for (StreamPushItem streamPushItem : pushList) { pushItemMap.put(streamPushItem.getApp() + streamPushItem.getStream(), streamPushItem); } } - if (streamInfoPushList.size() > 0) { - for (StreamInfo streamInfo : streamInfoPushList) { - streamInfoPushItemMap.put(streamInfo.getApp() + streamInfo.getStreamId(), streamInfo); + if (mediaItems.size() > 0) { + for (MediaItem mediaItem : mediaItems) { + streamInfoPushItemMap.put(mediaItem.getApp() + mediaItem.getStream(), mediaItem); } } zlmresTfulUtils.getMediaList(mediaServerItem, (mediaList ->{ @@ -220,19 +247,19 @@ public class StreamPushServiceImpl implements IStreamPushService { } } - Collection offlineStreamInfoItems = streamInfoPushItemMap.values(); - if (offlineStreamInfoItems.size() > 0) { + Collection offlineMediaItemList = streamInfoPushItemMap.values(); + if (offlineMediaItemList.size() > 0) { String type = "PUSH"; - for (StreamInfo offlineStreamInfoItem : offlineStreamInfoItems) { + for (MediaItem offlineMediaItem : offlineMediaItemList) { JSONObject jsonObject = new JSONObject(); jsonObject.put("serverId", userSetup.getServerId()); - jsonObject.put("app", offlineStreamInfoItem.getApp()); - jsonObject.put("stream", offlineStreamInfoItem.getStreamId()); + jsonObject.put("app", offlineMediaItem.getApp()); + jsonObject.put("stream", offlineMediaItem.getStream()); jsonObject.put("register", false); jsonObject.put("mediaServerId", mediaServerId); redisCatchStorage.sendStreamChangeMsg(type, jsonObject); // 移除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"; // 发送redis消息 - List streamInfoList = redisCatchStorage.getStreams(mediaServerId, type); + List streamInfoList = redisCatchStorage.getStreams(mediaServerId, type); if (streamInfoList.size() > 0) { - for (StreamInfo streamInfo : streamInfoList) { + for (MediaItem mediaItem : streamInfoList) { // 移除redis内流的信息 - redisCatchStorage.removeStream(mediaServerId, type, streamInfo.getApp(), streamInfo.getStreamId()); + redisCatchStorage.removeStream(mediaServerId, type, mediaItem.getApp(), mediaItem.getStream()); JSONObject jsonObject = new JSONObject(); jsonObject.put("serverId", userSetup.getServerId()); - jsonObject.put("app", streamInfo.getApp()); - jsonObject.put("stream", streamInfo.getStreamId()); + jsonObject.put("app", mediaItem.getApp()); + jsonObject.put("stream", mediaItem.getStream()); jsonObject.put("register", false); jsonObject.put("mediaServerId", mediaServerId); redisCatchStorage.sendStreamChangeMsg(type, jsonObject); @@ -295,4 +322,37 @@ public class StreamPushServiceImpl implements IStreamPushService { } return true; } + + @Override + public void batchAdd(List streamPushItems) { + streamPushMapper.addAll(streamPushItems); + gbStreamMapper.batchAdd(streamPushItems); + // 查找开启了全部直播流共享的上级平台 + List 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); + } + } + } + } + + + } + } } diff --git a/src/main/java/com/genersoft/iot/vmp/service/impl/StreamPushUploadFileHandler.java b/src/main/java/com/genersoft/iot/vmp/service/impl/StreamPushUploadFileHandler.java new file mode 100644 index 00000000..16924df3 --- /dev/null +++ b/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 { + + private ErrorDataHandler errorDataHandler; + private IStreamPushService pushService; + private String defaultMediaServerId; + private List streamPushItems = new ArrayList<>(); + private Set streamPushStreamSet = new HashSet<>(); + private Set streamPushGBSet = new HashSet<>(); + private List errorStreamList = new ArrayList<>(); + private List 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 streams, List 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); + } +} diff --git a/src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java b/src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java index 68a772ef..bf2104c7 100644 --- a/src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java +++ b/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.genersoft.iot.vmp.common.StreamInfo; -import com.genersoft.iot.vmp.gb28181.bean.Device; -import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; -import com.genersoft.iot.vmp.gb28181.bean.ParentPlatformCatch; -import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem; +import com.genersoft.iot.vmp.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.StreamPushItem; +import com.genersoft.iot.vmp.service.bean.GPSMsgInfo; import com.genersoft.iot.vmp.service.bean.ThirdPartyGB; import java.util.List; @@ -145,7 +145,7 @@ public interface IRedisCatchStorage { * @param app * @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 @@ -177,7 +177,7 @@ public interface IRedisCatchStorage { */ ThirdPartyGB queryMemberNoGBId(String queryKey); - List getStreams(String mediaServerId, String pull); + List getStreams(String mediaServerId, String pull); /** * 将device信息写入redis @@ -185,10 +185,33 @@ public interface IRedisCatchStorage { */ void updateDevice(Device device); + void removeDevice(String deviceId); + /** * 获取Device */ Device getDevice(String deviceId); void resetAllCSEQ(); + + void updateGpsMsgInfo(GPSMsgInfo gpsMsgInfo); + + GPSMsgInfo getGpsMsgInfo(String gbId); + List 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 getAllSubscribe(); + + List getAllSubscribePlatform(); } diff --git a/src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorager.java b/src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorager.java index 9118d760..e4bda3f0 100644 --- a/src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorager.java +++ b/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.StreamProxyItem; 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.github.pagehelper.PageInfo; @@ -99,6 +100,7 @@ public interface IVideoManagerStorager { * @return */ public List queryChannelsByDeviceId(String deviceId); + public List queryOnlineChannelsByDeviceId(String deviceId); /** * 获取某个设备的通道 @@ -243,7 +245,7 @@ public interface IVideoManagerStorager { * @param channelReduces * @return */ - int updateChannelForGB(String platformId, List channelReduces); + int updateChannelForGB(String platformId, List channelReduces, String catalogId); /** * 移除上级平台的通道信息 @@ -256,6 +258,9 @@ public interface IVideoManagerStorager { DeviceChannel queryChannelInParentPlatform(String platformId, String channelId); + List queryChannelInParentPlatformAndCatalog(String platformId, String catalogId); + List queryStreamInParentPlatformAndCatalog(String platformId, String catalogId); + Device queryVideoDeviceByPlatformIdAndChannelId(String platformId, String channelId); @@ -337,7 +342,7 @@ public interface IVideoManagerStorager { * @param channelId * @return */ - List queryStreamInParentPlatform(String platformId, String channelId); + GbStream queryStreamInParentPlatform(String platformId, String channelId); /** * 获取平台关联的直播流 @@ -431,4 +436,38 @@ public interface IVideoManagerStorager { * @param deviceChannelList */ boolean resetChannels(String deviceId, List deviceChannelList); + + /** + * 获取目录信息 + * @param platformId + * @param parentId + * @return + */ + List 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 queryCatalogInPlatform(String serverGBId); + + int delRelation(PlatformCatalog platformCatalog); + + int updateStreamGPS(List gpsMsgInfo); + + List queryPlatFormListForGBWithGBId(String channelId, List platforms); + + List queryPlatFormListForStreamWithGBId(String app, String stream, List platforms); + + GbStream getGbStream(String app, String streamId); + + void delCatalogByPlatformId(String serverGBId); + + void delRelationByPlatformId(String serverGBId); } diff --git a/src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceChannelMapper.java b/src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceChannelMapper.java index 8377ccbf..4a12ce4b 100644 --- a/src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceChannelMapper.java +++ b/src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceChannelMapper.java @@ -54,17 +54,22 @@ public interface DeviceChannelMapper { int update(DeviceChannel channel); @Select(value = {" "}) List queryChannels(String deviceId, String parentChannelId, String query, Boolean hasSubChannel, Boolean online); @@ -91,7 +96,8 @@ public interface DeviceChannelMapper { "SELECT * FROM ( "+ " SELECT dc.channelId, dc.deviceId, dc.name, de.manufacturer, de.hostAddress, " + "(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 " + "LEFT JOIN device de ON dc.deviceId = de.deviceId " + " WHERE 1=1 " + @@ -169,19 +175,30 @@ public interface DeviceChannelMapper { ""}) int batchUpdate(List updateChannels); + @Select(value = {" "}) - List queryChannelsByDeviceIdWithStartAndLimit(String deviceId, String parentChannelId, String query, Boolean hasSubChannel, Boolean online, int start, int limit); + List 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 queryOnlineChannelsByDeviceId(String deviceId); } diff --git a/src/main/java/com/genersoft/iot/vmp/storager/dao/GbStreamMapper.java b/src/main/java/com/genersoft/iot/vmp/storager/dao/GbStreamMapper.java index ffbca9c9..ce6ac9ef 100644 --- a/src/main/java/com/genersoft/iot/vmp/storager/dao/GbStreamMapper.java +++ b/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.media.zlm.dto.StreamProxyItem; 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.springframework.stereotype.Repository; @@ -12,7 +14,7 @@ import java.util.List; @Repository 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" + "('${app}', '${stream}', '${gbId}', '${name}', " + "'${longitude}', '${latitude}', '${streamType}', " + @@ -35,8 +37,10 @@ public interface GbStreamMapper { @Delete("DELETE FROM gb_stream WHERE app=#{app} AND stream=#{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") - List selectAll(); + @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.platformId is null OR pgs.platformId = #{platformId}") + List selectAll(String platformId); @Select("SELECT * FROM gb_stream WHERE app=#{app} AND stream=#{stream}") StreamProxyItem selectOne(String app, String stream); @@ -44,32 +48,31 @@ public interface GbStreamMapper { @Select("SELECT * FROM gb_stream WHERE gbId=#{gbId}") List 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 " + "WHERE gs.gbId = '${gbId}' AND pgs.platformId = '${platformId}'") - List 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 " + "WHERE pgs.platformId = '${platformId}'") List 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 queryStreamNotInPlatform(); + @Update("UPDATE gb_stream " + "SET status=${status} " + "WHERE app=#{app} AND stream=#{stream}") 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 selectAllByMediaServerId(String mediaServerId); - @Update("UPDATE gb_stream " + "SET status=${status} " + "WHERE mediaServerId=#{mediaServerId} ") 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}") void deleteWithoutGBId(String type, String mediaServerId); @@ -82,7 +85,7 @@ public interface GbStreamMapper { void batchDel(List streamProxyItemList); @Insert("") void batchAdd(List subList); + + @Update({""}) + int updateStreamGPS(List gpsMsgInfos); } diff --git a/src/main/java/com/genersoft/iot/vmp/storager/dao/ParentPlatformMapper.java b/src/main/java/com/genersoft/iot/vmp/storager/dao/ParentPlatformMapper.java index c92711ae..4f0cbeae 100644 --- a/src/main/java/com/genersoft/iot/vmp/storager/dao/ParentPlatformMapper.java +++ b/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, " + " devicePort, username, password, expires, keepTimeout, transport, characterSet, ptz, rtcp, " + - " status, shareAllLiveStream) " + + " status, shareAllLiveStream, catalogId) " + " VALUES (${enable}, '${name}', '${serverGBId}', '${serverGBDomain}', '${serverIP}', ${serverPort}, '${deviceGBId}', '${deviceIp}', " + " '${devicePort}', '${username}', '${password}', '${expires}', '${keepTimeout}', '${transport}', '${characterSet}', ${ptz}, ${rtcp}, " + - " ${status}, ${shareAllLiveStream})") + " ${status}, ${shareAllLiveStream}, #{catalogId})") int addParentPlatform(ParentPlatform parentPlatform); @Update("UPDATE parent_platform " + @@ -40,7 +40,8 @@ public interface ParentPlatformMapper { "ptz=#{ptz}, " + "rtcp=#{rtcp}, " + "status=#{status}, " + - "shareAllLiveStream=#{shareAllLiveStream} " + + "shareAllLiveStream=#{shareAllLiveStream}, " + + "catalogId=#{catalogId} " + "WHERE id=#{id}") int updateParentPlatform(ParentPlatform parentPlatform); @@ -74,4 +75,11 @@ public interface ParentPlatformMapper { @Select("SELECT * FROM parent_platform WHERE shareAllLiveStream=true") List selectAllAhareAllLiveStream(); + + @Update(value = {" "}) + int setDefaultCatalog(String platformId, String catalogId); } diff --git a/src/main/java/com/genersoft/iot/vmp/storager/dao/PlatformCatalogMapper.java b/src/main/java/com/genersoft/iot/vmp/storager/dao/PlatformCatalogMapper.java new file mode 100644 index 00000000..59ecdbcb --- /dev/null +++ b/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 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 = {" "}) + 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 selectByPlatForm(String platformId); +} diff --git a/src/main/java/com/genersoft/iot/vmp/storager/dao/PlatformChannelMapper.java b/src/main/java/com/genersoft/iot/vmp/storager/dao/PlatformChannelMapper.java index c8130c34..4f5de2b8 100644 --- a/src/main/java/com/genersoft/iot/vmp/storager/dao/PlatformChannelMapper.java +++ b/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.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 org.apache.ibatis.annotations.Delete; import org.apache.ibatis.annotations.Insert; @@ -25,9 +27,9 @@ public interface PlatformChannelMapper { List findChannelRelatedPlatform(String platformId, List deviceAndChannelIds); @Insert("") int addChannels(String platformId, List channelReducesToAdd); @@ -54,6 +56,41 @@ public interface PlatformChannelMapper { "platformId='${platformId}' AND channelId='${channelId}' ) AND channelId='${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 queryChannelInParentPlatformAndCatalog(String platformId, String catalogId); + @Select("SELECT * FROM device WHERE deviceId = (SELECT deviceId FROM platform_gb_channel WHERE platformId='${platformId}' AND channelId='${channelId}')") Device queryVideoDeviceByPlatformIdAndChannelId(String platformId, String channelId); + + @Delete("") + int delByCatalogId(String id); + + @Delete("") + int delByCatalogIdAndChannelIdAndPlatformId(PlatformCatalog platformCatalog); + + @Select(" ") + List queryPlatFormListForGBWithGBId(String channelId, List platforms); + + @Delete("") + void delByPlatformId(String serverGBId); } diff --git a/src/main/java/com/genersoft/iot/vmp/storager/dao/PlatformGbStreamMapper.java b/src/main/java/com/genersoft/iot/vmp/storager/dao/PlatformGbStreamMapper.java index a51eda2d..a07e68ee 100644 --- a/src/main/java/com/genersoft/iot/vmp/storager/dao/PlatformGbStreamMapper.java +++ b/src/main/java/com/genersoft/iot/vmp/storager/dao/PlatformGbStreamMapper.java @@ -1,5 +1,8 @@ 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.media.zlm.dto.StreamProxyItem; import org.apache.ibatis.annotations.*; @@ -12,8 +15,8 @@ import java.util.List; @Repository public interface PlatformGbStreamMapper { - @Insert("INSERT INTO platform_gb_stream (app, stream, platformId) VALUES" + - "('${app}', '${stream}', '${platformId}')") + @Insert("REPLACE INTO platform_gb_stream (app, stream, platformId, catalogId) VALUES" + + "('${app}', '${stream}', '${platformId}', '${catalogId}')") int add(PlatformGbStream platformGbStream); @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}") int delByPlatformId(String platformId); - @Select("SELECT * FROM platform_gb_stream WHERE app=#{app} AND stream=#{stream}") - List selectByAppAndStream(String app, String stream); + @Select("SELECT " + + "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 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); + + @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 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 queryChannelInParentPlatformAndCatalogForCatalog(String platformId, String catalogId); + + @Delete("DELETE FROM platform_gb_stream WHERE catalogId=#{id}") + int delByCatalogId(String id); + + @Select(" ") + List queryPlatFormListForGBWithGBId(String app, String stream, List platforms); + + @Select("SELECT * FROM platform_gb_stream WHERE app=#{app} AND stream=#{stream} AND platformId=#{platformId}") + int delByAppAndStreamAndPlatform(String app, String streamId, String platformId); } diff --git a/src/main/java/com/genersoft/iot/vmp/storager/dao/StreamPushMapper.java b/src/main/java/com/genersoft/iot/vmp/storager/dao/StreamPushMapper.java index c5b22f8b..9a5d3be6 100644 --- a/src/main/java/com/genersoft/iot/vmp/storager/dao/StreamPushMapper.java +++ b/src/main/java/com/genersoft/iot/vmp/storager/dao/StreamPushMapper.java @@ -40,7 +40,7 @@ public interface StreamPushMapper { "") int delAll(List 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 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}") @@ -50,9 +50,9 @@ public interface StreamPushMapper { StreamPushItem selectOne(String app, String stream); @Insert(" diff --git a/web_src/src/components/dialog/catalogEdit.vue b/web_src/src/components/dialog/catalogEdit.vue new file mode 100644 index 00000000..5b594947 --- /dev/null +++ b/web_src/src/components/dialog/catalogEdit.vue @@ -0,0 +1,101 @@ + + + diff --git a/web_src/src/components/dialog/chooseChannel.vue b/web_src/src/components/dialog/chooseChannel.vue index 87fc62e4..23df2c1b 100644 --- a/web_src/src/components/dialog/chooseChannel.vue +++ b/web_src/src/components/dialog/chooseChannel.vue @@ -1,25 +1,40 @@ @@ -27,12 +42,14 @@ + + diff --git a/web_src/src/components/dialog/chooseChannelForGb.vue b/web_src/src/components/dialog/chooseChannelForGb.vue index f5c66d26..e46d3e57 100644 --- a/web_src/src/components/dialog/chooseChannelForGb.vue +++ b/web_src/src/components/dialog/chooseChannelForGb.vue @@ -21,15 +21,14 @@ - 全部共享 + - - - + + - + - +