Commit bdf799fb6458e1d906e70b37ba36065afac3ac0b
Committed by
GitHub
Merge branch 'wvp-28181-2.0' into wvp-28181-2.0
Showing
26 changed files
with
1071 additions
and
917 deletions
README.md
| 1 | - | 1 | + |
| 2 | # 撘蝞勗28181悅閫像 | 2 | # 撘蝞勗28181悅閫像 |
| 3 | 3 | ||
| 4 | [](https://travis-ci.org/xia-chu/ZLMediaKit) | 4 | [](https://travis-ci.org/xia-chu/ZLMediaKit) |
| @@ -17,7 +17,7 @@ WEB VIDEO PLATFORM銝銝芸鈭B28181-2016蝞勗 | @@ -17,7 +17,7 @@ WEB VIDEO PLATFORM銝銝芸鈭B28181-2016蝞勗 | ||
| 17 | # 摨嚗 | 17 | # 摨嚗 |
| 18 | 辣仍閫 | 18 | 辣仍閫 |
| 19 | 像VR蝑挽憭 | 19 | 像VR蝑挽憭 |
| 20 | -漣 | 20 | +漣像蝥扯楊蝵 |
| 21 | tsp/rtmp蝑蓮像 | 21 | tsp/rtmp蝑蓮像 |
| 22 | tsp/rtmp蝑瘚蓮像 | 22 | tsp/rtmp蝑瘚蓮像 |
| 23 | 23 | ||
| @@ -31,62 +31,49 @@ WEB VIDEO PLATFORM銝銝芸鈭B28181-2016蝞勗 | @@ -31,62 +31,49 @@ WEB VIDEO PLATFORM銝銝芸鈭B28181-2016蝞勗 | ||
| 31 | https://gitee.com/pan648540858/wvp-GB28181-pro.git | 31 | https://gitee.com/pan648540858/wvp-GB28181-pro.git |
| 32 | 32 | ||
| 33 | # | 33 | # |
| 34 | - | ||
| 35 | - | ||
| 36 | - | ||
| 37 | - | ||
| 38 | - | ||
| 39 | - | ||
| 40 | - | ||
| 41 | - | ||
| 42 | -# 1.0 蝖 | ||
| 43 | -1. 閫; | ||
| 44 | -2. 鈭嚗憬嚗; | ||
| 45 | -3. 閫挽憭縑郊; | ||
| 46 | -4. 蝳餃蝥輻; | ||
| 47 | -5. 敶霂V嚗鈭VR\DVR嚗翰餈eek; | ||
| 48 | -6. 犖閫瘚; | ||
| 49 | -7. DPCP銝斤縑隞支芋撘; | ||
| 50 | -8. eb, 銝閬蝵脣垢, wvp蔭辣蝵, vp銝韏琿蝵; | ||
| 51 | -9. 像, 笆憭批像憭折挽憭餈; | ||
| 52 | -10. 蝝,; | ||
| 53 | -11. 蔭ZLM慦, 蔭憸憸; | ||
| 54 | -12. udp憭垢璅∪, dp璅∪扯; | ||
| 55 | -13. 憸挽蝵; | ||
| 56 | -14. 敶霂; | ||
| 57 | -15. dp/tcp芋撘; | ||
| 58 | -16. 颲RTSPTMPTTP-FLVebsocket-FLVLS憭悅瘚 | ||
| 59 | -17. | ||
| 60 | -18. 蝵蝵, vp銝lm蝵 | ||
| 61 | -19. h265, g.711撘(閬loseWaitRTPInfo霈曆蛹false) | ||
| 62 | -20. 霅虫縑憭垢霅虫縑 | ||
| 63 | - | ||
| 64 | -# 1.0 | ||
| 65 | -1. eb, 銝閬蝵脣垢, wvp蔭辣蝵, vp銝韏琿蝵; | ||
| 66 | -2. 像, 笆憭批像憭折挽憭餈; | ||
| 67 | -3. 蝝,; | ||
| 68 | -4. 蔭ZLM慦, 蔭憸憸; | ||
| 69 | -5. udp憭垢璅∪, dp璅∪扯; | ||
| 70 | -6. 憸挽蝵; | ||
| 71 | -7. 敶霂; | ||
| 72 | -8. dp/tcp芋撘; | ||
| 73 | -9. 颲RTSPTMPTTP-FLVebsocket-FLVLS憭悅瘚 | ||
| 74 | -10. | ||
| 75 | -11. 蝵蝵, vp銝lm蝵 | ||
| 76 | -12. h265, g.711撘 | ||
| 77 | -13. 摰嚗瘚嚗誨絲. ( [IKI](https://github.com/648540858/wvp-GB28181-pro/wiki/%E5%A6%82%E4%BD%95%E4%BD%BF%E7%94%A8%E5%9B%BA%E5%AE%9A%E6%92%AD%E6%94%BE%E5%9C%B0%E5%9D%80%E4%B8%8E%E8%87%AA%E5%8A%A8%E7%82%B9%E6%92%AD)嚗 | ||
| 78 | -14. 霅虫縑憭垢霅虫縑 | ||
| 79 | -15. 恥瘜 | ||
| 80 | - - [X] 蝘餃雿蔭霈a | ||
| 81 | - - [X] 蝘餃雿蔭憭 | ||
| 82 | - - [X] 霅虫辣霈a | ||
| 83 | - - [X] 霅虫辣憭 | ||
| 84 | - - [X] 霈曉敶恥 | ||
| 85 | - - [X] 霈曉敶憭 | ||
| 86 | -16. 蝘餃雿蔭霂W蝷綽蔭辣霈曄蔭蝘餃雿蔭摮 | ||
| 87 | - | ||
| 88 | -# 2.0 | ||
| 89 | -- [X] 漣 | 34 | + |
| 35 | + | ||
| 36 | + | ||
| 37 | + | ||
| 38 | + | ||
| 39 | + | ||
| 40 | + | ||
| 41 | + | ||
| 42 | +# | ||
| 43 | +- [X] eb | ||
| 44 | +- [X] 摰寞扯憟 | ||
| 45 | +- [X] 摮嚗WGS84CJ02銝斤頂嚗僎銝頧砍蛹頂餈內 | ||
| 46 | +- [X] 霈曉 | ||
| 47 | + - [X] 閫 | ||
| 48 | + - [X] 頝舀嚗憭挽憭鈭扯 | ||
| 49 | + - [X] 鈭嚗霈曉蓮 | ||
| 50 | + - [X] 憸蔭雿霂g蝙銝挽蝵 | ||
| 51 | + - [X] 霂﹫VR/IPC銝嚗銝蝸 | ||
| 52 | + - [X] 犖閫瘚 | ||
| 53 | + - [X] 閫挽憭縑郊 | ||
| 54 | + - [X] 蝳餃蝥輻 | ||
| 55 | + - [X] 颲RTSPTMPTTP-FLVebsocket-FLVLS憭悅瘚 | ||
| 56 | + - [X] 銝芣閫仍嚗敶誑隞颱 | ||
| 57 | + - [X] DPCP銝斤縑隞支芋撘 | ||
| 58 | + - [X] DPCP銝斤芋撘 | ||
| 59 | + - [X] 蝝, | ||
| 60 | + - [X] 敶霂 | ||
| 61 | + - [X] 誘憸甇X敶勗 | ||
| 62 | + - [X] | ||
| 63 | + - [X] H264265 | ||
| 64 | + - [X] 霅虫縑憭垢霅虫縑 | ||
| 65 | + - [X] 恥瘜 | ||
| 66 | + - [X] 蝘餃雿蔭霈a | ||
| 67 | + - [X] 蝘餃雿蔭憭 | ||
| 68 | + - [X] 霅虫辣霈a | ||
| 69 | + - [X] 霅虫辣憭 | ||
| 70 | + - [X] 霈曉敶恥 | ||
| 71 | + - [X] 霈曉敶憭 | ||
| 72 | + - [X] 蝘餃雿蔭霂W蝷 | ||
| 73 | + - [X] 瘛餃挽憭挽憭挽蝵桀 | ||
| 74 | +- [X] 像撖寞 | ||
| 75 | +- [X] 漣 | ||
| 76 | + - [X] 漣 | ||
| 90 | - [X] WEB瘛餃漣撟喳 | 77 | - [X] WEB瘛餃漣撟喳 |
| 91 | - [X] 瘜典 | 78 | - [X] 瘜典 |
| 92 | - [X] 敹歲靽暑 | 79 | - [X] 敹歲靽暑 |
| @@ -101,61 +88,33 @@ https://gitee.com/pan648540858/wvp-GB28181-pro.git | @@ -101,61 +88,33 @@ https://gitee.com/pan648540858/wvp-GB28181-pro.git | ||
| 101 | - [X] 敶恥 | 88 | - [X] 敶恥 |
| 102 | - [X] 敶 | 89 | - [X] 敶 |
| 103 | - [X] GPS霈a嚗瘚 | 90 | - [X] GPS霈a嚗瘚 |
| 104 | -- [X] 瘛餃挽憭挽憭挽蝵桀 | ||
| 105 | -- [X] 瘛餃TSP閫 | ||
| 106 | -- [X] 瘛餃 | ||
| 107 | -- [X] 瘛餃TMP閫 | ||
| 108 | -- [X] 鈭垢敶閬蝵脣蝙嚗 | 91 | +- [X] 蔭ZLM慦, 蔭憸憸; |
| 109 | - [X] 憭嚗韐蝸雿雿輻 | 92 | - [X] 憭嚗韐蝸雿雿輻 |
| 110 | -- [X] WEB蝡舀H264銝265嚗憸.711A/G.711U/AAC,閬虜蝻撘 | ||
| 111 | -- [X] 摮 | ||
| 112 | -- [X] WGS84CJ02銝斤頂 | ||
| 113 | - | ||
| 114 | -[//]: # (# docker敹恍) | ||
| 115 | - | ||
| 116 | -[//]: # (ocker-compose蛹輕銝嚗洵銝之摰嗡蝙嚗輕銝之摰嗉扇敺撈銝泅tar ) | ||
| 117 | - | ||
| 118 | -[//]: # (https://github.com/SaltFish001/wvp_pro_compose) | ||
| 119 | - | ||
| 120 | -[//]: # ([https://github.com/SaltFish001/wvp_pro_compose](https://github.com/SaltFish001/wvp_pro_compose)) | ||
| 121 | - | ||
| 122 | -[//]: # (餈雿輕銝芷摮銝憸) | ||
| 123 | - | ||
| 124 | -[//]: # (```shell) | ||
| 125 | - | ||
| 126 | -[//]: # (docker pull 648540858/wvp_pro) | ||
| 127 | - | ||
| 128 | -[//]: # () | ||
| 129 | -[//]: # (docker run --env WVP_IP="雿P" -it -p 18080:18080 -p 30000-30500:30000-30500/udp -p 30000-30500:30000-30500/tcp -p 80:80 -p 5060:5060 -p 5060:5060/udp 648540858/wvp_pro) | ||
| 130 | - | ||
| 131 | -[//]: # (```) | ||
| 132 | - | ||
| 133 | -[//]: # (docker雿輻霂行https://hub.docker.com/r/648540858/wvp_pro](https://hub.docker.com/r/648540858/wvp_pro)) | ||
| 134 | - | ||
| 135 | -# gitee郊隞 | ||
| 136 | -https://gitee.com/pan648540858/wvp-GB28181-pro.git | ||
| 137 | - | ||
| 138 | -# 憸 | 93 | +- [X] udp憭垢璅∪, dp璅∪扯; |
| 94 | +- [X] 蝵蝵莎 | ||
| 95 | +- [X] vp銝lm蝵莎像撟嗅 | ||
| 96 | +- [X] TSP/RTMP嚗蛹撘隞像 | ||
| 97 | +- [X] 瘚TSP/RTMP嚗蛹撘隞像 | ||
| 98 | +- [X] 瘚 | ||
| 99 | +- [X] | ||
| 100 | +- [X] 鈭垢敶瘚/隞/隞亙鈭垢嚗蝸 | ||
| 101 | + | ||
| 102 | + | ||
| 103 | +# 憸圾 | ||
| 139 | 暻餌鈭挽憭摰寞改隞仿閬之挽憭瘚挽憭偌撟單隞仿憸 | 104 | 暻餌鈭挽憭摰寞改隞仿閬之挽憭瘚挽憭偌撟單隞仿憸 |
| 140 | 1. iki嚗粉隞亙葬雿憸 | 105 | 1. iki嚗粉隞亙葬雿憸 |
| 141 | 2. 揣issues嚗之 | 106 | 2. 揣issues嚗之 |
| 142 | -3. Q蝢歹之敹撈嚗撣歇蝏粉鈭iki揣鈭ssues | 107 | +3. Q蝢歹901799015嚗之敹撈嚗撣歇蝏粉鈭iki揣鈭ssues |
| 143 | 4. 雿隞亥窈雿蛹雿圾蝑晶 | 108 | 4. 雿隞亥窈雿蛹雿圾蝑晶 |
| 144 | 5. 雿隞交憸挽憭隞交摰寞憸 | 109 | 5. 雿隞交憸挽憭隞交摰寞憸 |
| 145 | 110 | ||
| 146 | - | ||
| 147 | -# | ||
| 148 | -蝘摰之摰嗅之銝瓷移憸隞乩晶圾蝑隞交R | ||
| 149 | -嚗笆隞遣霈桀隞交SSUE嚗隞亙黎銝韏瑁賑甈Z頞憿寧銝剜犖 | ||
| 150 | - | ||
| 151 | - | ||
| 152 | - | ||
| 153 | # 雿輻撣桀 | 111 | # 雿輻撣桀 |
| 154 | QQ蝢: 901799015, ZLM雿輻﹝[https://github.com/ZLMediaKit/ZLMediaKit](https://github.com/ZLMediaKit/ZLMediaKit) | 112 | QQ蝢: 901799015, ZLM雿輻﹝[https://github.com/ZLMediaKit/ZLMediaKit](https://github.com/ZLMediaKit/ZLMediaKit) |
| 155 | QQ蝘縑銝銝, 蝎曉.甈Z之摰嗅蝢日悄霈.閫★撖嫣葬嚗洽餈tar漱pr | 113 | QQ蝘縑銝銝, 蝎曉.甈Z之摰嗅蝢日悄霈.閫★撖嫣葬嚗洽餈tar漱pr |
| 156 | 114 | ||
| 157 | # 悅 | 115 | # 悅 |
| 158 | 憿寧誨蝙摰賣IT悅嚗靽縑銝隞亥摨鈭★ 雿憿寧銋蝣蝙鈭鈭隞皞誨銝窈銵隞嚗 鈭蝙憿寧漣熒噩蛹銝璁憿寧嚗窈銵 雿輻憿寧隞嚗砲悅銝剖銵冽憿寧靘洵銝摨悅 | 116 | 憿寧誨蝙摰賣IT悅嚗靽縑銝隞亥摨鈭★ 雿憿寧銋蝣蝙鈭鈭隞皞誨銝窈銵隞嚗 鈭蝙憿寧漣熒噩蛹銝璁憿寧嚗窈銵 雿輻憿寧隞嚗砲悅銝剖銵冽憿寧靘洵銝摨悅 |
| 117 | + | ||
| 159 | # 靚 | 118 | # 靚 |
| 160 | 陝雿憭(https://github.com/xia-chu) 皞獢,撟嗅撘葉蝏葬 | 119 | 陝雿憭(https://github.com/xia-chu) 皞獢,撟嗅撘葉蝏葬 |
| 161 | 陝雿dexter langhuihui](https://github.com/langhuihui) 撘皞末EB | 120 | 陝雿dexter langhuihui](https://github.com/langhuihui) 撘皞末EB |
doc/_content/introduction/config.md
| @@ -31,6 +31,7 @@ java -jar wvp-pro-*.jar | @@ -31,6 +31,7 @@ java -jar wvp-pro-*.jar | ||
| 31 | ## 2 配置WVP-PRO | 31 | ## 2 配置WVP-PRO |
| 32 | ### 2.1 Mysql数据库配置 | 32 | ### 2.1 Mysql数据库配置 |
| 33 | 首先你需要创建一个名为wvp(也可使用其他名字)的数据库,并使用sql/mysql.sql导入数据库,初始化数据库结构。 | 33 | 首先你需要创建一个名为wvp(也可使用其他名字)的数据库,并使用sql/mysql.sql导入数据库,初始化数据库结构。 |
| 34 | +(这里注意,取决于版本,新版的sql文件夹下有update.sql,补丁包,一定要注意运行导入) | ||
| 34 | 在application-dev.yml中配置(使用1.2方式的是在jar包的同级目录的application.yml)配置数据库连接,包括数据库连接信息,密码。 | 35 | 在application-dev.yml中配置(使用1.2方式的是在jar包的同级目录的application.yml)配置数据库连接,包括数据库连接信息,密码。 |
| 35 | ### 2.2 Redis数据库配置 | 36 | ### 2.2 Redis数据库配置 |
| 36 | 配置wvp中的redis连接信息,建议wvp自己单独使用一个db。 | 37 | 配置wvp中的redis连接信息,建议wvp自己单独使用一个db。 |
| @@ -116,4 +117,4 @@ user-settings: | @@ -116,4 +117,4 @@ user-settings: | ||
| 116 | 117 | ||
| 117 | 118 | ||
| 118 | 如果配置信息无误,你可以启动zlm,再启动wvp来测试了,启动成功的话,你可以在wvp的日志下看到zlm已连接的提示。 | 119 | 如果配置信息无误,你可以启动zlm,再启动wvp来测试了,启动成功的话,你可以在wvp的日志下看到zlm已连接的提示。 |
| 119 | -接下来[部署到服务器](./_content/introduction/deployment.md), 如何你只是本地运行直接再本地运行即可。 | ||
| 120 | \ No newline at end of file | 120 | \ No newline at end of file |
| 121 | +接下来[部署到服务器](./_content/introduction/deployment.md), 如何你只是本地运行直接再本地运行即可。 |
doc/_media/2.png
0 → 100644
469 KB
doc/_media/3-1.png
0 → 100644
136 KB
doc/_media/3-2.png
0 → 100644
650 KB
doc/_media/3-3.png
0 → 100644
1.04 MB
doc/_media/3.png
0 → 100644
146 KB
doc/_media/index.png
0 → 100644
154 KB
sql/mysql.sql
| @@ -39,6 +39,7 @@ CREATE TABLE `device` ( | @@ -39,6 +39,7 @@ CREATE TABLE `device` ( | ||
| 39 | `updateTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | 39 | `updateTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, |
| 40 | `port` int DEFAULT NULL, | 40 | `port` int DEFAULT NULL, |
| 41 | `expires` int DEFAULT NULL, | 41 | `expires` int DEFAULT NULL, |
| 42 | + `keepaliveIntervalTime` int DEFAULT NULL, | ||
| 42 | `subscribeCycleForCatalog` int DEFAULT NULL, | 43 | `subscribeCycleForCatalog` int DEFAULT NULL, |
| 43 | `hostAddress` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | 44 | `hostAddress` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, |
| 44 | `charset` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | 45 | `charset` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, |
src/main/java/com/genersoft/iot/vmp/gb28181/session/CatalogDataCatch.java
| @@ -109,12 +109,18 @@ public class CatalogDataCatch { | @@ -109,12 +109,18 @@ public class CatalogDataCatch { | ||
| 109 | 109 | ||
| 110 | for (String deviceId : keys) { | 110 | for (String deviceId : keys) { |
| 111 | CatalogData catalogData = data.get(deviceId); | 111 | CatalogData catalogData = data.get(deviceId); |
| 112 | - if ( catalogData.getLastTime().isBefore(instantBefore5S)) { // 超过五秒收不到消息任务超时, 只更新这一部分数据 | 112 | + if ( catalogData.getLastTime().isBefore(instantBefore5S)) { |
| 113 | + // 超过五秒收不到消息任务超时, 只更新这一部分数据, 收到数据与声明的总数一致,则重置通道数据,数据不全则只对收到的数据做更新操作 | ||
| 113 | if (catalogData.getStatus().equals(CatalogData.CatalogDataStatus.runIng)) { | 114 | if (catalogData.getStatus().equals(CatalogData.CatalogDataStatus.runIng)) { |
| 114 | - storager.resetChannels(catalogData.getDevice().getDeviceId(), catalogData.getChannelList()); | 115 | + if (catalogData.getTotal() == catalogData.getChannelList().size()) { |
| 116 | + storager.resetChannels(catalogData.getDevice().getDeviceId(), catalogData.getChannelList()); | ||
| 117 | + }else { | ||
| 118 | + storager.updateChannels(catalogData.getDevice().getDeviceId(), catalogData.getChannelList()); | ||
| 119 | + } | ||
| 120 | + String errorMsg = "更新成功,共" + catalogData.getTotal() + "条,已更新" + catalogData.getChannelList().size() + "条"; | ||
| 121 | + catalogData.setErrorMsg(errorMsg); | ||
| 115 | if (catalogData.getTotal() != catalogData.getChannelList().size()) { | 122 | if (catalogData.getTotal() != catalogData.getChannelList().size()) { |
| 116 | - String errorMsg = "更新成功,共" + catalogData.getTotal() + "条,已更新" + catalogData.getChannelList().size() + "条"; | ||
| 117 | - catalogData.setErrorMsg(errorMsg); | 123 | + |
| 118 | } | 124 | } |
| 119 | }else if (catalogData.getStatus().equals(CatalogData.CatalogDataStatus.ready)) { | 125 | }else if (catalogData.getStatus().equals(CatalogData.CatalogDataStatus.ready)) { |
| 120 | String errorMsg = "同步失败,等待回复超时"; | 126 | String errorMsg = "同步失败,等待回复超时"; |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java
| 1 | package com.genersoft.iot.vmp.gb28181.transmit.cmd.impl; | 1 | package com.genersoft.iot.vmp.gb28181.transmit.cmd.impl; |
| 2 | 2 | ||
| 3 | import com.alibaba.fastjson2.JSON; | 3 | import com.alibaba.fastjson2.JSON; |
| 4 | +import com.genersoft.iot.vmp.conf.DynamicTask; | ||
| 4 | import com.genersoft.iot.vmp.gb28181.SipLayer; | 5 | import com.genersoft.iot.vmp.gb28181.SipLayer; |
| 5 | import com.genersoft.iot.vmp.gb28181.bean.*; | 6 | import com.genersoft.iot.vmp.gb28181.bean.*; |
| 6 | import com.genersoft.iot.vmp.gb28181.event.SipSubscribe; | 7 | import com.genersoft.iot.vmp.gb28181.event.SipSubscribe; |
| @@ -61,6 +62,9 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { | @@ -61,6 +62,9 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { | ||
| 61 | @Autowired | 62 | @Autowired |
| 62 | private SIPSender sipSender; | 63 | private SIPSender sipSender; |
| 63 | 64 | ||
| 65 | + @Autowired | ||
| 66 | + private DynamicTask dynamicTask; | ||
| 67 | + | ||
| 64 | @Override | 68 | @Override |
| 65 | public void register(ParentPlatform parentPlatform, SipSubscribe.Event errorEvent , SipSubscribe.Event okEvent) throws InvalidArgumentException, ParseException, SipException { | 69 | public void register(ParentPlatform parentPlatform, SipSubscribe.Event errorEvent , SipSubscribe.Event okEvent) throws InvalidArgumentException, ParseException, SipException { |
| 66 | register(parentPlatform, null, null, errorEvent, okEvent, false, true); | 70 | register(parentPlatform, null, null, errorEvent, okEvent, false, true); |
| @@ -109,13 +113,14 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { | @@ -109,13 +113,14 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { | ||
| 109 | public String keepalive(ParentPlatform parentPlatform,SipSubscribe.Event errorEvent , SipSubscribe.Event okEvent) throws SipException, InvalidArgumentException, ParseException { | 113 | public String keepalive(ParentPlatform parentPlatform,SipSubscribe.Event errorEvent , SipSubscribe.Event okEvent) throws SipException, InvalidArgumentException, ParseException { |
| 110 | String characterSet = parentPlatform.getCharacterSet(); | 114 | String characterSet = parentPlatform.getCharacterSet(); |
| 111 | StringBuffer keepaliveXml = new StringBuffer(200); | 115 | StringBuffer keepaliveXml = new StringBuffer(200); |
| 112 | - keepaliveXml.append("<?xml version=\"1.0\" encoding=\"" + characterSet + "\"?>\r\n"); | ||
| 113 | - keepaliveXml.append("<Notify>\r\n"); | ||
| 114 | - keepaliveXml.append("<CmdType>Keepalive</CmdType>\r\n"); | ||
| 115 | - keepaliveXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n"); | ||
| 116 | - keepaliveXml.append("<DeviceID>" + parentPlatform.getDeviceGBId() + "</DeviceID>\r\n"); | ||
| 117 | - keepaliveXml.append("<Status>OK</Status>\r\n"); | ||
| 118 | - keepaliveXml.append("</Notify>\r\n"); | 116 | + keepaliveXml.append("<?xml version=\"1.0\" encoding=\"") |
| 117 | + .append(characterSet).append("\"?>\r\n") | ||
| 118 | + .append("<Notify>\r\n") | ||
| 119 | + .append("<CmdType>Keepalive</CmdType>\r\n") | ||
| 120 | + .append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n") | ||
| 121 | + .append("<DeviceID>" + parentPlatform.getDeviceGBId() + "</DeviceID>\r\n") | ||
| 122 | + .append("<Status>OK</Status>\r\n") | ||
| 123 | + .append("</Notify>\r\n"); | ||
| 119 | 124 | ||
| 120 | CallIdHeader callIdHeader = sipSender.getNewCallIdHeader(parentPlatform.getDeviceIp(),parentPlatform.getTransport()); | 125 | CallIdHeader callIdHeader = sipSender.getNewCallIdHeader(parentPlatform.getDeviceIp(),parentPlatform.getTransport()); |
| 121 | 126 | ||
| @@ -133,7 +138,6 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { | @@ -133,7 +138,6 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { | ||
| 133 | * 向上级回复通道信息 | 138 | * 向上级回复通道信息 |
| 134 | * @param channel 通道信息 | 139 | * @param channel 通道信息 |
| 135 | * @param parentPlatform 平台信息 | 140 | * @param parentPlatform 平台信息 |
| 136 | - * @return | ||
| 137 | */ | 141 | */ |
| 138 | @Override | 142 | @Override |
| 139 | public void catalogQuery(DeviceChannel channel, ParentPlatform parentPlatform, String sn, String fromTag, int size) throws SipException, InvalidArgumentException, ParseException { | 143 | public void catalogQuery(DeviceChannel channel, ParentPlatform parentPlatform, String sn, String fromTag, int size) throws SipException, InvalidArgumentException, ParseException { |
| @@ -160,18 +164,18 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { | @@ -160,18 +164,18 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { | ||
| 160 | if ( parentPlatform ==null) { | 164 | if ( parentPlatform ==null) { |
| 161 | return ; | 165 | return ; |
| 162 | } | 166 | } |
| 163 | - sendCatalogResponse(channels, parentPlatform, sn, fromTag, 0); | 167 | + sendCatalogResponse(channels, parentPlatform, sn, fromTag, 0, true); |
| 164 | } | 168 | } |
| 165 | private String getCatalogXml(List<DeviceChannel> channels, String sn, ParentPlatform parentPlatform, int size) { | 169 | private String getCatalogXml(List<DeviceChannel> channels, String sn, ParentPlatform parentPlatform, int size) { |
| 166 | String characterSet = parentPlatform.getCharacterSet(); | 170 | String characterSet = parentPlatform.getCharacterSet(); |
| 167 | StringBuffer catalogXml = new StringBuffer(600); | 171 | StringBuffer catalogXml = new StringBuffer(600); |
| 168 | - catalogXml.append("<?xml version=\"1.0\" encoding=\"" + characterSet +"\"?>\r\n"); | ||
| 169 | - catalogXml.append("<Response>\r\n"); | ||
| 170 | - catalogXml.append("<CmdType>Catalog</CmdType>\r\n"); | ||
| 171 | - catalogXml.append("<SN>" +sn + "</SN>\r\n"); | ||
| 172 | - catalogXml.append("<DeviceID>" + parentPlatform.getDeviceGBId() + "</DeviceID>\r\n"); | ||
| 173 | - catalogXml.append("<SumNum>" + size + "</SumNum>\r\n"); | ||
| 174 | - catalogXml.append("<DeviceList Num=\"" + channels.size() +"\">\r\n"); | 172 | + catalogXml.append("<?xml version=\"1.0\" encoding=\"" + characterSet +"\"?>\r\n") |
| 173 | + .append("<Response>\r\n") | ||
| 174 | + .append("<CmdType>Catalog</CmdType>\r\n") | ||
| 175 | + .append("<SN>" +sn + "</SN>\r\n") | ||
| 176 | + .append("<DeviceID>" + parentPlatform.getDeviceGBId() + "</DeviceID>\r\n") | ||
| 177 | + .append("<SumNum>" + size + "</SumNum>\r\n") | ||
| 178 | + .append("<DeviceList Num=\"" + channels.size() +"\">\r\n"); | ||
| 175 | if (channels.size() > 0) { | 179 | if (channels.size() > 0) { |
| 176 | for (DeviceChannel channel : channels) { | 180 | for (DeviceChannel channel : channels) { |
| 177 | if (parentPlatform.getServerGBId().equals(channel.getParentId())) { | 181 | if (parentPlatform.getServerGBId().equals(channel.getParentId())) { |
| @@ -222,7 +226,7 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { | @@ -222,7 +226,7 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { | ||
| 222 | return catalogXml.toString(); | 226 | return catalogXml.toString(); |
| 223 | } | 227 | } |
| 224 | 228 | ||
| 225 | - private void sendCatalogResponse(List<DeviceChannel> channels, ParentPlatform parentPlatform, String sn, String fromTag, int index) throws SipException, InvalidArgumentException, ParseException { | 229 | + private void sendCatalogResponse(List<DeviceChannel> channels, ParentPlatform parentPlatform, String sn, String fromTag, int index, boolean sendAfterResponse) throws SipException, InvalidArgumentException, ParseException { |
| 226 | if (index >= channels.size()) { | 230 | if (index >= channels.size()) { |
| 227 | return; | 231 | return; |
| 228 | } | 232 | } |
| @@ -236,15 +240,49 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { | @@ -236,15 +240,49 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { | ||
| 236 | // callid | 240 | // callid |
| 237 | CallIdHeader callIdHeader = sipSender.getNewCallIdHeader(parentPlatform.getDeviceIp(),parentPlatform.getTransport()); | 241 | CallIdHeader callIdHeader = sipSender.getNewCallIdHeader(parentPlatform.getDeviceIp(),parentPlatform.getTransport()); |
| 238 | 242 | ||
| 239 | - Request request = headerProviderPlatformProvider.createMessageRequest(parentPlatform, catalogXml, fromTag, SipUtils.getNewViaTag(), callIdHeader); | ||
| 240 | - sipSender.transmitRequest(parentPlatform.getDeviceIp(), request, null, eventResult -> { | ||
| 241 | - int indexNext = index + parentPlatform.getCatalogGroup(); | ||
| 242 | - try { | ||
| 243 | - sendCatalogResponse(channels, parentPlatform, sn, fromTag, indexNext); | ||
| 244 | - } catch (SipException | InvalidArgumentException | ParseException e) { | ||
| 245 | - logger.error("[命令发送失败] 国标级联 目录查询回复: {}", e.getMessage()); | ||
| 246 | - } | ||
| 247 | - }); | 243 | + SIPRequest request = (SIPRequest)headerProviderPlatformProvider.createMessageRequest(parentPlatform, catalogXml, fromTag, SipUtils.getNewViaTag(), callIdHeader); |
| 244 | + | ||
| 245 | + String timeoutTaskKey = "catalog_task_" + parentPlatform.getServerGBId() + sn; | ||
| 246 | + | ||
| 247 | + String callId = request.getCallIdHeader().getCallId(); | ||
| 248 | + | ||
| 249 | + if (sendAfterResponse) { | ||
| 250 | + // 默认按照收到200回复后发送下一条, 如果超时收不到回复,就以30毫秒的间隔直接发送。 | ||
| 251 | + dynamicTask.startDelay(timeoutTaskKey, ()->{ | ||
| 252 | + sipSubscribe.removeOkSubscribe(callId); | ||
| 253 | + int indexNext = index + parentPlatform.getCatalogGroup(); | ||
| 254 | + try { | ||
| 255 | + sendCatalogResponse(channels, parentPlatform, sn, fromTag, indexNext, false); | ||
| 256 | + } catch (SipException | InvalidArgumentException | ParseException e) { | ||
| 257 | + logger.error("[命令发送失败] 国标级联 目录查询回复: {}", e.getMessage()); | ||
| 258 | + } | ||
| 259 | + }, 3000); | ||
| 260 | + sipSender.transmitRequest(parentPlatform.getDeviceIp(), request, eventResult -> { | ||
| 261 | + logger.error("[目录推送失败] 国标级联 platform : {}, code: {}, msg: {}, 停止发送", parentPlatform.getServerGBId(), eventResult.statusCode, eventResult.msg); | ||
| 262 | + dynamicTask.stop(timeoutTaskKey); | ||
| 263 | + }, eventResult -> { | ||
| 264 | + dynamicTask.stop(timeoutTaskKey); | ||
| 265 | + int indexNext = index + parentPlatform.getCatalogGroup(); | ||
| 266 | + try { | ||
| 267 | + sendCatalogResponse(channels, parentPlatform, sn, fromTag, indexNext, true); | ||
| 268 | + } catch (SipException | InvalidArgumentException | ParseException e) { | ||
| 269 | + logger.error("[命令发送失败] 国标级联 目录查询回复: {}", e.getMessage()); | ||
| 270 | + } | ||
| 271 | + }); | ||
| 272 | + }else { | ||
| 273 | + sipSender.transmitRequest(parentPlatform.getDeviceIp(), request, eventResult -> { | ||
| 274 | + logger.error("[目录推送失败] 国标级联 platform : {}, code: {}, msg: {}, 停止发送", parentPlatform.getServerGBId(), eventResult.statusCode, eventResult.msg); | ||
| 275 | + dynamicTask.stop(timeoutTaskKey); | ||
| 276 | + }, null); | ||
| 277 | + dynamicTask.startDelay(timeoutTaskKey, ()->{ | ||
| 278 | + int indexNext = index + parentPlatform.getCatalogGroup(); | ||
| 279 | + try { | ||
| 280 | + sendCatalogResponse(channels, parentPlatform, sn, fromTag, indexNext, false); | ||
| 281 | + } catch (SipException | InvalidArgumentException | ParseException e) { | ||
| 282 | + logger.error("[命令发送失败] 国标级联 目录查询回复: {}", e.getMessage()); | ||
| 283 | + } | ||
| 284 | + }, 30); | ||
| 285 | + } | ||
| 248 | } | 286 | } |
| 249 | 287 | ||
| 250 | /** | 288 | /** |
| @@ -294,15 +332,15 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { | @@ -294,15 +332,15 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { | ||
| 294 | String statusStr = (status==1)?"ONLINE":"OFFLINE"; | 332 | String statusStr = (status==1)?"ONLINE":"OFFLINE"; |
| 295 | String characterSet = parentPlatform.getCharacterSet(); | 333 | String characterSet = parentPlatform.getCharacterSet(); |
| 296 | StringBuffer deviceStatusXml = new StringBuffer(600); | 334 | StringBuffer deviceStatusXml = new StringBuffer(600); |
| 297 | - deviceStatusXml.append("<?xml version=\"1.0\" encoding=\"" + characterSet + "\"?>\r\n"); | ||
| 298 | - deviceStatusXml.append("<Response>\r\n"); | ||
| 299 | - deviceStatusXml.append("<CmdType>DeviceStatus</CmdType>\r\n"); | ||
| 300 | - deviceStatusXml.append("<SN>" +sn + "</SN>\r\n"); | ||
| 301 | - deviceStatusXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n"); | ||
| 302 | - deviceStatusXml.append("<Result>OK</Result>\r\n"); | ||
| 303 | - deviceStatusXml.append("<Online>"+statusStr+"</Online>\r\n"); | ||
| 304 | - deviceStatusXml.append("<Status>OK</Status>\r\n"); | ||
| 305 | - deviceStatusXml.append("</Response>\r\n"); | 335 | + deviceStatusXml.append("<?xml version=\"1.0\" encoding=\"" + characterSet + "\"?>\r\n") |
| 336 | + .append("<Response>\r\n") | ||
| 337 | + .append("<CmdType>DeviceStatus</CmdType>\r\n") | ||
| 338 | + .append("<SN>" +sn + "</SN>\r\n") | ||
| 339 | + .append("<DeviceID>" + channelId + "</DeviceID>\r\n") | ||
| 340 | + .append("<Result>OK</Result>\r\n") | ||
| 341 | + .append("<Online>"+statusStr+"</Online>\r\n") | ||
| 342 | + .append("<Status>OK</Status>\r\n") | ||
| 343 | + .append("</Response>\r\n"); | ||
| 306 | 344 | ||
| 307 | CallIdHeader callIdHeader = sipSender.getNewCallIdHeader(parentPlatform.getDeviceIp(),parentPlatform.getTransport()); | 345 | CallIdHeader callIdHeader = sipSender.getNewCallIdHeader(parentPlatform.getDeviceIp(),parentPlatform.getTransport()); |
| 308 | 346 | ||
| @@ -321,18 +359,18 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { | @@ -321,18 +359,18 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { | ||
| 321 | 359 | ||
| 322 | String characterSet = parentPlatform.getCharacterSet(); | 360 | String characterSet = parentPlatform.getCharacterSet(); |
| 323 | StringBuffer deviceStatusXml = new StringBuffer(600); | 361 | StringBuffer deviceStatusXml = new StringBuffer(600); |
| 324 | - deviceStatusXml.append("<?xml version=\"1.0\" encoding=\"" + characterSet + "\"?>\r\n"); | ||
| 325 | - deviceStatusXml.append("<Notify>\r\n"); | ||
| 326 | - deviceStatusXml.append("<CmdType>MobilePosition</CmdType>\r\n"); | ||
| 327 | - deviceStatusXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n"); | ||
| 328 | - deviceStatusXml.append("<DeviceID>" + gpsMsgInfo.getId() + "</DeviceID>\r\n"); | ||
| 329 | - deviceStatusXml.append("<Time>" + gpsMsgInfo.getTime() + "</Time>\r\n"); | ||
| 330 | - deviceStatusXml.append("<Longitude>" + gpsMsgInfo.getLng() + "</Longitude>\r\n"); | ||
| 331 | - deviceStatusXml.append("<Latitude>" + gpsMsgInfo.getLat() + "</Latitude>\r\n"); | ||
| 332 | - deviceStatusXml.append("<Speed>" + gpsMsgInfo.getSpeed() + "</Speed>\r\n"); | ||
| 333 | - deviceStatusXml.append("<Direction>" + gpsMsgInfo.getDirection() + "</Direction>\r\n"); | ||
| 334 | - deviceStatusXml.append("<Altitude>" + gpsMsgInfo.getAltitude() + "</Altitude>\r\n"); | ||
| 335 | - deviceStatusXml.append("</Notify>\r\n"); | 362 | + deviceStatusXml.append("<?xml version=\"1.0\" encoding=\"" + characterSet + "\"?>\r\n") |
| 363 | + .append("<Notify>\r\n") | ||
| 364 | + .append("<CmdType>MobilePosition</CmdType>\r\n") | ||
| 365 | + .append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n") | ||
| 366 | + .append("<DeviceID>" + gpsMsgInfo.getId() + "</DeviceID>\r\n") | ||
| 367 | + .append("<Time>" + gpsMsgInfo.getTime() + "</Time>\r\n") | ||
| 368 | + .append("<Longitude>" + gpsMsgInfo.getLng() + "</Longitude>\r\n") | ||
| 369 | + .append("<Latitude>" + gpsMsgInfo.getLat() + "</Latitude>\r\n") | ||
| 370 | + .append("<Speed>" + gpsMsgInfo.getSpeed() + "</Speed>\r\n") | ||
| 371 | + .append("<Direction>" + gpsMsgInfo.getDirection() + "</Direction>\r\n") | ||
| 372 | + .append("<Altitude>" + gpsMsgInfo.getAltitude() + "</Altitude>\r\n") | ||
| 373 | + .append("</Notify>\r\n"); | ||
| 336 | 374 | ||
| 337 | sendNotify(parentPlatform, deviceStatusXml.toString(), subscribeInfo, eventResult -> { | 375 | sendNotify(parentPlatform, deviceStatusXml.toString(), subscribeInfo, eventResult -> { |
| 338 | logger.error("发送NOTIFY通知消息失败。错误:{} {}", eventResult.statusCode, eventResult.msg); | 376 | logger.error("发送NOTIFY通知消息失败。错误:{} {}", eventResult.statusCode, eventResult.msg); |
| @@ -349,21 +387,21 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { | @@ -349,21 +387,21 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { | ||
| 349 | deviceAlarm.getLongitude(), deviceAlarm.getLatitude(), JSON.toJSONString(deviceAlarm)); | 387 | deviceAlarm.getLongitude(), deviceAlarm.getLatitude(), JSON.toJSONString(deviceAlarm)); |
| 350 | String characterSet = parentPlatform.getCharacterSet(); | 388 | String characterSet = parentPlatform.getCharacterSet(); |
| 351 | StringBuffer deviceStatusXml = new StringBuffer(600); | 389 | StringBuffer deviceStatusXml = new StringBuffer(600); |
| 352 | - deviceStatusXml.append("<?xml version=\"1.0\" encoding=\"" + characterSet + "\"?>\r\n"); | ||
| 353 | - deviceStatusXml.append("<Notify>\r\n"); | ||
| 354 | - deviceStatusXml.append("<CmdType>Alarm</CmdType>\r\n"); | ||
| 355 | - deviceStatusXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n"); | ||
| 356 | - deviceStatusXml.append("<DeviceID>" + deviceAlarm.getChannelId() + "</DeviceID>\r\n"); | ||
| 357 | - deviceStatusXml.append("<AlarmPriority>" + deviceAlarm.getAlarmPriority() + "</AlarmPriority>\r\n"); | ||
| 358 | - deviceStatusXml.append("<AlarmMethod>" + deviceAlarm.getAlarmMethod() + "</AlarmMethod>\r\n"); | ||
| 359 | - deviceStatusXml.append("<AlarmTime>" + deviceAlarm.getAlarmTime() + "</AlarmTime>\r\n"); | ||
| 360 | - deviceStatusXml.append("<AlarmDescription>" + deviceAlarm.getAlarmDescription() + "</AlarmDescription>\r\n"); | ||
| 361 | - deviceStatusXml.append("<Longitude>" + deviceAlarm.getLongitude() + "</Longitude>\r\n"); | ||
| 362 | - deviceStatusXml.append("<Latitude>" + deviceAlarm.getLatitude() + "</Latitude>\r\n"); | ||
| 363 | - deviceStatusXml.append("<info>\r\n"); | ||
| 364 | - deviceStatusXml.append("<AlarmType>" + deviceAlarm.getAlarmType() + "</AlarmType>\r\n"); | ||
| 365 | - deviceStatusXml.append("</info>\r\n"); | ||
| 366 | - deviceStatusXml.append("</Notify>\r\n"); | 390 | + deviceStatusXml.append("<?xml version=\"1.0\" encoding=\"" + characterSet + "\"?>\r\n") |
| 391 | + .append("<Notify>\r\n") | ||
| 392 | + .append("<CmdType>Alarm</CmdType>\r\n") | ||
| 393 | + .append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n") | ||
| 394 | + .append("<DeviceID>" + deviceAlarm.getChannelId() + "</DeviceID>\r\n") | ||
| 395 | + .append("<AlarmPriority>" + deviceAlarm.getAlarmPriority() + "</AlarmPriority>\r\n") | ||
| 396 | + .append("<AlarmMethod>" + deviceAlarm.getAlarmMethod() + "</AlarmMethod>\r\n") | ||
| 397 | + .append("<AlarmTime>" + deviceAlarm.getAlarmTime() + "</AlarmTime>\r\n") | ||
| 398 | + .append("<AlarmDescription>" + deviceAlarm.getAlarmDescription() + "</AlarmDescription>\r\n") | ||
| 399 | + .append("<Longitude>" + deviceAlarm.getLongitude() + "</Longitude>\r\n") | ||
| 400 | + .append("<Latitude>" + deviceAlarm.getLatitude() + "</Latitude>\r\n") | ||
| 401 | + .append("<info>\r\n") | ||
| 402 | + .append("<AlarmType>" + deviceAlarm.getAlarmType() + "</AlarmType>\r\n") | ||
| 403 | + .append("</info>\r\n") | ||
| 404 | + .append("</Notify>\r\n"); | ||
| 367 | 405 | ||
| 368 | CallIdHeader callIdHeader = sipSender.getNewCallIdHeader(parentPlatform.getDeviceIp(),parentPlatform.getTransport()); | 406 | CallIdHeader callIdHeader = sipSender.getNewCallIdHeader(parentPlatform.getDeviceIp(),parentPlatform.getTransport()); |
| 369 | 407 | ||
| @@ -422,13 +460,13 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { | @@ -422,13 +460,13 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { | ||
| 422 | StringBuffer catalogXml = new StringBuffer(600); | 460 | StringBuffer catalogXml = new StringBuffer(600); |
| 423 | 461 | ||
| 424 | String characterSet = parentPlatform.getCharacterSet(); | 462 | String characterSet = parentPlatform.getCharacterSet(); |
| 425 | - catalogXml.append("<?xml version=\"1.0\" encoding=\"" + characterSet + "\"?>\r\n"); | ||
| 426 | - catalogXml.append("<Notify>\r\n"); | ||
| 427 | - catalogXml.append("<CmdType>Catalog</CmdType>\r\n"); | ||
| 428 | - catalogXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n"); | ||
| 429 | - catalogXml.append("<DeviceID>" + parentPlatform.getDeviceGBId() + "</DeviceID>\r\n"); | ||
| 430 | - catalogXml.append("<SumNum>1</SumNum>\r\n"); | ||
| 431 | - catalogXml.append("<DeviceList Num=\"" + channels.size() + "\">\r\n"); | 463 | + catalogXml.append("<?xml version=\"1.0\" encoding=\"" + characterSet + "\"?>\r\n") |
| 464 | + .append("<Notify>\r\n") | ||
| 465 | + .append("<CmdType>Catalog</CmdType>\r\n") | ||
| 466 | + .append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n") | ||
| 467 | + .append("<DeviceID>" + parentPlatform.getDeviceGBId() + "</DeviceID>\r\n") | ||
| 468 | + .append("<SumNum>1</SumNum>\r\n") | ||
| 469 | + .append("<DeviceList Num=\"" + channels.size() + "\">\r\n"); | ||
| 432 | if (channels.size() > 0) { | 470 | if (channels.size() > 0) { |
| 433 | for (DeviceChannel channel : channels) { | 471 | for (DeviceChannel channel : channels) { |
| 434 | if (parentPlatform.getServerGBId().equals(channel.getParentId())) { | 472 | if (parentPlatform.getServerGBId().equals(channel.getParentId())) { |
| @@ -449,16 +487,16 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { | @@ -449,16 +487,16 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { | ||
| 449 | catalogXml.append("<Parental>" + channel.getParental() + "</Parental>\r\n"); | 487 | catalogXml.append("<Parental>" + channel.getParental() + "</Parental>\r\n"); |
| 450 | if (channel.getParental() == 0) { | 488 | if (channel.getParental() == 0) { |
| 451 | // 通道项 | 489 | // 通道项 |
| 452 | - catalogXml.append("<Manufacturer>" + channel.getManufacture() + "</Manufacturer>\r\n"); | ||
| 453 | - catalogXml.append("<Secrecy>" + channel.getSecrecy() + "</Secrecy>\r\n"); | ||
| 454 | - catalogXml.append("<RegisterWay>" + channel.getRegisterWay() + "</RegisterWay>\r\n"); | ||
| 455 | - catalogXml.append("<Status>" + (channel.getStatus() == 0 ? "OFF" : "ON") + "</Status>\r\n"); | 490 | + catalogXml.append("<Manufacturer>" + channel.getManufacture() + "</Manufacturer>\r\n") |
| 491 | + .append("<Secrecy>" + channel.getSecrecy() + "</Secrecy>\r\n") | ||
| 492 | + .append("<RegisterWay>" + channel.getRegisterWay() + "</RegisterWay>\r\n") | ||
| 493 | + .append("<Status>" + (channel.getStatus() == 0 ? "OFF" : "ON") + "</Status>\r\n"); | ||
| 456 | 494 | ||
| 457 | if (channel.getChannelType() != 2) { // 业务分组/虚拟组织/行政区划 不设置以下属性 | 495 | if (channel.getChannelType() != 2) { // 业务分组/虚拟组织/行政区划 不设置以下属性 |
| 458 | - catalogXml.append("<Model>" + channel.getModel() + "</Model>\r\n"); | ||
| 459 | - catalogXml.append("<Owner> " + channel.getOwner()+ "</Owner>\r\n"); | ||
| 460 | - catalogXml.append("<CivilCode>" + channel.getCivilCode() + "</CivilCode>\r\n"); | ||
| 461 | - catalogXml.append("<Address>" + channel.getAddress() + "</Address>\r\n"); | 496 | + catalogXml.append("<Model>" + channel.getModel() + "</Model>\r\n") |
| 497 | + .append("<Owner> " + channel.getOwner()+ "</Owner>\r\n") | ||
| 498 | + .append("<CivilCode>" + channel.getCivilCode() + "</CivilCode>\r\n") | ||
| 499 | + .append("<Address>" + channel.getAddress() + "</Address>\r\n"); | ||
| 462 | } | 500 | } |
| 463 | if (!"presence".equals(subscribeInfo.getEventType())) { | 501 | if (!"presence".equals(subscribeInfo.getEventType())) { |
| 464 | catalogXml.append("<Event>" + type + "</Event>\r\n"); | 502 | catalogXml.append("<Event>" + type + "</Event>\r\n"); |
| @@ -468,8 +506,8 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { | @@ -468,8 +506,8 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { | ||
| 468 | catalogXml.append("</Item>\r\n"); | 506 | catalogXml.append("</Item>\r\n"); |
| 469 | } | 507 | } |
| 470 | } | 508 | } |
| 471 | - catalogXml.append("</DeviceList>\r\n"); | ||
| 472 | - catalogXml.append("</Notify>\r\n"); | 509 | + catalogXml.append("</DeviceList>\r\n") |
| 510 | + .append("</Notify>\r\n"); | ||
| 473 | return catalogXml.toString(); | 511 | return catalogXml.toString(); |
| 474 | } | 512 | } |
| 475 | 513 | ||
| @@ -515,26 +553,26 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { | @@ -515,26 +553,26 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { | ||
| 515 | 553 | ||
| 516 | String characterSet = parentPlatform.getCharacterSet(); | 554 | String characterSet = parentPlatform.getCharacterSet(); |
| 517 | StringBuffer catalogXml = new StringBuffer(600); | 555 | StringBuffer catalogXml = new StringBuffer(600); |
| 518 | - catalogXml.append("<?xml version=\"1.0\" encoding=\"" + characterSet + "\"?>\r\n"); | ||
| 519 | - catalogXml.append("<Notify>\r\n"); | ||
| 520 | - catalogXml.append("<CmdType>Catalog</CmdType>\r\n"); | ||
| 521 | - catalogXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n"); | ||
| 522 | - catalogXml.append("<DeviceID>" + parentPlatform.getDeviceGBId() + "</DeviceID>\r\n"); | ||
| 523 | - catalogXml.append("<SumNum>1</SumNum>\r\n"); | ||
| 524 | - catalogXml.append("<DeviceList Num=\" " + channels.size() + " \">\r\n"); | 556 | + catalogXml.append("<?xml version=\"1.0\" encoding=\"" + characterSet + "\"?>\r\n") |
| 557 | + .append("<Notify>\r\n") | ||
| 558 | + .append("<CmdType>Catalog</CmdType>\r\n") | ||
| 559 | + .append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n") | ||
| 560 | + .append("<DeviceID>" + parentPlatform.getDeviceGBId() + "</DeviceID>\r\n") | ||
| 561 | + .append("<SumNum>1</SumNum>\r\n") | ||
| 562 | + .append("<DeviceList Num=\" " + channels.size() + " \">\r\n"); | ||
| 525 | if (channels.size() > 0) { | 563 | if (channels.size() > 0) { |
| 526 | for (DeviceChannel channel : channels) { | 564 | for (DeviceChannel channel : channels) { |
| 527 | if (parentPlatform.getServerGBId().equals(channel.getParentId())) { | 565 | if (parentPlatform.getServerGBId().equals(channel.getParentId())) { |
| 528 | channel.setParentId(parentPlatform.getDeviceGBId()); | 566 | channel.setParentId(parentPlatform.getDeviceGBId()); |
| 529 | } | 567 | } |
| 530 | - catalogXml.append("<Item>\r\n"); | ||
| 531 | - catalogXml.append("<DeviceID>" + channel.getChannelId() + "</DeviceID>\r\n"); | ||
| 532 | - catalogXml.append("<Event>" + type + "</Event>\r\n"); | ||
| 533 | - catalogXml.append("</Item>\r\n"); | 568 | + catalogXml.append("<Item>\r\n") |
| 569 | + .append("<DeviceID>" + channel.getChannelId() + "</DeviceID>\r\n") | ||
| 570 | + .append("<Event>" + type + "</Event>\r\n") | ||
| 571 | + .append("</Item>\r\n"); | ||
| 534 | } | 572 | } |
| 535 | } | 573 | } |
| 536 | - catalogXml.append("</DeviceList>\r\n"); | ||
| 537 | - catalogXml.append("</Notify>\r\n"); | 574 | + catalogXml.append("</DeviceList>\r\n") |
| 575 | + .append("</Notify>\r\n"); | ||
| 538 | return catalogXml.toString(); | 576 | return catalogXml.toString(); |
| 539 | } | 577 | } |
| 540 | @Override | 578 | @Override |
| @@ -544,12 +582,12 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { | @@ -544,12 +582,12 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { | ||
| 544 | } | 582 | } |
| 545 | String characterSet = parentPlatform.getCharacterSet(); | 583 | String characterSet = parentPlatform.getCharacterSet(); |
| 546 | StringBuffer recordXml = new StringBuffer(600); | 584 | StringBuffer recordXml = new StringBuffer(600); |
| 547 | - recordXml.append("<?xml version=\"1.0\" encoding=\"" + characterSet + "\"?>\r\n"); | ||
| 548 | - recordXml.append("<Response>\r\n"); | ||
| 549 | - recordXml.append("<CmdType>RecordInfo</CmdType>\r\n"); | ||
| 550 | - recordXml.append("<SN>" +recordInfo.getSn() + "</SN>\r\n"); | ||
| 551 | - recordXml.append("<DeviceID>" + recordInfo.getDeviceId() + "</DeviceID>\r\n"); | ||
| 552 | - recordXml.append("<SumNum>" + recordInfo.getSumNum() + "</SumNum>\r\n"); | 585 | + recordXml.append("<?xml version=\"1.0\" encoding=\"" + characterSet + "\"?>\r\n") |
| 586 | + .append("<Response>\r\n") | ||
| 587 | + .append("<CmdType>RecordInfo</CmdType>\r\n") | ||
| 588 | + .append("<SN>" +recordInfo.getSn() + "</SN>\r\n") | ||
| 589 | + .append("<DeviceID>" + recordInfo.getDeviceId() + "</DeviceID>\r\n") | ||
| 590 | + .append("<SumNum>" + recordInfo.getSumNum() + "</SumNum>\r\n"); | ||
| 553 | if (recordInfo.getRecordList() == null ) { | 591 | if (recordInfo.getRecordList() == null ) { |
| 554 | recordXml.append("<RecordList Num=\"0\">\r\n"); | 592 | recordXml.append("<RecordList Num=\"0\">\r\n"); |
| 555 | }else { | 593 | }else { |
| @@ -558,12 +596,12 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { | @@ -558,12 +596,12 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { | ||
| 558 | for (RecordItem recordItem : recordInfo.getRecordList()) { | 596 | for (RecordItem recordItem : recordInfo.getRecordList()) { |
| 559 | recordXml.append("<Item>\r\n"); | 597 | recordXml.append("<Item>\r\n"); |
| 560 | if (deviceChannel != null) { | 598 | if (deviceChannel != null) { |
| 561 | - recordXml.append("<DeviceID>" + recordItem.getDeviceId() + "</DeviceID>\r\n"); | ||
| 562 | - recordXml.append("<Name>" + recordItem.getName() + "</Name>\r\n"); | ||
| 563 | - recordXml.append("<StartTime>" + DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(recordItem.getStartTime()) + "</StartTime>\r\n"); | ||
| 564 | - recordXml.append("<EndTime>" + DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(recordItem.getEndTime()) + "</EndTime>\r\n"); | ||
| 565 | - recordXml.append("<Secrecy>" + recordItem.getSecrecy() + "</Secrecy>\r\n"); | ||
| 566 | - recordXml.append("<Type>" + recordItem.getType() + "</Type>\r\n"); | 599 | + recordXml.append("<DeviceID>" + recordItem.getDeviceId() + "</DeviceID>\r\n") |
| 600 | + .append("<Name>" + recordItem.getName() + "</Name>\r\n") | ||
| 601 | + .append("<StartTime>" + DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(recordItem.getStartTime()) + "</StartTime>\r\n") | ||
| 602 | + .append("<EndTime>" + DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(recordItem.getEndTime()) + "</EndTime>\r\n") | ||
| 603 | + .append("<Secrecy>" + recordItem.getSecrecy() + "</Secrecy>\r\n") | ||
| 604 | + .append("<Type>" + recordItem.getType() + "</Type>\r\n"); | ||
| 567 | if (!ObjectUtils.isEmpty(recordItem.getFileSize())) { | 605 | if (!ObjectUtils.isEmpty(recordItem.getFileSize())) { |
| 568 | recordXml.append("<FileSize>" + recordItem.getFileSize() + "</FileSize>\r\n"); | 606 | recordXml.append("<FileSize>" + recordItem.getFileSize() + "</FileSize>\r\n"); |
| 569 | } | 607 | } |
| @@ -576,8 +614,8 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { | @@ -576,8 +614,8 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { | ||
| 576 | } | 614 | } |
| 577 | } | 615 | } |
| 578 | 616 | ||
| 579 | - recordXml.append("</RecordList>\r\n"); | ||
| 580 | - recordXml.append("</Response>\r\n"); | 617 | + recordXml.append("</RecordList>\r\n") |
| 618 | + .append("</Response>\r\n"); | ||
| 581 | 619 | ||
| 582 | // callid | 620 | // callid |
| 583 | CallIdHeader callIdHeader = sipSender.getNewCallIdHeader(parentPlatform.getDeviceIp(),parentPlatform.getTransport()); | 621 | CallIdHeader callIdHeader = sipSender.getNewCallIdHeader(parentPlatform.getDeviceIp(),parentPlatform.getTransport()); |
| @@ -596,13 +634,13 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { | @@ -596,13 +634,13 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { | ||
| 596 | 634 | ||
| 597 | String characterSet = parentPlatform.getCharacterSet(); | 635 | String characterSet = parentPlatform.getCharacterSet(); |
| 598 | StringBuffer mediaStatusXml = new StringBuffer(200); | 636 | StringBuffer mediaStatusXml = new StringBuffer(200); |
| 599 | - mediaStatusXml.append("<?xml version=\"1.0\" encoding=\"" + characterSet + "\"?>\r\n"); | ||
| 600 | - mediaStatusXml.append("<Notify>\r\n"); | ||
| 601 | - mediaStatusXml.append("<CmdType>MediaStatus</CmdType>\r\n"); | ||
| 602 | - mediaStatusXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n"); | ||
| 603 | - mediaStatusXml.append("<DeviceID>" + sendRtpItem.getChannelId() + "</DeviceID>\r\n"); | ||
| 604 | - mediaStatusXml.append("<NotifyType>121</NotifyType>\r\n"); | ||
| 605 | - mediaStatusXml.append("</Notify>\r\n"); | 637 | + mediaStatusXml.append("<?xml version=\"1.0\" encoding=\"" + characterSet + "\"?>\r\n") |
| 638 | + .append("<Notify>\r\n") | ||
| 639 | + .append("<CmdType>MediaStatus</CmdType>\r\n") | ||
| 640 | + .append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n") | ||
| 641 | + .append("<DeviceID>" + sendRtpItem.getChannelId() + "</DeviceID>\r\n") | ||
| 642 | + .append("<NotifyType>121</NotifyType>\r\n") | ||
| 643 | + .append("</Notify>\r\n"); | ||
| 606 | 644 | ||
| 607 | SIPRequest messageRequest = (SIPRequest)headerProviderPlatformProvider.createMessageRequest(parentPlatform, mediaStatusXml.toString(), | 645 | SIPRequest messageRequest = (SIPRequest)headerProviderPlatformProvider.createMessageRequest(parentPlatform, mediaStatusXml.toString(), |
| 608 | sendRtpItem); | 646 | sendRtpItem); |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/SIPRequestProcessorParent.java
| @@ -3,7 +3,6 @@ package com.genersoft.iot.vmp.gb28181.transmit.event.request; | @@ -3,7 +3,6 @@ package com.genersoft.iot.vmp.gb28181.transmit.event.request; | ||
| 3 | import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; | 3 | import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; |
| 4 | import com.genersoft.iot.vmp.gb28181.transmit.SIPSender; | 4 | import com.genersoft.iot.vmp.gb28181.transmit.SIPSender; |
| 5 | import com.genersoft.iot.vmp.gb28181.utils.SipUtils; | 5 | import com.genersoft.iot.vmp.gb28181.utils.SipUtils; |
| 6 | -import gov.nist.javax.sip.SipProviderImpl; | ||
| 7 | import gov.nist.javax.sip.message.SIPRequest; | 6 | import gov.nist.javax.sip.message.SIPRequest; |
| 8 | import gov.nist.javax.sip.message.SIPResponse; | 7 | import gov.nist.javax.sip.message.SIPResponse; |
| 9 | import org.apache.commons.lang3.ArrayUtils; | 8 | import org.apache.commons.lang3.ArrayUtils; |
| @@ -14,19 +13,17 @@ import org.dom4j.io.SAXReader; | @@ -14,19 +13,17 @@ import org.dom4j.io.SAXReader; | ||
| 14 | import org.slf4j.Logger; | 13 | import org.slf4j.Logger; |
| 15 | import org.slf4j.LoggerFactory; | 14 | import org.slf4j.LoggerFactory; |
| 16 | import org.springframework.beans.factory.annotation.Autowired; | 15 | import org.springframework.beans.factory.annotation.Autowired; |
| 17 | -import org.springframework.beans.factory.annotation.Qualifier; | ||
| 18 | 16 | ||
| 19 | import javax.sip.*; | 17 | import javax.sip.*; |
| 20 | import javax.sip.address.Address; | 18 | import javax.sip.address.Address; |
| 21 | -import javax.sip.address.AddressFactory; | ||
| 22 | import javax.sip.address.SipURI; | 19 | import javax.sip.address.SipURI; |
| 23 | -import javax.sip.header.*; | 20 | +import javax.sip.header.ContentTypeHeader; |
| 21 | +import javax.sip.header.ExpiresHeader; | ||
| 22 | +import javax.sip.header.HeaderFactory; | ||
| 24 | import javax.sip.message.MessageFactory; | 23 | import javax.sip.message.MessageFactory; |
| 25 | import javax.sip.message.Request; | 24 | import javax.sip.message.Request; |
| 26 | import javax.sip.message.Response; | 25 | import javax.sip.message.Response; |
| 27 | import java.io.ByteArrayInputStream; | 26 | import java.io.ByteArrayInputStream; |
| 28 | -import java.nio.ByteBuffer; | ||
| 29 | -import java.nio.charset.StandardCharsets; | ||
| 30 | import java.text.ParseException; | 27 | import java.text.ParseException; |
| 31 | import java.util.ArrayList; | 28 | import java.util.ArrayList; |
| 32 | import java.util.Arrays; | 29 | import java.util.Arrays; |
| @@ -44,15 +41,6 @@ public abstract class SIPRequestProcessorParent { | @@ -44,15 +41,6 @@ public abstract class SIPRequestProcessorParent { | ||
| 44 | @Autowired | 41 | @Autowired |
| 45 | private SIPSender sipSender; | 42 | private SIPSender sipSender; |
| 46 | 43 | ||
| 47 | - public AddressFactory getAddressFactory() { | ||
| 48 | - try { | ||
| 49 | - return SipFactory.getInstance().createAddressFactory(); | ||
| 50 | - } catch (PeerUnavailableException e) { | ||
| 51 | - e.printStackTrace(); | ||
| 52 | - } | ||
| 53 | - return null; | ||
| 54 | - } | ||
| 55 | - | ||
| 56 | public HeaderFactory getHeaderFactory() { | 44 | public HeaderFactory getHeaderFactory() { |
| 57 | try { | 45 | try { |
| 58 | return SipFactory.getInstance().createHeaderFactory(); | 46 | return SipFactory.getInstance().createHeaderFactory(); |
| @@ -93,53 +81,6 @@ public abstract class SIPRequestProcessorParent { | @@ -93,53 +81,6 @@ public abstract class SIPRequestProcessorParent { | ||
| 93 | return responseAck(sipRequest, statusCode, msg, null); | 81 | return responseAck(sipRequest, statusCode, msg, null); |
| 94 | } | 82 | } |
| 95 | 83 | ||
| 96 | -// public SIPResponse responseAck(ServerTransaction serverTransaction, int statusCode, String msg, ResponseAckExtraParam responseAckExtraParam) throws SipException, InvalidArgumentException, ParseException { | ||
| 97 | -// if (serverTransaction == null) { | ||
| 98 | -// logger.warn("[回复消息] ServerTransaction 为null"); | ||
| 99 | -// return null; | ||
| 100 | -// } | ||
| 101 | -// ToHeader toHeader = (ToHeader) serverTransaction.getRequest().getHeader(ToHeader.NAME); | ||
| 102 | -// if (toHeader.getTag() == null) { | ||
| 103 | -// toHeader.setTag(SipUtils.getNewTag()); | ||
| 104 | -// } | ||
| 105 | -// SIPResponse response = (SIPResponse)getMessageFactory().createResponse(statusCode, serverTransaction.getRequest()); | ||
| 106 | -// if (msg != null) { | ||
| 107 | -// response.setReasonPhrase(msg); | ||
| 108 | -// } | ||
| 109 | -// if (responseAckExtraParam != null) { | ||
| 110 | -// if (responseAckExtraParam.sipURI != null && serverTransaction.getRequest().getMethod().equals(Request.INVITE)) { | ||
| 111 | -// logger.debug("responseSdpAck SipURI: {}:{}", responseAckExtraParam.sipURI.getHost(), responseAckExtraParam.sipURI.getPort()); | ||
| 112 | -// Address concatAddress = SipFactory.getInstance().createAddressFactory().createAddress( | ||
| 113 | -// SipFactory.getInstance().createAddressFactory().createSipURI(responseAckExtraParam.sipURI.getUser(), responseAckExtraParam.sipURI.getHost()+":"+responseAckExtraParam.sipURI.getPort() | ||
| 114 | -// )); | ||
| 115 | -// response.addHeader(SipFactory.getInstance().createHeaderFactory().createContactHeader(concatAddress)); | ||
| 116 | -// } | ||
| 117 | -// if (responseAckExtraParam.contentTypeHeader != null) { | ||
| 118 | -// response.setContent(responseAckExtraParam.content, responseAckExtraParam.contentTypeHeader); | ||
| 119 | -// } | ||
| 120 | -// | ||
| 121 | -// if (serverTransaction.getRequest().getMethod().equals(Request.SUBSCRIBE)) { | ||
| 122 | -// if (responseAckExtraParam.expires == -1) { | ||
| 123 | -// logger.error("[参数不全] 2xx的SUBSCRIBE回复,必须设置Expires header"); | ||
| 124 | -// }else { | ||
| 125 | -// ExpiresHeader expiresHeader = SipFactory.getInstance().createHeaderFactory().createExpiresHeader(responseAckExtraParam.expires); | ||
| 126 | -// response.addHeader(expiresHeader); | ||
| 127 | -// } | ||
| 128 | -// } | ||
| 129 | -// }else { | ||
| 130 | -// if (serverTransaction.getRequest().getMethod().equals(Request.SUBSCRIBE)) { | ||
| 131 | -// logger.error("[参数不全] 2xx的SUBSCRIBE回复,必须设置Expires header"); | ||
| 132 | -// } | ||
| 133 | -// } | ||
| 134 | -// serverTransaction.sendResponse(response); | ||
| 135 | -// if (statusCode >= 200 && !"NOTIFY".equalsIgnoreCase(serverTransaction.getRequest().getMethod())) { | ||
| 136 | -// if (serverTransaction.getDialog() != null) { | ||
| 137 | -// serverTransaction.getDialog().delete(); | ||
| 138 | -// } | ||
| 139 | -// } | ||
| 140 | -// return response; | ||
| 141 | -// } | ||
| 142 | - | ||
| 143 | public SIPResponse responseAck(SIPRequest sipRequest, int statusCode, String msg, ResponseAckExtraParam responseAckExtraParam) throws SipException, InvalidArgumentException, ParseException { | 84 | public SIPResponse responseAck(SIPRequest sipRequest, int statusCode, String msg, ResponseAckExtraParam responseAckExtraParam) throws SipException, InvalidArgumentException, ParseException { |
| 144 | if (sipRequest.getToHeader().getTag() == null) { | 85 | if (sipRequest.getToHeader().getTag() == null) { |
| 145 | sipRequest.getToHeader().setTag(SipUtils.getNewTag()); | 86 | sipRequest.getToHeader().setTag(SipUtils.getNewTag()); |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java
| @@ -228,7 +228,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements | @@ -228,7 +228,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements | ||
| 228 | } | 228 | } |
| 229 | return; | 229 | return; |
| 230 | } else { | 230 | } else { |
| 231 | - logger.info("通道不存在,返回404"); | 231 | + logger.info("通道不存在,返回404: {}", channelId); |
| 232 | try { | 232 | try { |
| 233 | // 通道不存在,发404,资源不存在 | 233 | // 通道不存在,发404,资源不存在 |
| 234 | responseAck(request, Response.NOT_FOUND); | 234 | responseAck(request, Response.NOT_FOUND); |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/CatalogQueryMessageHandler.java
| 1 | package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.query.cmd; | 1 | package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.query.cmd; |
| 2 | 2 | ||
| 3 | import com.genersoft.iot.vmp.conf.SipConfig; | 3 | import com.genersoft.iot.vmp.conf.SipConfig; |
| 4 | -import com.genersoft.iot.vmp.gb28181.bean.*; | 4 | +import com.genersoft.iot.vmp.gb28181.bean.Device; |
| 5 | +import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; | ||
| 6 | +import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; | ||
| 5 | import com.genersoft.iot.vmp.gb28181.event.EventPublisher; | 7 | import com.genersoft.iot.vmp.gb28181.event.EventPublisher; |
| 6 | -import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; | ||
| 7 | import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform; | 8 | import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform; |
| 8 | import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent; | 9 | import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent; |
| 9 | import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler; | 10 | import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler; |
| @@ -63,7 +64,6 @@ public class CatalogQueryMessageHandler extends SIPRequestProcessorParent implem | @@ -63,7 +64,6 @@ public class CatalogQueryMessageHandler extends SIPRequestProcessorParent implem | ||
| 63 | @Override | 64 | @Override |
| 64 | public void handForPlatform(RequestEvent evt, ParentPlatform parentPlatform, Element rootElement) { | 65 | public void handForPlatform(RequestEvent evt, ParentPlatform parentPlatform, Element rootElement) { |
| 65 | 66 | ||
| 66 | - String key = DeferredResultHolder.CALLBACK_CMD_CATALOG + parentPlatform.getServerGBId(); | ||
| 67 | FromHeader fromHeader = (FromHeader) evt.getRequest().getHeader(FromHeader.NAME); | 67 | FromHeader fromHeader = (FromHeader) evt.getRequest().getHeader(FromHeader.NAME); |
| 68 | try { | 68 | try { |
| 69 | // 回复200 OK | 69 | // 回复200 OK |
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java
| @@ -8,6 +8,8 @@ import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException; | @@ -8,6 +8,8 @@ import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException; | ||
| 8 | import com.genersoft.iot.vmp.gb28181.bean.*; | 8 | import com.genersoft.iot.vmp.gb28181.bean.*; |
| 9 | import com.genersoft.iot.vmp.gb28181.event.EventPublisher; | 9 | import com.genersoft.iot.vmp.gb28181.event.EventPublisher; |
| 10 | import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager; | 10 | import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager; |
| 11 | +import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; | ||
| 12 | +import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage; | ||
| 11 | import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; | 13 | import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; |
| 12 | import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform; | 14 | import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform; |
| 13 | import com.genersoft.iot.vmp.media.zlm.dto.HookType; | 15 | import com.genersoft.iot.vmp.media.zlm.dto.HookType; |
| @@ -18,7 +20,10 @@ import com.genersoft.iot.vmp.media.zlm.dto.hook.*; | @@ -18,7 +20,10 @@ import com.genersoft.iot.vmp.media.zlm.dto.hook.*; | ||
| 18 | import com.genersoft.iot.vmp.service.*; | 20 | import com.genersoft.iot.vmp.service.*; |
| 19 | import com.genersoft.iot.vmp.storager.IRedisCatchStorage; | 21 | import com.genersoft.iot.vmp.storager.IRedisCatchStorage; |
| 20 | import com.genersoft.iot.vmp.storager.IVideoManagerStorage; | 22 | import com.genersoft.iot.vmp.storager.IVideoManagerStorage; |
| 23 | +import com.genersoft.iot.vmp.vmanager.bean.DeferredResultEx; | ||
| 24 | +import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; | ||
| 21 | import com.genersoft.iot.vmp.vmanager.bean.StreamContent; | 25 | import com.genersoft.iot.vmp.vmanager.bean.StreamContent; |
| 26 | +import com.genersoft.iot.vmp.vmanager.bean.WVPResult; | ||
| 22 | import org.slf4j.Logger; | 27 | import org.slf4j.Logger; |
| 23 | import org.slf4j.LoggerFactory; | 28 | import org.slf4j.LoggerFactory; |
| 24 | import org.springframework.beans.factory.annotation.Autowired; | 29 | import org.springframework.beans.factory.annotation.Autowired; |
| @@ -26,6 +31,7 @@ import org.springframework.beans.factory.annotation.Qualifier; | @@ -26,6 +31,7 @@ import org.springframework.beans.factory.annotation.Qualifier; | ||
| 26 | import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; | 31 | import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; |
| 27 | import org.springframework.util.ObjectUtils; | 32 | import org.springframework.util.ObjectUtils; |
| 28 | import org.springframework.web.bind.annotation.*; | 33 | import org.springframework.web.bind.annotation.*; |
| 34 | +import org.springframework.web.context.request.async.DeferredResult; | ||
| 29 | 35 | ||
| 30 | import javax.servlet.http.HttpServletRequest; | 36 | import javax.servlet.http.HttpServletRequest; |
| 31 | import javax.sip.InvalidArgumentException; | 37 | import javax.sip.InvalidArgumentException; |
| @@ -34,638 +40,644 @@ import java.text.ParseException; | @@ -34,638 +40,644 @@ import java.text.ParseException; | ||
| 34 | import java.util.HashMap; | 40 | import java.util.HashMap; |
| 35 | import java.util.List; | 41 | import java.util.List; |
| 36 | import java.util.Map; | 42 | import java.util.Map; |
| 43 | +import java.util.UUID; | ||
| 37 | 44 | ||
| 38 | -/** | 45 | +/** |
| 39 | * @description:针对 ZLMediaServer的hook事件监听 | 46 | * @description:针对 ZLMediaServer的hook事件监听 |
| 40 | * @author: swwheihei | 47 | * @author: swwheihei |
| 41 | - * @date: 2020年5月8日 上午10:46:48 | 48 | + * @date: 2020年5月8日 上午10:46:48 |
| 42 | */ | 49 | */ |
| 43 | @RestController | 50 | @RestController |
| 44 | @RequestMapping("/index/hook") | 51 | @RequestMapping("/index/hook") |
| 45 | public class ZLMHttpHookListener { | 52 | public class ZLMHttpHookListener { |
| 46 | 53 | ||
| 47 | - private final static Logger logger = LoggerFactory.getLogger(ZLMHttpHookListener.class); | 54 | + private final static Logger logger = LoggerFactory.getLogger(ZLMHttpHookListener.class); |
| 48 | 55 | ||
| 49 | - @Autowired | ||
| 50 | - private SIPCommander cmder; | ||
| 51 | - | ||
| 52 | - @Autowired | ||
| 53 | - private SIPCommanderFroPlatform commanderFroPlatform; | ||
| 54 | - | ||
| 55 | - @Autowired | ||
| 56 | - private IPlayService playService; | ||
| 57 | - | ||
| 58 | - @Autowired | ||
| 59 | - private IVideoManagerStorage storager; | ||
| 60 | - | ||
| 61 | - @Autowired | ||
| 62 | - private IRedisCatchStorage redisCatchStorage; | ||
| 63 | - | ||
| 64 | - @Autowired | ||
| 65 | - private IDeviceService deviceService; | ||
| 66 | - | ||
| 67 | - @Autowired | ||
| 68 | - private IMediaServerService mediaServerService; | ||
| 69 | - | ||
| 70 | - @Autowired | ||
| 71 | - private IStreamProxyService streamProxyService; | ||
| 72 | - | ||
| 73 | - @Autowired | ||
| 74 | - private IStreamPushService streamPushService; | ||
| 75 | - | ||
| 76 | - @Autowired | ||
| 77 | - private IMediaService mediaService; | ||
| 78 | - | ||
| 79 | - @Autowired | ||
| 80 | - private EventPublisher eventPublisher; | ||
| 81 | - | ||
| 82 | - @Autowired | ||
| 83 | - private ZLMMediaListManager zlmMediaListManager; | ||
| 84 | - | ||
| 85 | - @Autowired | ||
| 86 | - private ZlmHttpHookSubscribe subscribe; | ||
| 87 | - | ||
| 88 | - @Autowired | ||
| 89 | - private UserSetting userSetting; | ||
| 90 | - | ||
| 91 | - @Autowired | ||
| 92 | - private IUserService userService; | ||
| 93 | - | ||
| 94 | - @Autowired | ||
| 95 | - private VideoStreamSessionManager sessionManager; | ||
| 96 | - | ||
| 97 | - @Autowired | ||
| 98 | - private AssistRESTfulUtils assistRESTfulUtils; | ||
| 99 | - | ||
| 100 | - @Qualifier("taskExecutor") | ||
| 101 | - @Autowired | ||
| 102 | - private ThreadPoolTaskExecutor taskExecutor; | ||
| 103 | - | ||
| 104 | - /** | ||
| 105 | - * 服务器定时上报时间,上报间隔可配置,默认10s上报一次 | ||
| 106 | - * | ||
| 107 | - */ | ||
| 108 | - @ResponseBody | ||
| 109 | - @PostMapping(value = "/on_server_keepalive", produces = "application/json;charset=UTF-8") | ||
| 110 | - public JSONObject onServerKeepalive(@RequestBody OnServerKeepaliveHookParam param){ | ||
| 111 | - | ||
| 112 | - logger.info("[ZLM HOOK] 收到zlm心跳:" + param.getMediaServerId()); | ||
| 113 | - | ||
| 114 | - taskExecutor.execute(()->{ | ||
| 115 | - List<ZlmHttpHookSubscribe.Event> subscribes = this.subscribe.getSubscribes(HookType.on_server_keepalive); | ||
| 116 | - JSONObject json = (JSONObject) JSON.toJSON(param); | ||
| 117 | - if (subscribes != null && subscribes.size() > 0) { | ||
| 118 | - for (ZlmHttpHookSubscribe.Event subscribe : subscribes) { | ||
| 119 | - subscribe.response(null, json); | ||
| 120 | - } | ||
| 121 | - } | ||
| 122 | - }); | ||
| 123 | - mediaServerService.updateMediaServerKeepalive(param.getMediaServerId(), param.getData()); | ||
| 124 | - | ||
| 125 | - JSONObject ret = new JSONObject(); | ||
| 126 | - ret.put("code", 0); | ||
| 127 | - ret.put("msg", "success"); | ||
| 128 | - | ||
| 129 | - return ret; | ||
| 130 | - } | ||
| 131 | - | ||
| 132 | - /** | ||
| 133 | - * 播放器鉴权事件,rtsp/rtmp/http-flv/ws-flv/hls的播放都将触发此鉴权事件。 | ||
| 134 | - * | ||
| 135 | - */ | ||
| 136 | - @ResponseBody | ||
| 137 | - @PostMapping(value = "/on_play", produces = "application/json;charset=UTF-8") | ||
| 138 | - public JSONObject onPlay(@RequestBody OnPlayHookParam param){ | ||
| 139 | - if (logger.isDebugEnabled()) { | ||
| 140 | - logger.debug("[ZLM HOOK] 播放鉴权:{}->{}" + param.getMediaServerId(), param); | ||
| 141 | - } | ||
| 142 | - String mediaServerId = param.getMediaServerId(); | ||
| 143 | - | ||
| 144 | - taskExecutor.execute(()->{ | ||
| 145 | - JSONObject json = (JSONObject) JSON.toJSON(param); | ||
| 146 | - ZlmHttpHookSubscribe.Event subscribe = this.subscribe.sendNotify(HookType.on_play, json); | ||
| 147 | - if (subscribe != null ) { | ||
| 148 | - MediaServerItem mediaInfo = mediaServerService.getOne(mediaServerId); | ||
| 149 | - if (mediaInfo != null) { | ||
| 150 | - subscribe.response(mediaInfo, json); | ||
| 151 | - } | ||
| 152 | - } | ||
| 153 | - }); | ||
| 154 | - JSONObject ret = new JSONObject(); | ||
| 155 | - if (!"rtp".equals(param.getApp())) { | ||
| 156 | - Map<String, String> paramMap = urlParamToMap(param.getParams()); | ||
| 157 | - StreamAuthorityInfo streamAuthorityInfo = redisCatchStorage.getStreamAuthorityInfo(param.getApp(), param.getStream()); | ||
| 158 | - if (streamAuthorityInfo != null && streamAuthorityInfo.getCallId() != null && !streamAuthorityInfo.getCallId().equals(paramMap.get("callId"))) { | ||
| 159 | - ret.put("code", 401); | ||
| 160 | - ret.put("msg", "Unauthorized"); | ||
| 161 | - return ret; | ||
| 162 | - } | ||
| 163 | - } | ||
| 164 | - | ||
| 165 | - ret.put("code", 0); | ||
| 166 | - ret.put("msg", "success"); | ||
| 167 | - return ret; | ||
| 168 | - } | ||
| 169 | - | ||
| 170 | - /** | ||
| 171 | - * rtsp/rtmp/rtp推流鉴权事件。 | ||
| 172 | - * | ||
| 173 | - */ | ||
| 174 | - @ResponseBody | ||
| 175 | - @PostMapping(value = "/on_publish", produces = "application/json;charset=UTF-8") | ||
| 176 | - public JSONObject onPublish(@RequestBody OnPublishHookParam param) { | ||
| 177 | - | ||
| 178 | - JSONObject json = (JSONObject) JSON.toJSON(param); | ||
| 179 | - | ||
| 180 | - logger.info("[ZLM HOOK]推流鉴权:{}->{}", param.getMediaServerId(), param); | ||
| 181 | - JSONObject ret = new JSONObject(); | ||
| 182 | - String mediaServerId = json.getString("mediaServerId"); | ||
| 183 | - MediaServerItem mediaInfo = mediaServerService.getOne(mediaServerId); | ||
| 184 | - | ||
| 185 | - if (!"rtp".equals(param.getApp())) { | ||
| 186 | - if (userSetting.getPushAuthority()) { | ||
| 187 | - // 推流鉴权 | ||
| 188 | - if (param.getParams() == null) { | ||
| 189 | - logger.info("推流鉴权失败: 缺少不要参数:sign=md5(user表的pushKey)"); | ||
| 190 | - ret.put("code", 401); | ||
| 191 | - ret.put("msg", "Unauthorized"); | ||
| 192 | - return ret; | ||
| 193 | - } | ||
| 194 | - Map<String, String> paramMap = urlParamToMap(param.getParams()); | ||
| 195 | - String sign = paramMap.get("sign"); | ||
| 196 | - if (sign == null) { | ||
| 197 | - logger.info("推流鉴权失败: 缺少不要参数:sign=md5(user表的pushKey)"); | ||
| 198 | - ret.put("code", 401); | ||
| 199 | - ret.put("msg", "Unauthorized"); | ||
| 200 | - return ret; | ||
| 201 | - } | ||
| 202 | - // 推流自定义播放鉴权码 | ||
| 203 | - String callId = paramMap.get("callId"); | ||
| 204 | - // 鉴权配置 | ||
| 205 | - boolean hasAuthority = userService.checkPushAuthority(callId, sign); | ||
| 206 | - if (!hasAuthority) { | ||
| 207 | - logger.info("推流鉴权失败: sign 无权限: callId={}. sign={}", callId, sign); | ||
| 208 | - ret.put("code", 401); | ||
| 209 | - ret.put("msg", "Unauthorized"); | ||
| 210 | - return ret; | ||
| 211 | - } | ||
| 212 | - StreamAuthorityInfo streamAuthorityInfo = StreamAuthorityInfo.getInstanceByHook(param); | ||
| 213 | - streamAuthorityInfo.setCallId(callId); | ||
| 214 | - streamAuthorityInfo.setSign(sign); | ||
| 215 | - // 鉴权通过 | ||
| 216 | - redisCatchStorage.updateStreamAuthorityInfo(param.getApp(), param.getStream(), streamAuthorityInfo); | ||
| 217 | - // 通知assist新的callId | ||
| 218 | - if (mediaInfo != null && mediaInfo.getRecordAssistPort() > 0) { | ||
| 219 | - taskExecutor.execute(()->{ | ||
| 220 | - assistRESTfulUtils.addStreamCallInfo(mediaInfo, param.getApp(), param.getStream(), callId, null); | ||
| 221 | - }); | ||
| 222 | - } | ||
| 223 | - } | ||
| 224 | - }else { | ||
| 225 | - zlmMediaListManager.sendStreamEvent(param.getApp(),param.getStream(), param.getMediaServerId()); | ||
| 226 | - } | ||
| 227 | - | ||
| 228 | - ret.put("code", 0); | ||
| 229 | - ret.put("msg", "success"); | ||
| 230 | - | ||
| 231 | - if (!"rtp".equals(param.getApp())) { | ||
| 232 | - ret.put("enable_audio", true); | ||
| 233 | - } | ||
| 234 | - | ||
| 235 | - taskExecutor.execute(()->{ | ||
| 236 | - ZlmHttpHookSubscribe.Event subscribe = this.subscribe.sendNotify(HookType.on_publish, json); | ||
| 237 | - if (subscribe != null) { | ||
| 238 | - if (mediaInfo != null) { | ||
| 239 | - subscribe.response(mediaInfo, json); | ||
| 240 | - }else { | ||
| 241 | - ret.put("code", 1); | ||
| 242 | - ret.put("msg", "zlm not register"); | ||
| 243 | - } | ||
| 244 | - } | ||
| 245 | - }); | ||
| 246 | - | ||
| 247 | - if ("rtp".equals(param.getApp())) { | ||
| 248 | - ret.put("enable_mp4", userSetting.getRecordSip()); | ||
| 249 | - }else { | ||
| 250 | - ret.put("enable_mp4", userSetting.isRecordPushLive()); | ||
| 251 | - } | ||
| 252 | - List<SsrcTransaction> ssrcTransactionForAll = sessionManager.getSsrcTransactionForAll(null, null, null, param.getStream()); | ||
| 253 | - if (ssrcTransactionForAll != null && ssrcTransactionForAll.size() == 1) { | ||
| 254 | - String deviceId = ssrcTransactionForAll.get(0).getDeviceId(); | ||
| 255 | - String channelId = ssrcTransactionForAll.get(0).getChannelId(); | ||
| 256 | - DeviceChannel deviceChannel = storager.queryChannel(deviceId, channelId); | ||
| 257 | - if (deviceChannel != null) { | ||
| 258 | - ret.put("enable_audio", deviceChannel.isHasAudio()); | ||
| 259 | - } | ||
| 260 | - // 如果是录像下载就设置视频间隔十秒 | ||
| 261 | - if (ssrcTransactionForAll.get(0).getType() == VideoStreamSessionManager.SessionType.download) { | ||
| 262 | - ret.put("mp4_max_second", 10); | ||
| 263 | - ret.put("enable_mp4", true); | ||
| 264 | - ret.put("enable_audio", true); | ||
| 265 | - } | ||
| 266 | - } | ||
| 267 | - return ret; | ||
| 268 | - } | ||
| 269 | - | ||
| 270 | - /** | ||
| 271 | - * rtsp/rtmp流注册或注销时触发此事件;此事件对回复不敏感。 | ||
| 272 | - * | ||
| 273 | - */ | ||
| 274 | - @ResponseBody | ||
| 275 | - @PostMapping(value = "/on_stream_changed", produces = "application/json;charset=UTF-8") | ||
| 276 | - public JSONObject onStreamChanged(@RequestBody OnStreamChangedHookParam param){ | ||
| 277 | - | ||
| 278 | - if (param.isRegist()) { | ||
| 279 | - logger.info("[ZLM HOOK] 流注册, {}->{}->{}/{}", param.getMediaServerId(), param.getSchema(), param.getApp(), param.getStream()); | ||
| 280 | - }else { | ||
| 281 | - logger.info("[ZLM HOOK] 流注销, {}->{}->{}/{}", param.getMediaServerId(), param.getSchema(), param.getApp(), param.getStream()); | ||
| 282 | - } | ||
| 283 | - | ||
| 284 | - | ||
| 285 | - JSONObject json = (JSONObject) JSON.toJSON(param); | ||
| 286 | - taskExecutor.execute(()->{ | ||
| 287 | - ZlmHttpHookSubscribe.Event subscribe = this.subscribe.sendNotify(HookType.on_stream_changed, json); | ||
| 288 | - if (subscribe != null ) { | ||
| 289 | - MediaServerItem mediaInfo = mediaServerService.getOne(param.getMediaServerId()); | ||
| 290 | - if (mediaInfo != null) { | ||
| 291 | - subscribe.response(mediaInfo, json); | ||
| 292 | - } | ||
| 293 | - } | ||
| 294 | - // 流消失移除redis play | ||
| 295 | - List<OnStreamChangedHookParam.MediaTrack> tracks = param.getTracks(); | ||
| 296 | - if (param.isRegist()) { | ||
| 297 | - if (param.getOriginType() == OriginType.RTMP_PUSH.ordinal() | ||
| 298 | - || param.getOriginType() == OriginType.RTSP_PUSH.ordinal() | ||
| 299 | - || param.getOriginType() == OriginType.RTC_PUSH.ordinal()) { | ||
| 300 | - | ||
| 301 | - StreamAuthorityInfo streamAuthorityInfo = redisCatchStorage.getStreamAuthorityInfo(param.getApp(), param.getStream()); | ||
| 302 | - if (streamAuthorityInfo == null) { | ||
| 303 | - streamAuthorityInfo = StreamAuthorityInfo.getInstanceByHook(param); | ||
| 304 | - }else { | ||
| 305 | - streamAuthorityInfo.setOriginType(param.getOriginType()); | ||
| 306 | - streamAuthorityInfo.setOriginTypeStr(param.getOriginTypeStr()); | ||
| 307 | - } | ||
| 308 | - redisCatchStorage.updateStreamAuthorityInfo(param.getApp(), param.getStream(), streamAuthorityInfo); | ||
| 309 | - } | ||
| 310 | - }else { | ||
| 311 | - redisCatchStorage.removeStreamAuthorityInfo(param.getApp(), param.getStream()); | ||
| 312 | - } | ||
| 313 | - | ||
| 314 | - if ("rtsp".equals(param.getSchema())){ | ||
| 315 | - if (param.isRegist()) { | ||
| 316 | - mediaServerService.addCount(param.getMediaServerId()); | ||
| 317 | - }else { | ||
| 318 | - mediaServerService.removeCount(param.getMediaServerId()); | ||
| 319 | - } | ||
| 320 | - if (param.getOriginType() == OriginType.PULL.ordinal() | ||
| 321 | - || param.getOriginType() == OriginType.FFMPEG_PULL.ordinal()) { | ||
| 322 | - // 设置拉流代理上线/离线 | ||
| 323 | - streamProxyService.updateStatus(param.isRegist(), param.getApp(), param.getStream()); | ||
| 324 | - } | ||
| 325 | - if ("rtp".equals(param.getApp()) && !param.isRegist() ) { | ||
| 326 | - StreamInfo streamInfo = redisCatchStorage.queryPlayByStreamId(param.getStream()); | ||
| 327 | - if (streamInfo!=null){ | ||
| 328 | - redisCatchStorage.stopPlay(streamInfo); | ||
| 329 | - storager.stopPlay(streamInfo.getDeviceID(), streamInfo.getChannelId()); | ||
| 330 | - }else{ | ||
| 331 | - streamInfo = redisCatchStorage.queryPlayback(null, null, param.getStream(), null); | ||
| 332 | - if (streamInfo != null) { | ||
| 333 | - redisCatchStorage.stopPlayback(streamInfo.getDeviceID(), streamInfo.getChannelId(), | ||
| 334 | - streamInfo.getStream(), null); | ||
| 335 | - } | ||
| 336 | - } | ||
| 337 | - }else { | ||
| 338 | - if (!"rtp".equals(param.getApp())){ | ||
| 339 | - String type = OriginType.values()[param.getOriginType()].getType(); | ||
| 340 | - MediaServerItem mediaServerItem = mediaServerService.getOne(param.getMediaServerId()); | ||
| 341 | - | ||
| 342 | - if (mediaServerItem != null){ | ||
| 343 | - if (param.isRegist()) { | ||
| 344 | - StreamAuthorityInfo streamAuthorityInfo = redisCatchStorage.getStreamAuthorityInfo(param.getApp(), param.getStream()); | ||
| 345 | - String callId = null; | ||
| 346 | - if (streamAuthorityInfo != null) { | ||
| 347 | - callId = streamAuthorityInfo.getCallId(); | ||
| 348 | - } | ||
| 349 | - StreamInfo streamInfoByAppAndStream = mediaService.getStreamInfoByAppAndStream(mediaServerItem, | ||
| 350 | - param.getApp(), param.getStream(), tracks, callId); | ||
| 351 | - param.setStreamInfo(new StreamContent(streamInfoByAppAndStream)); | ||
| 352 | - redisCatchStorage.addStream(mediaServerItem, type, param.getApp(), param.getStream(), param); | ||
| 353 | - if (param.getOriginType() == OriginType.RTSP_PUSH.ordinal() | ||
| 354 | - || param.getOriginType() == OriginType.RTMP_PUSH.ordinal() | ||
| 355 | - || param.getOriginType() == OriginType.RTC_PUSH.ordinal() ) { | ||
| 356 | - param.setSeverId(userSetting.getServerId()); | ||
| 357 | - zlmMediaListManager.addPush(param); | ||
| 358 | - } | ||
| 359 | - }else { | ||
| 360 | - // 兼容流注销时类型从redis记录获取 | ||
| 361 | - OnStreamChangedHookParam onStreamChangedHookParam = redisCatchStorage.getStreamInfo(param.getApp(), param.getStream(), param.getMediaServerId()); | ||
| 362 | - if (onStreamChangedHookParam != null) { | ||
| 363 | - type = OriginType.values()[onStreamChangedHookParam.getOriginType()].getType(); | ||
| 364 | - redisCatchStorage.removeStream(mediaServerItem.getId(), type, param.getApp(), param.getStream()); | ||
| 365 | - } | ||
| 366 | - GbStream gbStream = storager.getGbStream(param.getApp(), param.getStream()); | ||
| 367 | - if (gbStream != null) { | 56 | + @Autowired |
| 57 | + private SIPCommander cmder; | ||
| 58 | + | ||
| 59 | + @Autowired | ||
| 60 | + private SIPCommanderFroPlatform commanderFroPlatform; | ||
| 61 | + | ||
| 62 | + @Autowired | ||
| 63 | + private IPlayService playService; | ||
| 64 | + | ||
| 65 | + @Autowired | ||
| 66 | + private IVideoManagerStorage storager; | ||
| 67 | + | ||
| 68 | + @Autowired | ||
| 69 | + private IRedisCatchStorage redisCatchStorage; | ||
| 70 | + | ||
| 71 | + @Autowired | ||
| 72 | + private IDeviceService deviceService; | ||
| 73 | + | ||
| 74 | + @Autowired | ||
| 75 | + private IMediaServerService mediaServerService; | ||
| 76 | + | ||
| 77 | + @Autowired | ||
| 78 | + private IStreamProxyService streamProxyService; | ||
| 79 | + | ||
| 80 | + @Autowired | ||
| 81 | + private DeferredResultHolder resultHolder; | ||
| 82 | + | ||
| 83 | + @Autowired | ||
| 84 | + private IMediaService mediaService; | ||
| 85 | + | ||
| 86 | + @Autowired | ||
| 87 | + private EventPublisher eventPublisher; | ||
| 88 | + | ||
| 89 | + @Autowired | ||
| 90 | + private ZLMMediaListManager zlmMediaListManager; | ||
| 91 | + | ||
| 92 | + @Autowired | ||
| 93 | + private ZlmHttpHookSubscribe subscribe; | ||
| 94 | + | ||
| 95 | + @Autowired | ||
| 96 | + private UserSetting userSetting; | ||
| 97 | + | ||
| 98 | + @Autowired | ||
| 99 | + private IUserService userService; | ||
| 100 | + | ||
| 101 | + @Autowired | ||
| 102 | + private VideoStreamSessionManager sessionManager; | ||
| 103 | + | ||
| 104 | + @Autowired | ||
| 105 | + private AssistRESTfulUtils assistRESTfulUtils; | ||
| 106 | + | ||
| 107 | + @Qualifier("taskExecutor") | ||
| 108 | + @Autowired | ||
| 109 | + private ThreadPoolTaskExecutor taskExecutor; | ||
| 110 | + | ||
| 111 | + /** | ||
| 112 | + * 服务器定时上报时间,上报间隔可配置,默认10s上报一次 | ||
| 113 | + */ | ||
| 114 | + @ResponseBody | ||
| 115 | + @PostMapping(value = "/on_server_keepalive", produces = "application/json;charset=UTF-8") | ||
| 116 | + public HookResult onServerKeepalive(@RequestBody OnServerKeepaliveHookParam param) { | ||
| 117 | + | ||
| 118 | + logger.info("[ZLM HOOK] 收到zlm心跳:" + param.getMediaServerId()); | ||
| 119 | + | ||
| 120 | + taskExecutor.execute(() -> { | ||
| 121 | + List<ZlmHttpHookSubscribe.Event> subscribes = this.subscribe.getSubscribes(HookType.on_server_keepalive); | ||
| 122 | + JSONObject json = (JSONObject) JSON.toJSON(param); | ||
| 123 | + if (subscribes != null && subscribes.size() > 0) { | ||
| 124 | + for (ZlmHttpHookSubscribe.Event subscribe : subscribes) { | ||
| 125 | + subscribe.response(null, json); | ||
| 126 | + } | ||
| 127 | + } | ||
| 128 | + }); | ||
| 129 | + mediaServerService.updateMediaServerKeepalive(param.getMediaServerId(), param.getData()); | ||
| 130 | + | ||
| 131 | + return HookResult.SUCCESS(); | ||
| 132 | + } | ||
| 133 | + | ||
| 134 | + /** | ||
| 135 | + * 播放器鉴权事件,rtsp/rtmp/http-flv/ws-flv/hls的播放都将触发此鉴权事件。 | ||
| 136 | + */ | ||
| 137 | + @ResponseBody | ||
| 138 | + @PostMapping(value = "/on_play", produces = "application/json;charset=UTF-8") | ||
| 139 | + public HookResult onPlay(@RequestBody OnPlayHookParam param) { | ||
| 140 | + if (logger.isDebugEnabled()) { | ||
| 141 | + logger.debug("[ZLM HOOK] 播放鉴权:{}->{}" + param.getMediaServerId(), param); | ||
| 142 | + } | ||
| 143 | + String mediaServerId = param.getMediaServerId(); | ||
| 144 | + | ||
| 145 | + taskExecutor.execute(() -> { | ||
| 146 | + JSONObject json = (JSONObject) JSON.toJSON(param); | ||
| 147 | + ZlmHttpHookSubscribe.Event subscribe = this.subscribe.sendNotify(HookType.on_play, json); | ||
| 148 | + if (subscribe != null) { | ||
| 149 | + MediaServerItem mediaInfo = mediaServerService.getOne(mediaServerId); | ||
| 150 | + if (mediaInfo != null) { | ||
| 151 | + subscribe.response(mediaInfo, json); | ||
| 152 | + } | ||
| 153 | + } | ||
| 154 | + }); | ||
| 155 | + if (!"rtp".equals(param.getApp())) { | ||
| 156 | + Map<String, String> paramMap = urlParamToMap(param.getParams()); | ||
| 157 | + StreamAuthorityInfo streamAuthorityInfo = redisCatchStorage.getStreamAuthorityInfo(param.getApp(), param.getStream()); | ||
| 158 | + if (streamAuthorityInfo != null && streamAuthorityInfo.getCallId() != null && !streamAuthorityInfo.getCallId().equals(paramMap.get("callId"))) { | ||
| 159 | + return new HookResult(401, "Unauthorized"); | ||
| 160 | + } | ||
| 161 | + } | ||
| 162 | + | ||
| 163 | + return HookResult.SUCCESS(); | ||
| 164 | + } | ||
| 165 | + | ||
| 166 | + /** | ||
| 167 | + * rtsp/rtmp/rtp推流鉴权事件。 | ||
| 168 | + */ | ||
| 169 | + @ResponseBody | ||
| 170 | + @PostMapping(value = "/on_publish", produces = "application/json;charset=UTF-8") | ||
| 171 | + public HookResultForOnPublish onPublish(@RequestBody OnPublishHookParam param) { | ||
| 172 | + | ||
| 173 | + JSONObject json = (JSONObject) JSON.toJSON(param); | ||
| 174 | + | ||
| 175 | + logger.info("[ZLM HOOK]推流鉴权:{}->{}", param.getMediaServerId(), param); | ||
| 176 | + | ||
| 177 | + String mediaServerId = json.getString("mediaServerId"); | ||
| 178 | + MediaServerItem mediaInfo = mediaServerService.getOne(mediaServerId); | ||
| 179 | + | ||
| 180 | + if (!"rtp".equals(param.getApp())) { | ||
| 181 | + if (userSetting.getPushAuthority()) { | ||
| 182 | + // 推流鉴权 | ||
| 183 | + if (param.getParams() == null) { | ||
| 184 | + logger.info("推流鉴权失败: 缺少不要参数:sign=md5(user表的pushKey)"); | ||
| 185 | + return new HookResultForOnPublish(401, "Unauthorized"); | ||
| 186 | + } | ||
| 187 | + Map<String, String> paramMap = urlParamToMap(param.getParams()); | ||
| 188 | + String sign = paramMap.get("sign"); | ||
| 189 | + if (sign == null) { | ||
| 190 | + logger.info("推流鉴权失败: 缺少不要参数:sign=md5(user表的pushKey)"); | ||
| 191 | + return new HookResultForOnPublish(401, "Unauthorized"); | ||
| 192 | + } | ||
| 193 | + // 推流自定义播放鉴权码 | ||
| 194 | + String callId = paramMap.get("callId"); | ||
| 195 | + // 鉴权配置 | ||
| 196 | + boolean hasAuthority = userService.checkPushAuthority(callId, sign); | ||
| 197 | + if (!hasAuthority) { | ||
| 198 | + logger.info("推流鉴权失败: sign 无权限: callId={}. sign={}", callId, sign); | ||
| 199 | + return new HookResultForOnPublish(401, "Unauthorized"); | ||
| 200 | + } | ||
| 201 | + StreamAuthorityInfo streamAuthorityInfo = StreamAuthorityInfo.getInstanceByHook(param); | ||
| 202 | + streamAuthorityInfo.setCallId(callId); | ||
| 203 | + streamAuthorityInfo.setSign(sign); | ||
| 204 | + // 鉴权通过 | ||
| 205 | + redisCatchStorage.updateStreamAuthorityInfo(param.getApp(), param.getStream(), streamAuthorityInfo); | ||
| 206 | + // 通知assist新的callId | ||
| 207 | + if (mediaInfo != null && mediaInfo.getRecordAssistPort() > 0) { | ||
| 208 | + taskExecutor.execute(() -> { | ||
| 209 | + assistRESTfulUtils.addStreamCallInfo(mediaInfo, param.getApp(), param.getStream(), callId, null); | ||
| 210 | + }); | ||
| 211 | + } | ||
| 212 | + } | ||
| 213 | + } else { | ||
| 214 | + zlmMediaListManager.sendStreamEvent(param.getApp(), param.getStream(), param.getMediaServerId()); | ||
| 215 | + } | ||
| 216 | + | ||
| 217 | + | ||
| 218 | + HookResultForOnPublish result = HookResultForOnPublish.SUCCESS(); | ||
| 219 | + if (!"rtp".equals(param.getApp())) { | ||
| 220 | + result.setEnable_audio(true); | ||
| 221 | + } | ||
| 222 | + | ||
| 223 | + taskExecutor.execute(() -> { | ||
| 224 | + ZlmHttpHookSubscribe.Event subscribe = this.subscribe.sendNotify(HookType.on_publish, json); | ||
| 225 | + if (subscribe != null) { | ||
| 226 | + if (mediaInfo != null) { | ||
| 227 | + subscribe.response(mediaInfo, json); | ||
| 228 | + } else { | ||
| 229 | + new HookResultForOnPublish(1, "zlm not register"); | ||
| 230 | + } | ||
| 231 | + } | ||
| 232 | + }); | ||
| 233 | + | ||
| 234 | + if ("rtp".equals(param.getApp())) { | ||
| 235 | + result.setEnable_mp4(userSetting.getRecordSip()); | ||
| 236 | + } else { | ||
| 237 | + result.setEnable_mp4(userSetting.isRecordPushLive()); | ||
| 238 | + } | ||
| 239 | + List<SsrcTransaction> ssrcTransactionForAll = sessionManager.getSsrcTransactionForAll(null, null, null, param.getStream()); | ||
| 240 | + if (ssrcTransactionForAll != null && ssrcTransactionForAll.size() == 1) { | ||
| 241 | + String deviceId = ssrcTransactionForAll.get(0).getDeviceId(); | ||
| 242 | + String channelId = ssrcTransactionForAll.get(0).getChannelId(); | ||
| 243 | + DeviceChannel deviceChannel = storager.queryChannel(deviceId, channelId); | ||
| 244 | + if (deviceChannel != null) { | ||
| 245 | + result.setEnable_audio(deviceChannel.isHasAudio()); | ||
| 246 | + } | ||
| 247 | + // 如果是录像下载就设置视频间隔十秒 | ||
| 248 | + if (ssrcTransactionForAll.get(0).getType() == VideoStreamSessionManager.SessionType.download) { | ||
| 249 | + result.setMp4_max_second(10); | ||
| 250 | + result.setEnable_audio(true); | ||
| 251 | + result.setEnable_mp4(true); | ||
| 252 | + } | ||
| 253 | + } | ||
| 254 | + return result; | ||
| 255 | + } | ||
| 256 | + | ||
| 257 | + /** | ||
| 258 | + * rtsp/rtmp流注册或注销时触发此事件;此事件对回复不敏感。 | ||
| 259 | + */ | ||
| 260 | + @ResponseBody | ||
| 261 | + @PostMapping(value = "/on_stream_changed", produces = "application/json;charset=UTF-8") | ||
| 262 | + public HookResult onStreamChanged(@RequestBody OnStreamChangedHookParam param) { | ||
| 263 | + | ||
| 264 | + if (param.isRegist()) { | ||
| 265 | + logger.info("[ZLM HOOK] 流注册, {}->{}->{}/{}", param.getMediaServerId(), param.getSchema(), param.getApp(), param.getStream()); | ||
| 266 | + } else { | ||
| 267 | + logger.info("[ZLM HOOK] 流注销, {}->{}->{}/{}", param.getMediaServerId(), param.getSchema(), param.getApp(), param.getStream()); | ||
| 268 | + } | ||
| 269 | + | ||
| 270 | + | ||
| 271 | + JSONObject json = (JSONObject) JSON.toJSON(param); | ||
| 272 | + taskExecutor.execute(() -> { | ||
| 273 | + ZlmHttpHookSubscribe.Event subscribe = this.subscribe.sendNotify(HookType.on_stream_changed, json); | ||
| 274 | + if (subscribe != null) { | ||
| 275 | + MediaServerItem mediaInfo = mediaServerService.getOne(param.getMediaServerId()); | ||
| 276 | + if (mediaInfo != null) { | ||
| 277 | + subscribe.response(mediaInfo, json); | ||
| 278 | + } | ||
| 279 | + } | ||
| 280 | + // 流消失移除redis play | ||
| 281 | + List<OnStreamChangedHookParam.MediaTrack> tracks = param.getTracks(); | ||
| 282 | + if (param.isRegist()) { | ||
| 283 | + if (param.getOriginType() == OriginType.RTMP_PUSH.ordinal() | ||
| 284 | + || param.getOriginType() == OriginType.RTSP_PUSH.ordinal() | ||
| 285 | + || param.getOriginType() == OriginType.RTC_PUSH.ordinal()) { | ||
| 286 | + | ||
| 287 | + StreamAuthorityInfo streamAuthorityInfo = redisCatchStorage.getStreamAuthorityInfo(param.getApp(), param.getStream()); | ||
| 288 | + if (streamAuthorityInfo == null) { | ||
| 289 | + streamAuthorityInfo = StreamAuthorityInfo.getInstanceByHook(param); | ||
| 290 | + } else { | ||
| 291 | + streamAuthorityInfo.setOriginType(param.getOriginType()); | ||
| 292 | + streamAuthorityInfo.setOriginTypeStr(param.getOriginTypeStr()); | ||
| 293 | + } | ||
| 294 | + redisCatchStorage.updateStreamAuthorityInfo(param.getApp(), param.getStream(), streamAuthorityInfo); | ||
| 295 | + } | ||
| 296 | + } else { | ||
| 297 | + redisCatchStorage.removeStreamAuthorityInfo(param.getApp(), param.getStream()); | ||
| 298 | + } | ||
| 299 | + | ||
| 300 | + if ("rtsp".equals(param.getSchema())) { | ||
| 301 | + if (param.isRegist()) { | ||
| 302 | + mediaServerService.addCount(param.getMediaServerId()); | ||
| 303 | + } else { | ||
| 304 | + mediaServerService.removeCount(param.getMediaServerId()); | ||
| 305 | + } | ||
| 306 | + if (param.getOriginType() == OriginType.PULL.ordinal() | ||
| 307 | + || param.getOriginType() == OriginType.FFMPEG_PULL.ordinal()) { | ||
| 308 | + // 设置拉流代理上线/离线 | ||
| 309 | + streamProxyService.updateStatus(param.isRegist(), param.getApp(), param.getStream()); | ||
| 310 | + } | ||
| 311 | + if ("rtp".equals(param.getApp()) && !param.isRegist()) { | ||
| 312 | + StreamInfo streamInfo = redisCatchStorage.queryPlayByStreamId(param.getStream()); | ||
| 313 | + if (streamInfo != null) { | ||
| 314 | + redisCatchStorage.stopPlay(streamInfo); | ||
| 315 | + storager.stopPlay(streamInfo.getDeviceID(), streamInfo.getChannelId()); | ||
| 316 | + } else { | ||
| 317 | + streamInfo = redisCatchStorage.queryPlayback(null, null, param.getStream(), null); | ||
| 318 | + if (streamInfo != null) { | ||
| 319 | + redisCatchStorage.stopPlayback(streamInfo.getDeviceID(), streamInfo.getChannelId(), | ||
| 320 | + streamInfo.getStream(), null); | ||
| 321 | + } | ||
| 322 | + } | ||
| 323 | + } else { | ||
| 324 | + if (!"rtp".equals(param.getApp())) { | ||
| 325 | + String type = OriginType.values()[param.getOriginType()].getType(); | ||
| 326 | + MediaServerItem mediaServerItem = mediaServerService.getOne(param.getMediaServerId()); | ||
| 327 | + | ||
| 328 | + if (mediaServerItem != null) { | ||
| 329 | + if (param.isRegist()) { | ||
| 330 | + StreamAuthorityInfo streamAuthorityInfo = redisCatchStorage.getStreamAuthorityInfo(param.getApp(), param.getStream()); | ||
| 331 | + String callId = null; | ||
| 332 | + if (streamAuthorityInfo != null) { | ||
| 333 | + callId = streamAuthorityInfo.getCallId(); | ||
| 334 | + } | ||
| 335 | + StreamInfo streamInfoByAppAndStream = mediaService.getStreamInfoByAppAndStream(mediaServerItem, | ||
| 336 | + param.getApp(), param.getStream(), tracks, callId); | ||
| 337 | + param.setStreamInfo(new StreamContent(streamInfoByAppAndStream)); | ||
| 338 | + redisCatchStorage.addStream(mediaServerItem, type, param.getApp(), param.getStream(), param); | ||
| 339 | + if (param.getOriginType() == OriginType.RTSP_PUSH.ordinal() | ||
| 340 | + || param.getOriginType() == OriginType.RTMP_PUSH.ordinal() | ||
| 341 | + || param.getOriginType() == OriginType.RTC_PUSH.ordinal()) { | ||
| 342 | + param.setSeverId(userSetting.getServerId()); | ||
| 343 | + zlmMediaListManager.addPush(param); | ||
| 344 | + } | ||
| 345 | + } else { | ||
| 346 | + // 兼容流注销时类型从redis记录获取 | ||
| 347 | + OnStreamChangedHookParam onStreamChangedHookParam = redisCatchStorage.getStreamInfo(param.getApp(), param.getStream(), param.getMediaServerId()); | ||
| 348 | + if (onStreamChangedHookParam != null) { | ||
| 349 | + type = OriginType.values()[onStreamChangedHookParam.getOriginType()].getType(); | ||
| 350 | + redisCatchStorage.removeStream(mediaServerItem.getId(), type, param.getApp(), param.getStream()); | ||
| 351 | + } | ||
| 352 | + GbStream gbStream = storager.getGbStream(param.getApp(), param.getStream()); | ||
| 353 | + if (gbStream != null) { | ||
| 368 | // eventPublisher.catalogEventPublishForStream(null, gbStream, CatalogEvent.OFF); | 354 | // eventPublisher.catalogEventPublishForStream(null, gbStream, CatalogEvent.OFF); |
| 369 | - } | ||
| 370 | - zlmMediaListManager.removeMedia(param.getApp(), param.getStream()); | ||
| 371 | - } | ||
| 372 | - if (type != null) { | ||
| 373 | - // 发送流变化redis消息 | ||
| 374 | - JSONObject jsonObject = new JSONObject(); | ||
| 375 | - jsonObject.put("serverId", userSetting.getServerId()); | ||
| 376 | - jsonObject.put("app", param.getApp()); | ||
| 377 | - jsonObject.put("stream", param.getStream()); | ||
| 378 | - jsonObject.put("register", param.isRegist()); | ||
| 379 | - jsonObject.put("mediaServerId", param.getMediaServerId()); | ||
| 380 | - redisCatchStorage.sendStreamChangeMsg(type, jsonObject); | ||
| 381 | - } | ||
| 382 | - } | ||
| 383 | - } | ||
| 384 | - } | ||
| 385 | - if (!param.isRegist()) { | ||
| 386 | - List<SendRtpItem> sendRtpItems = redisCatchStorage.querySendRTPServerByStream(param.getStream()); | ||
| 387 | - if (sendRtpItems.size() > 0) { | ||
| 388 | - for (SendRtpItem sendRtpItem : sendRtpItems) { | ||
| 389 | - if (sendRtpItem.getApp().equals(param.getApp())) { | ||
| 390 | - String platformId = sendRtpItem.getPlatformId(); | ||
| 391 | - ParentPlatform platform = storager.queryParentPlatByServerGBId(platformId); | ||
| 392 | - Device device = deviceService.getDevice(platformId); | ||
| 393 | - | ||
| 394 | - try { | ||
| 395 | - if (platform != null) { | ||
| 396 | - commanderFroPlatform.streamByeCmd(platform, sendRtpItem); | ||
| 397 | - }else { | ||
| 398 | - cmder.streamByeCmd(device, sendRtpItem.getChannelId(), param.getStream(), sendRtpItem.getCallId()); | ||
| 399 | - } | ||
| 400 | - } catch (SipException | InvalidArgumentException | ParseException | SsrcTransactionNotFoundException e) { | ||
| 401 | - logger.error("[命令发送失败] 国标级联 发送BYE: {}", e.getMessage()); | ||
| 402 | - } | ||
| 403 | - } | ||
| 404 | - } | ||
| 405 | - } | ||
| 406 | - } | ||
| 407 | - } | ||
| 408 | - }); | ||
| 409 | - | ||
| 410 | - JSONObject ret = new JSONObject(); | ||
| 411 | - ret.put("code", 0); | ||
| 412 | - ret.put("msg", "success"); | ||
| 413 | - return ret; | ||
| 414 | - } | ||
| 415 | - | ||
| 416 | - /** | ||
| 417 | - * 流无人观看时事件,用户可以通过此事件选择是否关闭无人看的流。 | ||
| 418 | - * | ||
| 419 | - */ | ||
| 420 | - @ResponseBody | ||
| 421 | - @PostMapping(value = "/on_stream_none_reader", produces = "application/json;charset=UTF-8") | ||
| 422 | - public JSONObject onStreamNoneReader(@RequestBody OnStreamNoneReaderHookParam param){ | ||
| 423 | - | ||
| 424 | - logger.info("[ZLM HOOK]流无人观看:{]->{}->{}/{}" + param.getMediaServerId(), param.getSchema(), param.getApp(), param.getStream()); | ||
| 425 | - JSONObject ret = new JSONObject(); | ||
| 426 | - ret.put("code", 0); | ||
| 427 | - // 国标类型的流 | ||
| 428 | - if ("rtp".equals(param.getApp())){ | ||
| 429 | - ret.put("close", userSetting.getStreamOnDemand()); | ||
| 430 | - // 国标流, 点播/录像回放/录像下载 | ||
| 431 | - StreamInfo streamInfoForPlayCatch = redisCatchStorage.queryPlayByStreamId(param.getStream()); | ||
| 432 | - // 点播 | ||
| 433 | - if (streamInfoForPlayCatch != null) { | ||
| 434 | - // 收到无人观看说明流也没有在往上级推送 | ||
| 435 | - if (redisCatchStorage.isChannelSendingRTP(streamInfoForPlayCatch.getChannelId())) { | ||
| 436 | - List<SendRtpItem> sendRtpItems = redisCatchStorage.querySendRTPServerByChnnelId(streamInfoForPlayCatch.getChannelId()); | ||
| 437 | - if (sendRtpItems.size() > 0) { | ||
| 438 | - for (SendRtpItem sendRtpItem : sendRtpItems) { | ||
| 439 | - ParentPlatform parentPlatform = storager.queryParentPlatByServerGBId(sendRtpItem.getPlatformId()); | ||
| 440 | - try { | ||
| 441 | - commanderFroPlatform.streamByeCmd(parentPlatform, sendRtpItem.getCallId()); | ||
| 442 | - } catch (SipException | InvalidArgumentException | ParseException e) { | ||
| 443 | - logger.error("[命令发送失败] 国标级联 发送BYE: {}", e.getMessage()); | ||
| 444 | - } | ||
| 445 | - redisCatchStorage.deleteSendRTPServer(parentPlatform.getServerGBId(), sendRtpItem.getChannelId(), | ||
| 446 | - sendRtpItem.getCallId(), sendRtpItem.getStreamId()); | ||
| 447 | - } | ||
| 448 | - } | ||
| 449 | - } | ||
| 450 | - Device device = deviceService.getDevice(streamInfoForPlayCatch.getDeviceID()); | ||
| 451 | - if (device != null) { | ||
| 452 | - try { | ||
| 453 | - cmder.streamByeCmd(device, streamInfoForPlayCatch.getChannelId(), | ||
| 454 | - streamInfoForPlayCatch.getStream(), null); | ||
| 455 | - } catch (InvalidArgumentException | ParseException | SipException | SsrcTransactionNotFoundException e) { | ||
| 456 | - logger.error("[无人观看]点播, 发送BYE失败 {}", e.getMessage()); | ||
| 457 | - } | ||
| 458 | - } | ||
| 459 | - | ||
| 460 | - redisCatchStorage.stopPlay(streamInfoForPlayCatch); | ||
| 461 | - storager.stopPlay(streamInfoForPlayCatch.getDeviceID(), streamInfoForPlayCatch.getChannelId()); | ||
| 462 | - return ret; | ||
| 463 | - } | ||
| 464 | - // 录像回放 | ||
| 465 | - StreamInfo streamInfoForPlayBackCatch = redisCatchStorage.queryPlayback(null, null, param.getStream(), null); | ||
| 466 | - if (streamInfoForPlayBackCatch != null ) { | ||
| 467 | - if (streamInfoForPlayBackCatch.isPause()) { | ||
| 468 | - ret.put("close", false); | ||
| 469 | - }else { | ||
| 470 | - Device device = deviceService.getDevice(streamInfoForPlayBackCatch.getDeviceID()); | ||
| 471 | - if (device != null) { | ||
| 472 | - try { | ||
| 473 | - cmder.streamByeCmd(device,streamInfoForPlayBackCatch.getChannelId(), | ||
| 474 | - streamInfoForPlayBackCatch.getStream(), null); | ||
| 475 | - } catch (InvalidArgumentException | ParseException | SipException | | ||
| 476 | - SsrcTransactionNotFoundException e) { | ||
| 477 | - logger.error("[无人观看]回放, 发送BYE失败 {}", e.getMessage()); | ||
| 478 | - } | ||
| 479 | - } | ||
| 480 | - redisCatchStorage.stopPlayback(streamInfoForPlayBackCatch.getDeviceID(), | ||
| 481 | - streamInfoForPlayBackCatch.getChannelId(), streamInfoForPlayBackCatch.getStream(), null); | ||
| 482 | - } | ||
| 483 | - return ret; | ||
| 484 | - } | ||
| 485 | - // 录像下载 | ||
| 486 | - StreamInfo streamInfoForDownload = redisCatchStorage.queryDownload(null, null, param.getStream(), null); | ||
| 487 | - // 进行录像下载时无人观看不断流 | ||
| 488 | - if (streamInfoForDownload != null) { | ||
| 489 | - ret.put("close", false); | ||
| 490 | - return ret; | ||
| 491 | - } | ||
| 492 | - }else { | ||
| 493 | - // 非国标流 推流/拉流代理 | ||
| 494 | - // 拉流代理 | ||
| 495 | - StreamProxyItem streamProxyItem = streamProxyService.getStreamProxyByAppAndStream(param.getApp(), param.getStream()); | ||
| 496 | - if (streamProxyItem != null ) { | ||
| 497 | - if (streamProxyItem.isEnable_remove_none_reader()) { | ||
| 498 | - // 无人观看自动移除 | ||
| 499 | - ret.put("close", true); | ||
| 500 | - streamProxyService.del(param.getApp(), param.getStream()); | ||
| 501 | - String url = streamProxyItem.getUrl() != null?streamProxyItem.getUrl():streamProxyItem.getSrc_url(); | ||
| 502 | - logger.info("[{}/{}]<-[{}] 拉流代理无人观看已经移除", param.getApp(), param.getStream(), url); | ||
| 503 | - }else if (streamProxyItem.isEnable_disable_none_reader()) { | ||
| 504 | - // 无人观看停用 | ||
| 505 | - ret.put("close", true); | ||
| 506 | - // 修改数据 | ||
| 507 | - streamProxyService.stop(param.getApp(), param.getStream()); | ||
| 508 | - }else { | ||
| 509 | - // 无人观看不做处理 | ||
| 510 | - ret.put("close", false); | ||
| 511 | - } | ||
| 512 | - return ret; | ||
| 513 | - } | ||
| 514 | - // 推流具有主动性,暂时不做处理 | 355 | + } |
| 356 | + zlmMediaListManager.removeMedia(param.getApp(), param.getStream()); | ||
| 357 | + } | ||
| 358 | + if (type != null) { | ||
| 359 | + // 发送流变化redis消息 | ||
| 360 | + JSONObject jsonObject = new JSONObject(); | ||
| 361 | + jsonObject.put("serverId", userSetting.getServerId()); | ||
| 362 | + jsonObject.put("app", param.getApp()); | ||
| 363 | + jsonObject.put("stream", param.getStream()); | ||
| 364 | + jsonObject.put("register", param.isRegist()); | ||
| 365 | + jsonObject.put("mediaServerId", param.getMediaServerId()); | ||
| 366 | + redisCatchStorage.sendStreamChangeMsg(type, jsonObject); | ||
| 367 | + } | ||
| 368 | + } | ||
| 369 | + } | ||
| 370 | + } | ||
| 371 | + if (!param.isRegist()) { | ||
| 372 | + List<SendRtpItem> sendRtpItems = redisCatchStorage.querySendRTPServerByStream(param.getStream()); | ||
| 373 | + if (sendRtpItems.size() > 0) { | ||
| 374 | + for (SendRtpItem sendRtpItem : sendRtpItems) { | ||
| 375 | + if (sendRtpItem.getApp().equals(param.getApp())) { | ||
| 376 | + String platformId = sendRtpItem.getPlatformId(); | ||
| 377 | + ParentPlatform platform = storager.queryParentPlatByServerGBId(platformId); | ||
| 378 | + Device device = deviceService.getDevice(platformId); | ||
| 379 | + | ||
| 380 | + try { | ||
| 381 | + if (platform != null) { | ||
| 382 | + commanderFroPlatform.streamByeCmd(platform, sendRtpItem); | ||
| 383 | + } else { | ||
| 384 | + cmder.streamByeCmd(device, sendRtpItem.getChannelId(), param.getStream(), sendRtpItem.getCallId()); | ||
| 385 | + } | ||
| 386 | + } catch (SipException | InvalidArgumentException | ParseException | | ||
| 387 | + SsrcTransactionNotFoundException e) { | ||
| 388 | + logger.error("[命令发送失败] 国标级联 发送BYE: {}", e.getMessage()); | ||
| 389 | + } | ||
| 390 | + } | ||
| 391 | + } | ||
| 392 | + } | ||
| 393 | + } | ||
| 394 | + } | ||
| 395 | + }); | ||
| 396 | + | ||
| 397 | + return HookResult.SUCCESS(); | ||
| 398 | + } | ||
| 399 | + | ||
| 400 | + /** | ||
| 401 | + * 流无人观看时事件,用户可以通过此事件选择是否关闭无人看的流。 | ||
| 402 | + */ | ||
| 403 | + @ResponseBody | ||
| 404 | + @PostMapping(value = "/on_stream_none_reader", produces = "application/json;charset=UTF-8") | ||
| 405 | + public JSONObject onStreamNoneReader(@RequestBody OnStreamNoneReaderHookParam param) { | ||
| 406 | + | ||
| 407 | + logger.info("[ZLM HOOK]流无人观看:{]->{}->{}/{}" + param.getMediaServerId(), param.getSchema(), param.getApp(), param.getStream()); | ||
| 408 | + JSONObject ret = new JSONObject(); | ||
| 409 | + ret.put("code", 0); | ||
| 410 | + // 国标类型的流 | ||
| 411 | + if ("rtp".equals(param.getApp())) { | ||
| 412 | + ret.put("close", userSetting.getStreamOnDemand()); | ||
| 413 | + // 国标流, 点播/录像回放/录像下载 | ||
| 414 | + StreamInfo streamInfoForPlayCatch = redisCatchStorage.queryPlayByStreamId(param.getStream()); | ||
| 415 | + // 点播 | ||
| 416 | + if (streamInfoForPlayCatch != null) { | ||
| 417 | + // 收到无人观看说明流也没有在往上级推送 | ||
| 418 | + if (redisCatchStorage.isChannelSendingRTP(streamInfoForPlayCatch.getChannelId())) { | ||
| 419 | + List<SendRtpItem> sendRtpItems = redisCatchStorage.querySendRTPServerByChnnelId(streamInfoForPlayCatch.getChannelId()); | ||
| 420 | + if (sendRtpItems.size() > 0) { | ||
| 421 | + for (SendRtpItem sendRtpItem : sendRtpItems) { | ||
| 422 | + ParentPlatform parentPlatform = storager.queryParentPlatByServerGBId(sendRtpItem.getPlatformId()); | ||
| 423 | + try { | ||
| 424 | + commanderFroPlatform.streamByeCmd(parentPlatform, sendRtpItem.getCallId()); | ||
| 425 | + } catch (SipException | InvalidArgumentException | ParseException e) { | ||
| 426 | + logger.error("[命令发送失败] 国标级联 发送BYE: {}", e.getMessage()); | ||
| 427 | + } | ||
| 428 | + redisCatchStorage.deleteSendRTPServer(parentPlatform.getServerGBId(), sendRtpItem.getChannelId(), | ||
| 429 | + sendRtpItem.getCallId(), sendRtpItem.getStreamId()); | ||
| 430 | + } | ||
| 431 | + } | ||
| 432 | + } | ||
| 433 | + Device device = deviceService.getDevice(streamInfoForPlayCatch.getDeviceID()); | ||
| 434 | + if (device != null) { | ||
| 435 | + try { | ||
| 436 | + cmder.streamByeCmd(device, streamInfoForPlayCatch.getChannelId(), | ||
| 437 | + streamInfoForPlayCatch.getStream(), null); | ||
| 438 | + } catch (InvalidArgumentException | ParseException | SipException | | ||
| 439 | + SsrcTransactionNotFoundException e) { | ||
| 440 | + logger.error("[无人观看]点播, 发送BYE失败 {}", e.getMessage()); | ||
| 441 | + } | ||
| 442 | + } | ||
| 443 | + | ||
| 444 | + redisCatchStorage.stopPlay(streamInfoForPlayCatch); | ||
| 445 | + storager.stopPlay(streamInfoForPlayCatch.getDeviceID(), streamInfoForPlayCatch.getChannelId()); | ||
| 446 | + return ret; | ||
| 447 | + } | ||
| 448 | + // 录像回放 | ||
| 449 | + StreamInfo streamInfoForPlayBackCatch = redisCatchStorage.queryPlayback(null, null, param.getStream(), null); | ||
| 450 | + if (streamInfoForPlayBackCatch != null) { | ||
| 451 | + if (streamInfoForPlayBackCatch.isPause()) { | ||
| 452 | + ret.put("close", false); | ||
| 453 | + } else { | ||
| 454 | + Device device = deviceService.getDevice(streamInfoForPlayBackCatch.getDeviceID()); | ||
| 455 | + if (device != null) { | ||
| 456 | + try { | ||
| 457 | + cmder.streamByeCmd(device, streamInfoForPlayBackCatch.getChannelId(), | ||
| 458 | + streamInfoForPlayBackCatch.getStream(), null); | ||
| 459 | + } catch (InvalidArgumentException | ParseException | SipException | | ||
| 460 | + SsrcTransactionNotFoundException e) { | ||
| 461 | + logger.error("[无人观看]回放, 发送BYE失败 {}", e.getMessage()); | ||
| 462 | + } | ||
| 463 | + } | ||
| 464 | + redisCatchStorage.stopPlayback(streamInfoForPlayBackCatch.getDeviceID(), | ||
| 465 | + streamInfoForPlayBackCatch.getChannelId(), streamInfoForPlayBackCatch.getStream(), null); | ||
| 466 | + } | ||
| 467 | + return ret; | ||
| 468 | + } | ||
| 469 | + // 录像下载 | ||
| 470 | + StreamInfo streamInfoForDownload = redisCatchStorage.queryDownload(null, null, param.getStream(), null); | ||
| 471 | + // 进行录像下载时无人观看不断流 | ||
| 472 | + if (streamInfoForDownload != null) { | ||
| 473 | + ret.put("close", false); | ||
| 474 | + return ret; | ||
| 475 | + } | ||
| 476 | + } else { | ||
| 477 | + // 非国标流 推流/拉流代理 | ||
| 478 | + // 拉流代理 | ||
| 479 | + StreamProxyItem streamProxyItem = streamProxyService.getStreamProxyByAppAndStream(param.getApp(), param.getStream()); | ||
| 480 | + if (streamProxyItem != null) { | ||
| 481 | + if (streamProxyItem.isEnable_remove_none_reader()) { | ||
| 482 | + // 无人观看自动移除 | ||
| 483 | + ret.put("close", true); | ||
| 484 | + streamProxyService.del(param.getApp(), param.getStream()); | ||
| 485 | + String url = streamProxyItem.getUrl() != null ? streamProxyItem.getUrl() : streamProxyItem.getSrc_url(); | ||
| 486 | + logger.info("[{}/{}]<-[{}] 拉流代理无人观看已经移除", param.getApp(), param.getStream(), url); | ||
| 487 | + } else if (streamProxyItem.isEnable_disable_none_reader()) { | ||
| 488 | + // 无人观看停用 | ||
| 489 | + ret.put("close", true); | ||
| 490 | + // 修改数据 | ||
| 491 | + streamProxyService.stop(param.getApp(), param.getStream()); | ||
| 492 | + } else { | ||
| 493 | + // 无人观看不做处理 | ||
| 494 | + ret.put("close", false); | ||
| 495 | + } | ||
| 496 | + return ret; | ||
| 497 | + } | ||
| 498 | + // 推流具有主动性,暂时不做处理 | ||
| 515 | // StreamPushItem streamPushItem = streamPushService.getPush(app, streamId); | 499 | // StreamPushItem streamPushItem = streamPushService.getPush(app, streamId); |
| 516 | // if (streamPushItem != null) { | 500 | // if (streamPushItem != null) { |
| 517 | // // TODO 发送停止 | 501 | // // TODO 发送停止 |
| 518 | // | 502 | // |
| 519 | // } | 503 | // } |
| 520 | - } | ||
| 521 | - return ret; | ||
| 522 | - } | ||
| 523 | - | ||
| 524 | - /** | ||
| 525 | - * 流未找到事件,用户可以在此事件触发时,立即去拉流,这样可以实现按需拉流;此事件对回复不敏感。 | ||
| 526 | - * | ||
| 527 | - */ | ||
| 528 | - @ResponseBody | ||
| 529 | - @PostMapping(value = "/on_stream_not_found", produces = "application/json;charset=UTF-8") | ||
| 530 | - public JSONObject onStreamNotFound(@RequestBody OnStreamNotFoundHookParam param){ | ||
| 531 | - logger.info("[ZLM HOOK] 流未找到:{}->{}->{}/{}", param.getMediaServerId(), param.getSchema(), param.getApp(), param.getStream()); | ||
| 532 | - taskExecutor.execute(()->{ | ||
| 533 | - MediaServerItem mediaInfo = mediaServerService.getOne(param.getMediaServerId()); | ||
| 534 | - if (userSetting.isAutoApplyPlay() && mediaInfo != null) { | ||
| 535 | - if ("rtp".equals(param.getApp())) { | ||
| 536 | - if (mediaInfo.isRtpEnable()) { | ||
| 537 | - String[] s = param.getStream().split("_"); | ||
| 538 | - if (s.length == 2) { | ||
| 539 | - String deviceId = s[0]; | ||
| 540 | - String channelId = s[1]; | ||
| 541 | - Device device = redisCatchStorage.getDevice(deviceId); | ||
| 542 | - if (device != null) { | ||
| 543 | - playService.play(mediaInfo,deviceId, channelId, null, null, null); | ||
| 544 | - } | ||
| 545 | - } | ||
| 546 | - } | ||
| 547 | - }else { | ||
| 548 | - // 拉流代理 | ||
| 549 | - StreamProxyItem streamProxyByAppAndStream = streamProxyService.getStreamProxyByAppAndStream(param.getApp(), param.getStream()); | ||
| 550 | - if (streamProxyByAppAndStream != null && streamProxyByAppAndStream.isEnable_disable_none_reader()) { | ||
| 551 | - streamProxyService.start(param.getApp(), param.getStream()); | ||
| 552 | - } | ||
| 553 | - } | ||
| 554 | - } | ||
| 555 | - }); | ||
| 556 | - | ||
| 557 | - | ||
| 558 | - JSONObject ret = new JSONObject(); | ||
| 559 | - ret.put("code", 0); | ||
| 560 | - ret.put("msg", "success"); | ||
| 561 | - return ret; | ||
| 562 | - } | ||
| 563 | - | ||
| 564 | - /** | ||
| 565 | - * 服务器启动事件,可以用于监听服务器崩溃重启;此事件对回复不敏感。 | ||
| 566 | - * | ||
| 567 | - */ | ||
| 568 | - @ResponseBody | ||
| 569 | - @PostMapping(value = "/on_server_started", produces = "application/json;charset=UTF-8") | ||
| 570 | - public JSONObject onServerStarted(HttpServletRequest request, @RequestBody JSONObject jsonObject){ | ||
| 571 | - | ||
| 572 | - jsonObject.put("ip", request.getRemoteAddr()); | ||
| 573 | - ZLMServerConfig zlmServerConfig = JSON.to(ZLMServerConfig.class, jsonObject); | ||
| 574 | - zlmServerConfig.setIp(request.getRemoteAddr()); | ||
| 575 | - logger.info("[ZLM HOOK] zlm 启动 " + zlmServerConfig.getGeneralMediaServerId()); | ||
| 576 | - taskExecutor.execute(()->{ | ||
| 577 | - List<ZlmHttpHookSubscribe.Event> subscribes = this.subscribe.getSubscribes(HookType.on_server_started); | ||
| 578 | - if (subscribes != null && subscribes.size() > 0) { | ||
| 579 | - for (ZlmHttpHookSubscribe.Event subscribe : subscribes) { | ||
| 580 | - subscribe.response(null, jsonObject); | ||
| 581 | - } | ||
| 582 | - } | ||
| 583 | - mediaServerService.zlmServerOnline(zlmServerConfig); | ||
| 584 | - }); | ||
| 585 | - | ||
| 586 | - JSONObject ret = new JSONObject(); | ||
| 587 | - ret.put("code", 0); | ||
| 588 | - ret.put("msg", "success"); | ||
| 589 | - return ret; | ||
| 590 | - } | ||
| 591 | - | ||
| 592 | - /** | ||
| 593 | - * 发送rtp(startSendRtp)被动关闭时回调 | ||
| 594 | - */ | ||
| 595 | - @ResponseBody | ||
| 596 | - @PostMapping(value = "/on_send_rtp_stopped", produces = "application/json;charset=UTF-8") | ||
| 597 | - public JSONObject onSendRtpStopped(HttpServletRequest request, @RequestBody OnSendRtpStoppedHookParam param){ | ||
| 598 | - | ||
| 599 | - logger.info("[ZLM HOOK] rtp发送关闭:{}->{}/{}", param.getMediaServerId(), param.getApp(), param.getStream()); | ||
| 600 | - | ||
| 601 | - JSONObject ret = new JSONObject(); | ||
| 602 | - ret.put("code", 0); | ||
| 603 | - ret.put("msg", "success"); | ||
| 604 | - | ||
| 605 | - // 查找对应的上级推流,发送停止 | ||
| 606 | - if (!"rtp".equals(param.getApp())) { | ||
| 607 | - return ret; | ||
| 608 | - } | ||
| 609 | - taskExecutor.execute(()->{ | ||
| 610 | - List<SendRtpItem> sendRtpItems = redisCatchStorage.querySendRTPServerByStream(param.getStream()); | ||
| 611 | - if (sendRtpItems.size() > 0) { | ||
| 612 | - for (SendRtpItem sendRtpItem : sendRtpItems) { | ||
| 613 | - ParentPlatform parentPlatform = storager.queryParentPlatByServerGBId(sendRtpItem.getPlatformId()); | ||
| 614 | - try { | ||
| 615 | - commanderFroPlatform.streamByeCmd(parentPlatform, sendRtpItem.getCallId()); | ||
| 616 | - } catch (SipException | InvalidArgumentException | ParseException e) { | ||
| 617 | - logger.error("[命令发送失败] 国标级联 发送BYE: {}", e.getMessage()); | ||
| 618 | - } | ||
| 619 | - redisCatchStorage.deleteSendRTPServer(parentPlatform.getServerGBId(), sendRtpItem.getChannelId(), | ||
| 620 | - sendRtpItem.getCallId(), sendRtpItem.getStreamId()); | ||
| 621 | - } | ||
| 622 | - } | ||
| 623 | - }); | ||
| 624 | - | ||
| 625 | - | ||
| 626 | - return ret; | ||
| 627 | - } | ||
| 628 | - | ||
| 629 | - /** | ||
| 630 | - * rtpServer收流超时 | ||
| 631 | - */ | ||
| 632 | - @ResponseBody | ||
| 633 | - @PostMapping(value = "/on_rtp_server_timeout", produces = "application/json;charset=UTF-8") | ||
| 634 | - public JSONObject onRtpServerTimeout(HttpServletRequest request, @RequestBody OnRtpServerTimeoutHookParam param){ | ||
| 635 | - logger.info("[ZLM HOOK] rtpServer收流超时:{}->{}({})", param.getMediaServerId(), param.getStream_id(), param.getSsrc()); | ||
| 636 | - | ||
| 637 | - JSONObject ret = new JSONObject(); | ||
| 638 | - ret.put("code", 0); | ||
| 639 | - ret.put("msg", "success"); | ||
| 640 | - | ||
| 641 | - taskExecutor.execute(()->{ | ||
| 642 | - JSONObject json = (JSONObject) JSON.toJSON(param); | ||
| 643 | - List<ZlmHttpHookSubscribe.Event> subscribes = this.subscribe.getSubscribes(HookType.on_rtp_server_timeout); | ||
| 644 | - if (subscribes != null && subscribes.size() > 0) { | ||
| 645 | - for (ZlmHttpHookSubscribe.Event subscribe : subscribes) { | ||
| 646 | - subscribe.response(null, json); | ||
| 647 | - } | ||
| 648 | - } | ||
| 649 | - }); | ||
| 650 | - | ||
| 651 | - return ret; | ||
| 652 | - } | ||
| 653 | - | ||
| 654 | - private Map<String, String> urlParamToMap(String params) { | ||
| 655 | - HashMap<String, String> map = new HashMap<>(); | ||
| 656 | - if (ObjectUtils.isEmpty(params)) { | ||
| 657 | - return map; | ||
| 658 | - } | ||
| 659 | - String[] paramsArray = params.split("&"); | ||
| 660 | - if (paramsArray.length == 0) { | ||
| 661 | - return map; | ||
| 662 | - } | ||
| 663 | - for (String param : paramsArray) { | ||
| 664 | - String[] paramArray = param.split("="); | ||
| 665 | - if (paramArray.length == 2){ | ||
| 666 | - map.put(paramArray[0], paramArray[1]); | ||
| 667 | - } | ||
| 668 | - } | ||
| 669 | - return map; | ||
| 670 | - } | 504 | + } |
| 505 | + return ret; | ||
| 506 | + } | ||
| 507 | + | ||
| 508 | + /** | ||
| 509 | + * 流未找到事件,用户可以在此事件触发时,立即去拉流,这样可以实现按需拉流;此事件对回复不敏感。 | ||
| 510 | + */ | ||
| 511 | + @ResponseBody | ||
| 512 | + @PostMapping(value = "/on_stream_not_found", produces = "application/json;charset=UTF-8") | ||
| 513 | + public DeferredResult<HookResult> onStreamNotFound(@RequestBody OnStreamNotFoundHookParam param) { | ||
| 514 | + logger.info("[ZLM HOOK] 流未找到:{}->{}->{}/{}", param.getMediaServerId(), param.getSchema(), param.getApp(), param.getStream()); | ||
| 515 | + | ||
| 516 | + DeferredResult<HookResult> defaultResult = new DeferredResult<>(); | ||
| 517 | + | ||
| 518 | + MediaServerItem mediaInfo = mediaServerService.getOne(param.getMediaServerId()); | ||
| 519 | + if (!userSetting.isAutoApplyPlay() || mediaInfo == null) { | ||
| 520 | + defaultResult.setResult(new HookResult(ErrorCode.ERROR404.getCode(), ErrorCode.ERROR404.getMsg())); | ||
| 521 | + return defaultResult; | ||
| 522 | + } | ||
| 523 | + | ||
| 524 | + if ("rtp".equals(param.getApp())) { | ||
| 525 | + String[] s = param.getStream().split("_"); | ||
| 526 | + if (!mediaInfo.isRtpEnable() || s.length != 2) { | ||
| 527 | + defaultResult.setResult(HookResult.SUCCESS()); | ||
| 528 | + return defaultResult; | ||
| 529 | + } | ||
| 530 | + String deviceId = s[0]; | ||
| 531 | + String channelId = s[1]; | ||
| 532 | + Device device = redisCatchStorage.getDevice(deviceId); | ||
| 533 | + if (device == null) { | ||
| 534 | + defaultResult.setResult(new HookResult(ErrorCode.ERROR404.getCode(), ErrorCode.ERROR404.getMsg())); | ||
| 535 | + return defaultResult; | ||
| 536 | + } | ||
| 537 | + DeviceChannel deviceChannel = storager.queryChannel(deviceId, channelId); | ||
| 538 | + if (deviceChannel == null) { | ||
| 539 | + defaultResult.setResult(new HookResult(ErrorCode.ERROR404.getCode(), ErrorCode.ERROR404.getMsg())); | ||
| 540 | + return defaultResult; | ||
| 541 | + } | ||
| 542 | + logger.info("[ZLM HOOK] 流未找到, 发起自动点播:{}->{}->{}/{}", param.getMediaServerId(), param.getSchema(), param.getApp(), param.getStream()); | ||
| 543 | + RequestMessage msg = new RequestMessage(); | ||
| 544 | + String key = DeferredResultHolder.CALLBACK_CMD_PLAY + deviceId + channelId; | ||
| 545 | + boolean exist = resultHolder.exist(key, null); | ||
| 546 | + msg.setKey(key); | ||
| 547 | + String uuid = UUID.randomUUID().toString(); | ||
| 548 | + msg.setId(uuid); | ||
| 549 | + DeferredResult<HookResult> result = new DeferredResult<>(userSetting.getPlayTimeout().longValue()); | ||
| 550 | + DeferredResultEx<HookResult> deferredResultEx = new DeferredResultEx<>(result); | ||
| 551 | + | ||
| 552 | + result.onTimeout(() -> { | ||
| 553 | + logger.info("点播接口等待超时"); | ||
| 554 | + // 释放rtpserver | ||
| 555 | + msg.setData(new HookResult(ErrorCode.ERROR100.getCode(), "点播超时")); | ||
| 556 | + resultHolder.invokeResult(msg); | ||
| 557 | + }); | ||
| 558 | + // TODO 在点播未成功的情况下在此调用接口点播会导致返回的流地址ip错误 | ||
| 559 | + deferredResultEx.setFilter(result1 -> { | ||
| 560 | + WVPResult<StreamInfo> wvpResult1 = (WVPResult<StreamInfo>) result1; | ||
| 561 | + HookResult resultForEnd = new HookResult(); | ||
| 562 | + resultForEnd.setCode(wvpResult1.getCode()); | ||
| 563 | + resultForEnd.setMsg(wvpResult1.getMsg()); | ||
| 564 | + return resultForEnd; | ||
| 565 | + }); | ||
| 566 | + | ||
| 567 | + // 录像查询以channelId作为deviceId查询 | ||
| 568 | + resultHolder.put(key, uuid, deferredResultEx); | ||
| 569 | + | ||
| 570 | + if (!exist) { | ||
| 571 | + playService.play(mediaInfo, deviceId, channelId, null, eventResult -> { | ||
| 572 | + msg.setData(new HookResult(eventResult.statusCode, eventResult.msg)); | ||
| 573 | + resultHolder.invokeResult(msg); | ||
| 574 | + }, null); | ||
| 575 | + } | ||
| 576 | + return result; | ||
| 577 | + } else { | ||
| 578 | + // 拉流代理 | ||
| 579 | + StreamProxyItem streamProxyByAppAndStream = streamProxyService.getStreamProxyByAppAndStream(param.getApp(), param.getStream()); | ||
| 580 | + if (streamProxyByAppAndStream != null && streamProxyByAppAndStream.isEnable_disable_none_reader()) { | ||
| 581 | + streamProxyService.start(param.getApp(), param.getStream()); | ||
| 582 | + } | ||
| 583 | + DeferredResult<HookResult> result = new DeferredResult<>(); | ||
| 584 | + result.setResult(HookResult.SUCCESS()); | ||
| 585 | + return result; | ||
| 586 | + } | ||
| 587 | + } | ||
| 588 | + | ||
| 589 | + /** | ||
| 590 | + * 服务器启动事件,可以用于监听服务器崩溃重启;此事件对回复不敏感。 | ||
| 591 | + */ | ||
| 592 | + @ResponseBody | ||
| 593 | + @PostMapping(value = "/on_server_started", produces = "application/json;charset=UTF-8") | ||
| 594 | + public HookResult onServerStarted(HttpServletRequest request, @RequestBody JSONObject jsonObject) { | ||
| 595 | + | ||
| 596 | + jsonObject.put("ip", request.getRemoteAddr()); | ||
| 597 | + ZLMServerConfig zlmServerConfig = JSON.to(ZLMServerConfig.class, jsonObject); | ||
| 598 | + zlmServerConfig.setIp(request.getRemoteAddr()); | ||
| 599 | + logger.info("[ZLM HOOK] zlm 启动 " + zlmServerConfig.getGeneralMediaServerId()); | ||
| 600 | + taskExecutor.execute(() -> { | ||
| 601 | + List<ZlmHttpHookSubscribe.Event> subscribes = this.subscribe.getSubscribes(HookType.on_server_started); | ||
| 602 | + if (subscribes != null && subscribes.size() > 0) { | ||
| 603 | + for (ZlmHttpHookSubscribe.Event subscribe : subscribes) { | ||
| 604 | + subscribe.response(null, jsonObject); | ||
| 605 | + } | ||
| 606 | + } | ||
| 607 | + mediaServerService.zlmServerOnline(zlmServerConfig); | ||
| 608 | + }); | ||
| 609 | + | ||
| 610 | + return HookResult.SUCCESS(); | ||
| 611 | + } | ||
| 612 | + | ||
| 613 | + /** | ||
| 614 | + * 发送rtp(startSendRtp)被动关闭时回调 | ||
| 615 | + */ | ||
| 616 | + @ResponseBody | ||
| 617 | + @PostMapping(value = "/on_send_rtp_stopped", produces = "application/json;charset=UTF-8") | ||
| 618 | + public HookResult onSendRtpStopped(HttpServletRequest request, @RequestBody OnSendRtpStoppedHookParam param) { | ||
| 619 | + | ||
| 620 | + logger.info("[ZLM HOOK] rtp发送关闭:{}->{}/{}", param.getMediaServerId(), param.getApp(), param.getStream()); | ||
| 621 | + | ||
| 622 | + // 查找对应的上级推流,发送停止 | ||
| 623 | + if (!"rtp".equals(param.getApp())) { | ||
| 624 | + return HookResult.SUCCESS(); | ||
| 625 | + } | ||
| 626 | + taskExecutor.execute(() -> { | ||
| 627 | + List<SendRtpItem> sendRtpItems = redisCatchStorage.querySendRTPServerByStream(param.getStream()); | ||
| 628 | + if (sendRtpItems.size() > 0) { | ||
| 629 | + for (SendRtpItem sendRtpItem : sendRtpItems) { | ||
| 630 | + ParentPlatform parentPlatform = storager.queryParentPlatByServerGBId(sendRtpItem.getPlatformId()); | ||
| 631 | + try { | ||
| 632 | + commanderFroPlatform.streamByeCmd(parentPlatform, sendRtpItem.getCallId()); | ||
| 633 | + } catch (SipException | InvalidArgumentException | ParseException e) { | ||
| 634 | + logger.error("[命令发送失败] 国标级联 发送BYE: {}", e.getMessage()); | ||
| 635 | + } | ||
| 636 | + redisCatchStorage.deleteSendRTPServer(parentPlatform.getServerGBId(), sendRtpItem.getChannelId(), | ||
| 637 | + sendRtpItem.getCallId(), sendRtpItem.getStreamId()); | ||
| 638 | + } | ||
| 639 | + } | ||
| 640 | + }); | ||
| 641 | + | ||
| 642 | + return HookResult.SUCCESS(); | ||
| 643 | + } | ||
| 644 | + | ||
| 645 | + /** | ||
| 646 | + * rtpServer收流超时 | ||
| 647 | + */ | ||
| 648 | + @ResponseBody | ||
| 649 | + @PostMapping(value = "/on_rtp_server_timeout", produces = "application/json;charset=UTF-8") | ||
| 650 | + public HookResult onRtpServerTimeout(HttpServletRequest request, @RequestBody OnRtpServerTimeoutHookParam param) { | ||
| 651 | + logger.info("[ZLM HOOK] rtpServer收流超时:{}->{}({})", param.getMediaServerId(), param.getStream_id(), param.getSsrc()); | ||
| 652 | + | ||
| 653 | + taskExecutor.execute(() -> { | ||
| 654 | + JSONObject json = (JSONObject) JSON.toJSON(param); | ||
| 655 | + List<ZlmHttpHookSubscribe.Event> subscribes = this.subscribe.getSubscribes(HookType.on_rtp_server_timeout); | ||
| 656 | + if (subscribes != null && subscribes.size() > 0) { | ||
| 657 | + for (ZlmHttpHookSubscribe.Event subscribe : subscribes) { | ||
| 658 | + subscribe.response(null, json); | ||
| 659 | + } | ||
| 660 | + } | ||
| 661 | + }); | ||
| 662 | + | ||
| 663 | + return HookResult.SUCCESS(); | ||
| 664 | + } | ||
| 665 | + | ||
| 666 | + private Map<String, String> urlParamToMap(String params) { | ||
| 667 | + HashMap<String, String> map = new HashMap<>(); | ||
| 668 | + if (ObjectUtils.isEmpty(params)) { | ||
| 669 | + return map; | ||
| 670 | + } | ||
| 671 | + String[] paramsArray = params.split("&"); | ||
| 672 | + if (paramsArray.length == 0) { | ||
| 673 | + return map; | ||
| 674 | + } | ||
| 675 | + for (String param : paramsArray) { | ||
| 676 | + String[] paramArray = param.split("="); | ||
| 677 | + if (paramArray.length == 2) { | ||
| 678 | + map.put(paramArray[0], paramArray[1]); | ||
| 679 | + } | ||
| 680 | + } | ||
| 681 | + return map; | ||
| 682 | + } | ||
| 671 | } | 683 | } |
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/HookResult.java
0 → 100644
| 1 | +package com.genersoft.iot.vmp.media.zlm.dto.hook; | ||
| 2 | + | ||
| 3 | +public class HookResult { | ||
| 4 | + | ||
| 5 | + private int code; | ||
| 6 | + private String msg; | ||
| 7 | + | ||
| 8 | + | ||
| 9 | + public HookResult() { | ||
| 10 | + } | ||
| 11 | + | ||
| 12 | + public HookResult(int code, String msg) { | ||
| 13 | + this.code = code; | ||
| 14 | + this.msg = msg; | ||
| 15 | + } | ||
| 16 | + | ||
| 17 | + public static HookResult SUCCESS(){ | ||
| 18 | + return new HookResult(0, "success"); | ||
| 19 | + } | ||
| 20 | + | ||
| 21 | + public int getCode() { | ||
| 22 | + return code; | ||
| 23 | + } | ||
| 24 | + | ||
| 25 | + public void setCode(int code) { | ||
| 26 | + this.code = code; | ||
| 27 | + } | ||
| 28 | + | ||
| 29 | + public String getMsg() { | ||
| 30 | + return msg; | ||
| 31 | + } | ||
| 32 | + | ||
| 33 | + public void setMsg(String msg) { | ||
| 34 | + this.msg = msg; | ||
| 35 | + } | ||
| 36 | +} |
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/HookResultForOnPublish.java
0 → 100644
| 1 | +package com.genersoft.iot.vmp.media.zlm.dto.hook; | ||
| 2 | + | ||
| 3 | +public class HookResultForOnPublish extends HookResult{ | ||
| 4 | + | ||
| 5 | + private boolean enable_audio; | ||
| 6 | + private boolean enable_mp4; | ||
| 7 | + private int mp4_max_second; | ||
| 8 | + | ||
| 9 | + public HookResultForOnPublish() { | ||
| 10 | + } | ||
| 11 | + | ||
| 12 | + public static HookResultForOnPublish SUCCESS(){ | ||
| 13 | + return new HookResultForOnPublish(0, "success"); | ||
| 14 | + } | ||
| 15 | + | ||
| 16 | + public HookResultForOnPublish(int code, String msg) { | ||
| 17 | + setCode(code); | ||
| 18 | + setMsg(msg); | ||
| 19 | + } | ||
| 20 | + | ||
| 21 | + public boolean isEnable_audio() { | ||
| 22 | + return enable_audio; | ||
| 23 | + } | ||
| 24 | + | ||
| 25 | + public void setEnable_audio(boolean enable_audio) { | ||
| 26 | + this.enable_audio = enable_audio; | ||
| 27 | + } | ||
| 28 | + | ||
| 29 | + public boolean isEnable_mp4() { | ||
| 30 | + return enable_mp4; | ||
| 31 | + } | ||
| 32 | + | ||
| 33 | + public void setEnable_mp4(boolean enable_mp4) { | ||
| 34 | + this.enable_mp4 = enable_mp4; | ||
| 35 | + } | ||
| 36 | + | ||
| 37 | + public int getMp4_max_second() { | ||
| 38 | + return mp4_max_second; | ||
| 39 | + } | ||
| 40 | + | ||
| 41 | + public void setMp4_max_second(int mp4_max_second) { | ||
| 42 | + this.mp4_max_second = mp4_max_second; | ||
| 43 | + } | ||
| 44 | +} |
src/main/java/com/genersoft/iot/vmp/service/impl/GbStreamServiceImpl.java
| @@ -152,6 +152,10 @@ public class GbStreamServiceImpl implements IGbStreamService { | @@ -152,6 +152,10 @@ public class GbStreamServiceImpl implements IGbStreamService { | ||
| 152 | 152 | ||
| 153 | @Override | 153 | @Override |
| 154 | public void sendCatalogMsg(GbStream gbStream, String type) { | 154 | public void sendCatalogMsg(GbStream gbStream, String type) { |
| 155 | + if (gbStream == null || type == null) { | ||
| 156 | + logger.warn("[发送目录订阅]类型:流信息或类型为NULL"); | ||
| 157 | + return; | ||
| 158 | + } | ||
| 155 | List<GbStream> gbStreams = new ArrayList<>(); | 159 | List<GbStream> gbStreams = new ArrayList<>(); |
| 156 | if (gbStream.getGbId() != null) { | 160 | if (gbStream.getGbId() != null) { |
| 157 | gbStreams.add(gbStream); | 161 | gbStreams.add(gbStream); |
src/main/java/com/genersoft/iot/vmp/service/impl/StreamPushServiceImpl.java
| @@ -184,7 +184,9 @@ public class StreamPushServiceImpl implements IStreamPushService { | @@ -184,7 +184,9 @@ public class StreamPushServiceImpl implements IStreamPushService { | ||
| 184 | @Override | 184 | @Override |
| 185 | public boolean stop(String app, String streamId) { | 185 | public boolean stop(String app, String streamId) { |
| 186 | StreamPushItem streamPushItem = streamPushMapper.selectOne(app, streamId); | 186 | StreamPushItem streamPushItem = streamPushMapper.selectOne(app, streamId); |
| 187 | - gbStreamService.sendCatalogMsg(streamPushItem, CatalogEvent.DEL); | 187 | + if (streamPushItem != null) { |
| 188 | + gbStreamService.sendCatalogMsg(streamPushItem, CatalogEvent.DEL); | ||
| 189 | + } | ||
| 188 | 190 | ||
| 189 | platformGbStreamMapper.delByAppAndStream(app, streamId); | 191 | platformGbStreamMapper.delByAppAndStream(app, streamId); |
| 190 | gbStreamMapper.del(app, streamId); | 192 | gbStreamMapper.del(app, streamId); |
src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorage.java
| @@ -2,7 +2,6 @@ package com.genersoft.iot.vmp.storager; | @@ -2,7 +2,6 @@ package com.genersoft.iot.vmp.storager; | ||
| 2 | 2 | ||
| 3 | import com.genersoft.iot.vmp.gb28181.bean.*; | 3 | import com.genersoft.iot.vmp.gb28181.bean.*; |
| 4 | import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem; | 4 | import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem; |
| 5 | -import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem; | ||
| 6 | import com.genersoft.iot.vmp.service.bean.GPSMsgInfo; | 5 | import com.genersoft.iot.vmp.service.bean.GPSMsgInfo; |
| 7 | import com.genersoft.iot.vmp.storager.dao.dto.ChannelSourceInfo; | 6 | import com.genersoft.iot.vmp.storager.dao.dto.ChannelSourceInfo; |
| 8 | import com.genersoft.iot.vmp.vmanager.gb28181.platform.bean.ChannelReduce; | 7 | import com.genersoft.iot.vmp.vmanager.gb28181.platform.bean.ChannelReduce; |
| @@ -330,6 +329,8 @@ public interface IVideoManagerStorage { | @@ -330,6 +329,8 @@ public interface IVideoManagerStorage { | ||
| 330 | */ | 329 | */ |
| 331 | boolean resetChannels(String deviceId, List<DeviceChannel> deviceChannelList); | 330 | boolean resetChannels(String deviceId, List<DeviceChannel> deviceChannelList); |
| 332 | 331 | ||
| 332 | + boolean updateChannels(String deviceId, List<DeviceChannel> deviceChannelList); | ||
| 333 | + | ||
| 333 | /** | 334 | /** |
| 334 | * 获取目录信息 | 335 | * 获取目录信息 |
| 335 | * @param platformId | 336 | * @param platformId |
src/main/java/com/genersoft/iot/vmp/storager/dao/UserMapper.java
| @@ -50,7 +50,7 @@ public interface UserMapper { | @@ -50,7 +50,7 @@ public interface UserMapper { | ||
| 50 | @ResultMap(value="roleMap") | 50 | @ResultMap(value="roleMap") |
| 51 | List<User> selectAll(); | 51 | List<User> selectAll(); |
| 52 | 52 | ||
| 53 | - @Select("select * from (select user.*, concat(#{callId}_', pushKey) as str1 from user) as u where md5(u.str1) = #{sign}") | 53 | + @Select("select * from (select user.*, concat(concat(#{callId}, '_'), pushKey) as str1 from user) as u where md5(u.str1) = #{sign}") |
| 54 | List<User> checkPushAuthorityByCallIdAndSign(String callId, String sign); | 54 | List<User> checkPushAuthorityByCallIdAndSign(String callId, String sign); |
| 55 | 55 | ||
| 56 | @Select("select * from user where md5(pushKey) = #{sign}") | 56 | @Select("select * from user where md5(pushKey) = #{sign}") |
src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStorageImpl.java
| @@ -194,6 +194,119 @@ public class VideoManagerStorageImpl implements IVideoManagerStorage { | @@ -194,6 +194,119 @@ public class VideoManagerStorageImpl implements IVideoManagerStorage { | ||
| 194 | 194 | ||
| 195 | } | 195 | } |
| 196 | 196 | ||
| 197 | + | ||
| 198 | + @Override | ||
| 199 | + public boolean updateChannels(String deviceId, List<DeviceChannel> deviceChannelList) { | ||
| 200 | + if (CollectionUtils.isEmpty(deviceChannelList)) { | ||
| 201 | + return false; | ||
| 202 | + } | ||
| 203 | + List<DeviceChannel> allChannels = deviceChannelMapper.queryAllChannels(deviceId); | ||
| 204 | + Map<String,DeviceChannel> allChannelMap = new ConcurrentHashMap<>(); | ||
| 205 | + if (allChannels.size() > 0) { | ||
| 206 | + for (DeviceChannel deviceChannel : allChannels) { | ||
| 207 | + allChannelMap.put(deviceChannel.getChannelId(), deviceChannel); | ||
| 208 | + } | ||
| 209 | + } | ||
| 210 | + List<DeviceChannel> addChannels = new ArrayList<>(); | ||
| 211 | + List<DeviceChannel> updateChannels = new ArrayList<>(); | ||
| 212 | + | ||
| 213 | + | ||
| 214 | + TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition); | ||
| 215 | + // 数据去重 | ||
| 216 | + StringBuilder stringBuilder = new StringBuilder(); | ||
| 217 | + Map<String, Integer> subContMap = new HashMap<>(); | ||
| 218 | + if (deviceChannelList.size() > 0) { | ||
| 219 | + // 数据去重 | ||
| 220 | + Set<String> gbIdSet = new HashSet<>(); | ||
| 221 | + for (DeviceChannel deviceChannel : deviceChannelList) { | ||
| 222 | + if (!gbIdSet.contains(deviceChannel.getChannelId())) { | ||
| 223 | + gbIdSet.add(deviceChannel.getChannelId()); | ||
| 224 | + if (allChannelMap.containsKey(deviceChannel.getChannelId())) { | ||
| 225 | + deviceChannel.setStreamId(allChannelMap.get(deviceChannel.getChannelId()).getStreamId()); | ||
| 226 | + deviceChannel.setHasAudio(allChannelMap.get(deviceChannel.getChannelId()).isHasAudio()); | ||
| 227 | + updateChannels.add(deviceChannel); | ||
| 228 | + }else { | ||
| 229 | + addChannels.add(deviceChannel); | ||
| 230 | + } | ||
| 231 | + if (!ObjectUtils.isEmpty(deviceChannel.getParentId())) { | ||
| 232 | + if (subContMap.get(deviceChannel.getParentId()) == null) { | ||
| 233 | + subContMap.put(deviceChannel.getParentId(), 1); | ||
| 234 | + }else { | ||
| 235 | + Integer count = subContMap.get(deviceChannel.getParentId()); | ||
| 236 | + subContMap.put(deviceChannel.getParentId(), count++); | ||
| 237 | + } | ||
| 238 | + } | ||
| 239 | + }else { | ||
| 240 | + stringBuilder.append(deviceChannel.getChannelId()).append(","); | ||
| 241 | + } | ||
| 242 | + } | ||
| 243 | + if (addChannels.size() > 0) { | ||
| 244 | + for (DeviceChannel channel : addChannels) { | ||
| 245 | + if (subContMap.get(channel.getChannelId()) != null){ | ||
| 246 | + channel.setSubCount(subContMap.get(channel.getChannelId())); | ||
| 247 | + } | ||
| 248 | + } | ||
| 249 | + } | ||
| 250 | + if (updateChannels.size() > 0) { | ||
| 251 | + for (DeviceChannel channel : updateChannels) { | ||
| 252 | + if (subContMap.get(channel.getChannelId()) != null){ | ||
| 253 | + channel.setSubCount(subContMap.get(channel.getChannelId())); | ||
| 254 | + } | ||
| 255 | + } | ||
| 256 | + } | ||
| 257 | + | ||
| 258 | + } | ||
| 259 | + if (stringBuilder.length() > 0) { | ||
| 260 | + logger.info("[目录查询]收到的数据存在重复: {}" , stringBuilder); | ||
| 261 | + } | ||
| 262 | + if(CollectionUtils.isEmpty(updateChannels) && CollectionUtils.isEmpty(addChannels) ){ | ||
| 263 | + logger.info("通道更新,数据为空={}" , deviceChannelList); | ||
| 264 | + return false; | ||
| 265 | + } | ||
| 266 | + try { | ||
| 267 | + int limitCount = 300; | ||
| 268 | + boolean result = false; | ||
| 269 | + if (addChannels.size() > 0) { | ||
| 270 | + if (addChannels.size() > limitCount) { | ||
| 271 | + for (int i = 0; i < addChannels.size(); i += limitCount) { | ||
| 272 | + int toIndex = i + limitCount; | ||
| 273 | + if (i + limitCount > addChannels.size()) { | ||
| 274 | + toIndex = addChannels.size(); | ||
| 275 | + } | ||
| 276 | + result = result || deviceChannelMapper.batchAdd(addChannels.subList(i, toIndex)) < 0; | ||
| 277 | + } | ||
| 278 | + }else { | ||
| 279 | + result = result || deviceChannelMapper.batchAdd(addChannels) < 0; | ||
| 280 | + } | ||
| 281 | + } | ||
| 282 | + if (updateChannels.size() > 0) { | ||
| 283 | + if (updateChannels.size() > limitCount) { | ||
| 284 | + for (int i = 0; i < updateChannels.size(); i += limitCount) { | ||
| 285 | + int toIndex = i + limitCount; | ||
| 286 | + if (i + limitCount > updateChannels.size()) { | ||
| 287 | + toIndex = updateChannels.size(); | ||
| 288 | + } | ||
| 289 | + result = result || deviceChannelMapper.batchUpdate(updateChannels.subList(i, toIndex)) < 0; | ||
| 290 | + } | ||
| 291 | + }else { | ||
| 292 | + result = result || deviceChannelMapper.batchUpdate(updateChannels) < 0; | ||
| 293 | + } | ||
| 294 | + } | ||
| 295 | + if (result) { | ||
| 296 | + //事务回滚 | ||
| 297 | + dataSourceTransactionManager.rollback(transactionStatus); | ||
| 298 | + }else { | ||
| 299 | + //手动提交 | ||
| 300 | + dataSourceTransactionManager.commit(transactionStatus); | ||
| 301 | + } | ||
| 302 | + return true; | ||
| 303 | + }catch (Exception e) { | ||
| 304 | + e.printStackTrace(); | ||
| 305 | + dataSourceTransactionManager.rollback(transactionStatus); | ||
| 306 | + return false; | ||
| 307 | + } | ||
| 308 | + } | ||
| 309 | + | ||
| 197 | @Override | 310 | @Override |
| 198 | public void deviceChannelOnline(String deviceId, String channelId) { | 311 | public void deviceChannelOnline(String deviceId, String channelId) { |
| 199 | deviceChannelMapper.online(deviceId, channelId); | 312 | deviceChannelMapper.online(deviceId, channelId); |
src/main/java/com/genersoft/iot/vmp/utils/redis/RedisUtil.java
| 1 | package com.genersoft.iot.vmp.utils.redis; | 1 | package com.genersoft.iot.vmp.utils.redis; |
| 2 | 2 | ||
| 3 | -import java.util.*; | ||
| 4 | -import java.util.concurrent.TimeUnit; | ||
| 5 | - | ||
| 6 | import com.alibaba.fastjson2.JSONObject; | 3 | import com.alibaba.fastjson2.JSONObject; |
| 7 | import com.genersoft.iot.vmp.utils.SpringBeanFactory; | 4 | import com.genersoft.iot.vmp.utils.SpringBeanFactory; |
| 8 | -import gov.nist.javax.sip.stack.UDPMessageChannel; | ||
| 9 | import org.springframework.data.redis.core.*; | 5 | import org.springframework.data.redis.core.*; |
| 10 | import org.springframework.util.CollectionUtils; | 6 | import org.springframework.util.CollectionUtils; |
| 11 | 7 | ||
| 8 | +import java.util.*; | ||
| 9 | +import java.util.concurrent.TimeUnit; | ||
| 10 | + | ||
| 12 | /** | 11 | /** |
| 13 | * Redis工具类 | 12 | * Redis工具类 |
| 14 | * @author swwheihei | 13 | * @author swwheihei |
src/main/java/com/genersoft/iot/vmp/vmanager/user/UserController.java
| @@ -11,17 +11,13 @@ import com.genersoft.iot.vmp.utils.DateUtil; | @@ -11,17 +11,13 @@ import com.genersoft.iot.vmp.utils.DateUtil; | ||
| 11 | import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; | 11 | import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; |
| 12 | import com.genersoft.iot.vmp.vmanager.bean.WVPResult; | 12 | import com.genersoft.iot.vmp.vmanager.bean.WVPResult; |
| 13 | import com.github.pagehelper.PageInfo; | 13 | import com.github.pagehelper.PageInfo; |
| 14 | - | ||
| 15 | import io.swagger.v3.oas.annotations.Operation; | 14 | import io.swagger.v3.oas.annotations.Operation; |
| 16 | import io.swagger.v3.oas.annotations.Parameter; | 15 | import io.swagger.v3.oas.annotations.Parameter; |
| 17 | import io.swagger.v3.oas.annotations.tags.Tag; | 16 | import io.swagger.v3.oas.annotations.tags.Tag; |
| 18 | import org.springframework.beans.factory.annotation.Autowired; | 17 | import org.springframework.beans.factory.annotation.Autowired; |
| 19 | -import org.springframework.http.HttpStatus; | ||
| 20 | -import org.springframework.http.ResponseEntity; | ||
| 21 | import org.springframework.security.authentication.AuthenticationManager; | 18 | import org.springframework.security.authentication.AuthenticationManager; |
| 22 | import org.springframework.util.DigestUtils; | 19 | import org.springframework.util.DigestUtils; |
| 23 | import org.springframework.util.ObjectUtils; | 20 | import org.springframework.util.ObjectUtils; |
| 24 | -import org.springframework.util.StringUtils; | ||
| 25 | import org.springframework.web.bind.annotation.*; | 21 | import org.springframework.web.bind.annotation.*; |
| 26 | 22 | ||
| 27 | import javax.security.sasl.AuthenticationException; | 23 | import javax.security.sasl.AuthenticationException; |
| @@ -90,7 +86,7 @@ public class UserController { | @@ -90,7 +86,7 @@ public class UserController { | ||
| 90 | 86 | ||
| 91 | 87 | ||
| 92 | @PostMapping("/add") | 88 | @PostMapping("/add") |
| 93 | - @Operation(summary = "停止视频回放") | 89 | + @Operation(summary = "添加用户") |
| 94 | @Parameter(name = "username", description = "用户名", required = true) | 90 | @Parameter(name = "username", description = "用户名", required = true) |
| 95 | @Parameter(name = "password", description = "密码(未md5加密的密码)", required = true) | 91 | @Parameter(name = "password", description = "密码(未md5加密的密码)", required = true) |
| 96 | @Parameter(name = "roleId", description = "角色ID", required = true) | 92 | @Parameter(name = "roleId", description = "角色ID", required = true) |
src/main/resources/all-application.yml
| @@ -168,7 +168,7 @@ user-settings: | @@ -168,7 +168,7 @@ user-settings: | ||
| 168 | # 保存移动位置历史轨迹:true:保留历史数据,false:仅保留最后的位置(默认) | 168 | # 保存移动位置历史轨迹:true:保留历史数据,false:仅保留最后的位置(默认) |
| 169 | save-position-history: false | 169 | save-position-history: false |
| 170 | # 点播等待超时时间,单位:毫秒 | 170 | # 点播等待超时时间,单位:毫秒 |
| 171 | - play-timeout: 3000 | 171 | + play-timeout: 18000 |
| 172 | # 上级点播等待超时时间,单位:毫秒 | 172 | # 上级点播等待超时时间,单位:毫秒 |
| 173 | platform-play-timeout: 60000 | 173 | platform-play-timeout: 60000 |
| 174 | # 是否开启接口鉴权 | 174 | # 是否开启接口鉴权 |
web_src/src/components/GBRecordDetail.vue
| @@ -181,7 +181,6 @@ | @@ -181,7 +181,6 @@ | ||
| 181 | this.recordListStyle.height = this.winHeight + "px"; | 181 | this.recordListStyle.height = this.winHeight + "px"; |
| 182 | this.playerStyle["height"] = this.winHeight + "px"; | 182 | this.playerStyle["height"] = this.winHeight + "px"; |
| 183 | this.chooseDate = moment().format('YYYY-MM-DD') | 183 | this.chooseDate = moment().format('YYYY-MM-DD') |
| 184 | - this.setTime(this.chooseDate + " 00:00:00", this.chooseDate + " 23:59:59"); | ||
| 185 | this.dateChange(); | 184 | this.dateChange(); |
| 186 | }, | 185 | }, |
| 187 | destroyed() { | 186 | destroyed() { |
| @@ -192,6 +191,8 @@ | @@ -192,6 +191,8 @@ | ||
| 192 | if (!this.chooseDate) { | 191 | if (!this.chooseDate) { |
| 193 | return; | 192 | return; |
| 194 | } | 193 | } |
| 194 | + | ||
| 195 | + this.setTime(this.chooseDate + " 00:00:00", this.chooseDate + " 23:59:59"); | ||
| 195 | this.recordsLoading = true; | 196 | this.recordsLoading = true; |
| 196 | this.detailFiles = []; | 197 | this.detailFiles = []; |
| 197 | this.$axios({ | 198 | this.$axios({ |