Compare commits

...

429 Commits

Author SHA1 Message Date
lin
9941608207 写入第三方同步的别名信息 2025-09-27 21:10:58 +08:00
lin
77594dae3d 支持从第三方同步分组信息 2025-09-27 21:03:20 +08:00
lin
4280a1d08e 移除自定义的是否支持云台属性 2025-09-26 17:31:37 +08:00
lin
8d6fe0c9d8 优化地图展示流程,已经默认统一坐标为wgs84 2025-09-25 18:06:58 +08:00
lin
6469aefe22 支持从第三方读取地图配置 2025-09-25 15:27:30 +08:00
lin
bee911fa09 通道增加自定义属性 是否支持云台控制和是否支持语音对讲 2025-09-24 17:47:12 +08:00
lin
554a11ead6 移除多余接口 2025-09-24 16:36:33 +08:00
lin
c0ef35c3a0 支持通用通道云台控制,支持地图位置编辑 2025-09-24 16:21:02 +08:00
lin
602cd390e0 去除部分警告 2025-09-24 11:40:31 +08:00
lin
842647674a 升级spring boot版本。默认jdk版本升级至21 2025-09-24 10:24:42 +08:00
lin
1156880194 Merge branch 'master' into dev/springBoot3
# Conflicts:
#	src/main/java/com/genersoft/iot/vmp/gb28181/controller/MediaController.java
#	src/main/java/com/genersoft/iot/vmp/jt1078/config/JT1078Controller.java
2025-09-24 08:38:29 +08:00
lin
dd2f99487d 优化播放效果 2025-09-23 23:27:42 +08:00
lin
3009951e45 优化播放效果 2025-09-23 23:07:36 +08:00
lin
0ed37d58ec 完善录像回放播放器切换 2025-09-23 18:04:30 +08:00
lin
e7d26b34b3 Merge branch 'dev/test' into dev/abl功能完善
# Conflicts:
#	web/src/views/cloudRecord/detail.vue
2025-09-23 16:18:46 +08:00
lin
f7eea28951 临时提交 2025-09-23 14:32:14 +08:00
lin
a706069e97 完善h265web seek 2025-09-22 23:30:09 +08:00
lin
3a594f7bee 优化abl云端录像播放效果 2025-09-22 14:31:04 +08:00
lin
15ff87a323 修复云端录像播放页面 2025-09-21 22:51:04 +08:00
lin
9edbcd9768 完善新的云端录像播放界面 2025-09-20 15:48:17 +08:00
lin
a2ac65dc70 zlm适配新的云端录像播放界面 2025-09-19 23:52:24 +08:00
lin
ff0d54968d zlm适配新的云端录像播放界面 2025-09-19 22:55:44 +08:00
lin
af3a283b3d 适配abl新的端口命名 2025-09-19 20:48:41 +08:00
lin
fd306d8ede 云端录像回放使用单文件播放 2025-09-19 18:02:53 +08:00
lin
a064f27bf8 支持ABL风格地址 2025-09-18 18:53:12 +08:00
lin
fb9ff67701 支持ABL录像回放 2025-09-17 18:19:33 +08:00
lin
403e7648f9 优化ABL结果封装完成 2025-09-16 17:57:59 +08:00
lin
c1672728d3 优化zlm结果封装完成 2025-09-16 10:52:58 +08:00
lin
576feec514 临时提交 2025-09-15 18:01:00 +08:00
lin
5c83bf2a41 临时提交 2025-09-15 17:59:18 +08:00
lin
d96faa2459 Merge remote-tracking branch 'origin/master' 2025-09-12 10:35:36 +08:00
lin
27c7969b8f 更新README 2025-09-12 10:35:24 +08:00
648540858
784c94cce8
Merge pull request #1971 from ShuiFan0/docker
确保Docker里的国标全流程与录像的可用
2025-09-11 10:23:28 +08:00
氵帆
6ae7bdc8e0 增加遗漏的端口,修复文件编码问题,增加打包推送脚本,增加说明文档 2025-09-09 18:02:00 +08:00
氵帆
752ee1c290 docker里的录像也能正常看了 2025-09-08 16:56:31 +08:00
lin
18be8aff6c abl 支持拉流代理 2025-09-08 16:09:01 +08:00
氵帆
f0f62fa675 能在Docker一键跑完大致流程 2025-09-08 13:36:27 +08:00
648540858
6ebeef33ae
Merge pull request #1969 from ShuiFan0/docker
实现docker的开箱即用
2025-09-05 09:22:00 +08:00
氵帆
021e7a908f 实现docker的开箱即用 2025-09-04 14:52:25 +08:00
648540858
fed14aded4
Merge pull request #1967 from Fdikc/patch-1
Update PlatformServiceImpl.java 平台级联删除
2025-09-04 09:08:17 +08:00
Dylan
dc5a66753c
Update PlatformServiceImpl.java 平台级联删除
平台级联删除
2025-09-03 19:26:05 +08:00
lin
04742531fc 修复推流列表在使用postgresql时查询失败 #1809 2025-08-27 10:01:22 +08:00
lin
5db66b0f40 修复分组信息缺少的行政区划编码 #1914 2025-08-27 09:56:50 +08:00
lin
416dac382e 修复离线失败 #1944 2025-08-25 15:44:18 +08:00
lin
dfba1840e3 推流数据导入完善异常提示 2025-08-15 17:03:31 +08:00
lin
6f577268ee 适配新版本zlm限流配置 2025-08-15 09:50:45 +08:00
lin
93724bac98 修复预置位查询空指针 2025-08-12 12:28:51 +08:00
lin
83662f4210 修复数据库索引重复 2025-08-12 11:36:23 +08:00
648540858
c11da964e2
Merge pull request #1946 from sxh-nice/master
修复GB28181预置位查询只能返回10条数据BUG
2025-08-10 10:15:55 +08:00
yosixiaohu
2877d67e92 修复GB28181预置位查询只能返回10条数据BUG 2025-08-09 11:14:39 +08:00
lin
56d4e1ebd9 调整抓拍代码 2025-08-08 10:38:38 +08:00
lin
e7d1a24f3e 修复部标通道中国标编辑的BUG 2025-08-08 08:55:28 +08:00
lin
ed00a2a75a 修复部标通道中国标编辑的BUG 2025-08-07 19:34:10 +08:00
lin
1702907573 修复全量脚本缺失的字段 2025-08-07 18:13:44 +08:00
lin
fad9f2954a 增加配置,修复添加部标设备异常 2025-08-07 17:52:06 +08:00
lin
45509372bd 修复过期时间设置异常 2025-08-07 17:31:51 +08:00
lin
5c25385d29 更新README 2025-08-07 16:35:09 +08:00
lin
1da487f02a [1078] 优化鉴权码位置,支持1078国标级联 2025-08-06 15:17:44 +08:00
lin
e555df52d3 [1078] 通用通道支持位置更新 2025-08-06 06:38:37 +08:00
lin
c90836261a [1078] 增加状态变化通知和位置事件 2025-08-05 18:05:18 +08:00
lin
d7f5e7d771 [1078] 通用通道录像回放支持 2025-08-03 17:20:24 +08:00
lin
0a19ce4f34 [1078] 临时提交 2025-08-01 19:45:40 +08:00
lin
efbd302260 Merge branch 'master' into 重构/1078 2025-08-01 19:00:13 +08:00
lin
09f1ef20a7 通用通道支持录像回放以及录像控制 2025-08-01 18:59:15 +08:00
lin
c75122008c 通用通道支持停止实时流 2025-08-01 15:58:30 +08:00
lin
e272d25939 [1078] 适配新结构接入通用通道支持云台控制 2025-08-01 14:39:33 +08:00
lin
2ee9a3fa71 [1078] 适配新结构接入通用通道 2025-07-31 21:21:31 +08:00
lin
333965255f Merge branch 'master' into 重构/1078
# Conflicts:
#	src/main/java/com/genersoft/iot/vmp/common/enums/ChannelDataType.java
#	src/main/java/com/genersoft/iot/vmp/gb28181/service/IGbChannelPlayService.java
#	src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/GbChannelPlayServiceImpl.java
2025-07-31 21:14:23 +08:00
lin
3f6264cad9 通用通道支持辅助开关、雨刷、自动扫描 2025-07-31 20:59:57 +08:00
lin
8ec950d515 通用通道支持巡航组 2025-07-31 20:54:08 +08:00
lin
9614584219 通用通道支持预置位调用,删除, 增加 2025-07-31 19:05:07 +08:00
lin
19b873ba5c 通用通道支持云台控制 2025-07-31 18:49:53 +08:00
lin
edeb8d6b3f 临时提交 2025-07-30 18:02:49 +08:00
lin
61a761e288 [1078] 修改颜色 2025-07-30 18:02:29 +08:00
lin
867b26b9a8 Merge branch 'master' into dev/通用通道云台控制 2025-07-30 10:34:58 +08:00
lin
24417203f0 修复前端布防撤防调用失败 2025-07-30 10:22:51 +08:00
lin
f3bd58acfe [1078] FTP使用随机用户和密码 2025-07-29 19:34:33 +08:00
lin
9e880786b3 [1078] 去除ftp配置中的ip配置 从连接中获取 2025-07-29 18:40:03 +08:00
648540858
d51de48923
Merge pull request #1933 from elpx/master
修改ip与port的拼接方式,以支持ipv6
2025-07-29 16:46:30 +08:00
lin
0ed395ff2e [1078] 支持通用通道的点播 2025-07-29 14:46:16 +08:00
elpx
3cec9d2bd1 修改ip与port的拼接方式,以支持ipv6 2025-07-28 23:57:16 +08:00
648540858
ed2f104529
Merge pull request #1931 from linwumingshi/fix/download-url
fix: 🐛 修复云录像下载链接中的格式化问题
2025-07-28 22:15:29 +08:00
lin
4c97022c78 [1078] 支持语音对讲 中心广播模式 2025-07-28 17:50:03 +08:00
linwumingshi
1693d904c4 fix: 🐛 修复云录像下载链接中的格式化问题
- 更新了 CloudRecordUtils 类,使其使用 UtilityClass 注解
- 优化了 getDownloadFilePath 方法,将文件路径作为独立参数传入
- 修复了原始实现中可能导致路径格式错误的问题
- 增加了方法注释,说明其功能和参数
2025-07-28 17:38:54 +08:00
648540858
c2d42d67c0
Merge pull request #1929 from XiaoQiTong/wvp-28181-2.0
修复一些实际使用中的bug
2025-07-28 14:58:15 +08:00
lin
4fb04776f2 [1078] 代码整理 2025-07-28 14:32:38 +08:00
韩浩然XiaoQiTong
65553e966e
Update SIPCommander.java 2025-07-28 10:29:47 +08:00
lin
e9eeeeefd7 Merge branch 'master' into 重构/1078 2025-07-28 08:47:30 +08:00
648540858
49578e884f
Merge pull request #1928 from meqbyte/master
jwt剩余时间计算错误
2025-07-28 08:32:24 +08:00
XiaoQiTong
e9c227a3cf 修复查询缓存少流媒体字段,导致指定流媒体收流失效问题 2025-07-27 16:29:00 +08:00
XiaoQiTong
3b1a6b4903 修复部分子码流指定问题,修复修改单个通道码流会全部修改的bug 2025-07-27 16:26:56 +08:00
XiaoQiTong
f9f9d03502 修复预置位查询指令海康平台响应不了的问题 2025-07-27 16:22:50 +08:00
XiaoQiTong
47571962e6 解决获取所有预置位返回错误的bug 2025-07-27 16:19:57 +08:00
lin
a79429115f [1078] 增加功能入口 2025-07-25 18:05:22 +08:00
lin
34fb79093e [1078] 完善立即拍摄的结果查询和下载 2025-07-25 17:49:22 +08:00
meqbyte
305c8ec8d7 jwt剩余时间计算错误 2025-07-25 15:59:59 +08:00
lin
43ef080f55 [1078] 增加立即拍摄 2025-07-25 15:37:03 +08:00
lin
ee52b43c99 [1078] 增加多媒体文件检索 2025-07-23 23:30:48 +08:00
lin
4cc399ce39 [1078] 增加设置电话本 2025-07-23 20:58:23 +08:00
lin
a69e3d5dde [1078] 增加音视频属性查询 2025-07-22 20:56:32 +08:00
lin
c0ab010475 [1078] 增加音视频属性查询 2025-07-22 20:51:03 +08:00
lin
79ee116174 [1078] 优化netty bytebuf释放 2025-07-22 10:02:32 +08:00
lin
045c14da0d [1078] 完善终端参数 2025-07-22 06:50:55 +08:00
lin
0c78a9460b [1078] 完善终端参数 2025-07-22 06:47:28 +08:00
lin
6e5cadd32b [1078] 去除多余选项 2025-07-22 06:14:30 +08:00
lin
fb150da97a [1078] 完善终端参数 2025-07-22 06:05:20 +08:00
lin
a4e20f0f50 [1078] 优化终端参数查询和设置 2025-07-21 18:01:44 +08:00
lin
9388c279e7 [1078] 补充终端参数 2025-07-21 17:48:02 +08:00
lin
03b5c0241f [1078] 优化终端参数查询和设置 2025-07-21 10:35:30 +08:00
lin
a60eb082fe [1078] 临时提交 2025-07-20 23:05:49 +08:00
lin
9d0678f765 [1078] 修复终端参数保存 2025-07-20 22:56:33 +08:00
lin
9b0d091e4e [1078] 优化终端参数查询和设置 2025-07-18 17:34:01 +08:00
lin
ebd95250c0 [1078] 增加车辆控制 2025-07-17 15:53:35 +08:00
lin
47e4f2343b [1078] 增加连接到指定服务器 2025-07-17 15:12:23 +08:00
lin
f7b35e8e14 [1078] 增加恢复出厂和终端复位 2025-07-17 13:03:23 +08:00
lin
8b17e97682 [1078] 增加驾驶员信息 2025-07-17 12:56:07 +08:00
lin
e730bf2d15 [1078] 修复mediaServer入库错误 2025-07-17 07:03:11 +08:00
lin
ca07935232 [1078] 增加电话回拨 2025-07-16 21:57:26 +08:00
lin
56b70d335a [1078] 增加文本下发 2025-07-16 18:23:34 +08:00
lin
29802ccded [1078] 增加文本下发 2025-07-16 18:22:33 +08:00
lin
3f2089f584 [1078] 增加位置信息展示 2025-07-16 16:02:07 +08:00
lin
45af124eb0 [1078] 支持终端属性和链路检测的UI 2025-07-16 11:00:43 +08:00
lin
5874d4d1fa [1078] 修复webrtc地址 2025-07-15 18:37:53 +08:00
lin
d40bc5a034 [1078] 设备列表增加搜索和状态筛选 2025-07-15 18:21:11 +08:00
lin
44ed06bcbe [1078] 支持无人观看自动停流 2025-07-15 18:11:23 +08:00
lin
be04660de8 [1078] 修复分包合并,优化设备列表排序,优化设备上线逻辑 2025-07-15 16:30:34 +08:00
lin
e28141da6e [1078] 临时提交 2025-07-14 18:06:18 +08:00
lin
04bcb6dcb8 [1078] 优化多媒体数据上传处理 2025-07-14 11:03:45 +08:00
lin
9d47fe30f5 [1078] 增加单条存储多媒体数据上传 2025-07-11 22:07:32 +08:00
lin
cefc87ad47 [1078] 完善抓图 2025-07-11 21:41:50 +08:00
lin
8c3e9320fa [1078] 增加抓图 2025-07-11 20:15:45 +08:00
lin
b7a2b6816b [1078] 完善录像下载 2025-07-10 18:48:25 +08:00
648540858
569b361a43 调整打包命名 2025-07-09 22:51:24 +08:00
648540858
16fd1db833 调整打包命名 2025-07-09 22:43:36 +08:00
lin
9c2c727c8c 调整打包时配置文件名称 2025-07-09 20:17:38 +08:00
648540858
42635592c6
Merge pull request #1908 from cuteLittleDevil/feat_github_action
添加github action打包功能
2025-07-09 19:53:38 +08:00
lin
1655e5903b [1078] 完善录像回放 2025-07-09 16:44:54 +08:00
lin
055bbc2dca [1078] 修复回放结束发送失败 2025-07-09 16:37:33 +08:00
lin
3c6b715ce1 [1078] 临时提交 2025-07-09 16:16:04 +08:00
lin
3d9e718f26 临时提交 2025-07-09 14:58:26 +08:00
CDCDDCDC
67ef8ed8f0 修改github action打包压缩包文件名 2025-07-09 12:46:31 +08:00
lin
48eff320fd [1078] 适配abl的播放1078 2025-07-09 12:32:31 +08:00
CDCDDCDC
8f2b107eab 添加github action打包功能 2025-07-08 19:46:17 +08:00
lin
3c88f86a73 Merge branch 'master' into dev/通用通道云台控制 2025-07-07 18:03:39 +08:00
lin
4765d0efa6 调整国标级联通道发送逻辑 2025-07-07 17:56:06 +08:00
lin
17c967ed4e [1078] 修复标签显示错误 2025-07-07 17:42:08 +08:00
lin
fae839af05 [1078] 兼容2013版本的设备属性查询和注册鉴权 2025-07-07 17:23:12 +08:00
lin
70356c08d2 调整国标级联通道发送逻辑 2025-07-07 16:17:14 +08:00
lin
93c24a74e6 Merge branch 'master' into 重构/1078 2025-07-07 11:46:13 +08:00
lin
51759535fc 临时提交 2025-07-07 09:30:04 +08:00
lin
51cd14e02e 行政区划或者业务分组添加通道后更新右边数据 2025-07-04 14:36:11 +08:00
lin
eddf20e62a 修复业务分组右键添加设备BUG 2025-07-04 14:21:56 +08:00
lin
a424f270e8 [1078] 兼容abl流媒体 2025-07-03 17:30:59 +08:00
lin
1bfb51c90e Merge branch 'dev/abl支持' into 重构/1078
# Conflicts:
#	src/main/resources/application.yml
2025-07-03 15:29:13 +08:00
lin
5bcdf5dfb6 [abl] 合并主线 2025-07-03 15:28:47 +08:00
lin
bab5534134 Merge branch 'master' into dev/abl支持
# Conflicts:
#	src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/MediaStatusNotifyMessageHandler.java
#	src/main/java/com/genersoft/iot/vmp/media/bean/MediaInfo.java
#	src/main/java/com/genersoft/iot/vmp/media/bean/MediaServer.java
#	src/main/java/com/genersoft/iot/vmp/media/bean/RecordInfo.java
#	src/main/java/com/genersoft/iot/vmp/service/bean/CloudRecordItem.java
#	src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java
#	src/main/java/com/genersoft/iot/vmp/storager/dao/CloudRecordServiceMapper.java
#	src/main/resources/application.yml
2025-07-03 14:58:24 +08:00
lin
537d86ca89 [1078] 合并主线 2025-07-03 14:54:29 +08:00
lin
465e03d15d Merge branch 'master' into 重构/1078
# Conflicts:
#	web/src/router/index.js
#	web/src/views/common/channelPlayer/chooseChannelForJt.vue
#	web/src/views/common/channelPlayer/jtDeviceEdit.vue
#	web/src/views/common/channelPlayer/jtDevicePlayer.vue
#	web_src/src/layout/UiHeader.vue
#	web_src/src/main.js
#	web_src/src/router/index.js
2025-07-03 09:41:55 +08:00
lin
c79b7a9743 更新README和文档 2025-07-03 06:45:14 +08:00
lin
8d488b33e9 调整菜单结构,增加通道列表,支持节点搜索 2025-07-02 17:21:20 +08:00
lin
e194c027cb 推流列表新增推流地址生成 2025-07-01 23:36:10 +08:00
lin
f8e5e8f057 优化拉流代理播放机制 2025-07-01 17:07:10 +08:00
lin
9e8fbea73b 支持zlm pro截图方式 2025-06-30 17:16:25 +08:00
lin
0d6ed0a71e 更新README 2025-06-30 10:24:06 +08:00
lin
54f6ff9f81 修复拉流代理转国标级联点播失败的BUG 2025-06-27 15:32:02 +08:00
648540858
5f4d78fe8f
Merge pull request #1900 from xiaoQQya/master
控制台新增国标收流通道列表查看弹窗
2025-06-26 14:09:27 +08:00
xiaoQQya
2b66404a2a fix: 修复国标收流列表播放按钮 loading 不生效问题 2025-06-26 13:24:15 +08:00
xiaoQQya
380c42040f fix: 修复国标收流列表关闭再打开时未刷新数据问题 2025-06-26 12:53:22 +08:00
xiaoQQya
1c25f2f190 feat: 新增国标收流通道列表查看 2025-06-26 11:46:14 +08:00
lin
d9b750dc50 补充丢失的文件 2025-06-26 11:05:39 +08:00
lin
d507d075b1 补充丢失的文件 2025-06-26 11:05:34 +08:00
648540858
592b1799e7
Merge pull request #1897 from xiaoQQya/master
修复登录页背景图加载失败问题
2025-06-26 07:05:05 +08:00
xiaoQQya
8c7b8eaeba perf: 登录状态持久化 2025-06-25 10:20:48 +08:00
xiaoQQya
6659779d91 fix: 修复登录页背景图加载失败问题 2025-06-25 10:19:57 +08:00
lin
b2000cba9a 更新README 2025-06-20 14:23:37 +08:00
lin
b5ca5feeea 优化登录页背景图加载速度 2025-06-19 15:51:49 +08:00
lin
1c55bc3fd1 预置位查询支持多段返回 2025-06-19 15:12:47 +08:00
lin
50df430831 修复对象解构时括号间距不一致的问题 2025-06-17 09:42:41 +08:00
648540858
371511f836
Merge pull request #1891 from q792602257/h2
支持h2数据库
2025-06-14 20:20:32 +08:00
Jerry Yan
eada4a64dc Merge branch 'boot3' into h2
# Conflicts:
#	src/main/resources/application-dev.yml
2025-06-13 16:41:32 +08:00
648540858
196ecad3a3
Merge pull request #1889 from q792602257/boot3
升级至SpringBoot3
2025-06-13 09:28:20 +08:00
648540858
d9b7be4814
Merge pull request #1887 from q792602257/date_header
支持关闭返回Date Header,进而实现关闭对摄像头的校时功能
2025-06-13 09:06:59 +08:00
Jerry Yan
1b35fbd0e0 支持关闭返回Date Header,进而实现关闭对摄像头的校时功能
Fixes #1700
2025-06-12 16:05:06 +08:00
Jerry Yan
2657d61c08 修复SpringSecurity 2025-06-12 09:50:29 +08:00
Jerry Yan
5aaa1c016b 即将过期状态判断错误 2025-06-12 09:50:29 +08:00
Jerry Yan
a948b78629 接口请求修复 2025-06-12 09:50:29 +08:00
Jerry Yan
f4ba4ef159 knife4j文档更新 2025-06-12 09:50:29 +08:00
Jerry Yan
8848de9d15 支持h2数据库 2025-06-11 12:54:45 +08:00
Jerry Yan
44bd521446 spring redis 新配置风格 2025-06-11 10:08:03 +08:00
Jerry Yan
14c85838f4 springboot3 2025-06-11 10:08:03 +08:00
lin
d15307533a Merge branch 'master' into 重构/1078
# Conflicts:
#	src/main/resources/application.yml
2025-06-03 17:21:21 +08:00
lin
1420fcfcd0 Merge branch 'master' into 重构/1078
# Conflicts:
#	src/main/java/com/genersoft/iot/vmp/service/bean/InviteErrorCode.java
#	src/main/resources/application.yml
2025-05-29 17:10:32 +08:00
lin
0c29c90d3b Merge branch 'master' into 重构/1078 2025-05-26 15:07:58 +08:00
lin
420b3889c5 [1078] 合并新UI 2025-05-16 15:17:35 +08:00
lin
7c5cee5d87 Merge branch 'refs/heads/master' into dev/1078-newUI 2025-05-16 11:03:40 +08:00
lin
27d7f3cc6e Merge branch 'master' into dev/1078-newUI 2025-05-16 08:50:26 +08:00
lin
592c1c2b71 [1078] 合并新UI 2025-05-15 18:32:03 +08:00
lin
5b89145337 增加接入信息展示 2025-05-15 10:28:02 +08:00
lin
6a2ecd937d Merge branch 'refs/heads/master' into dev/1078-newUI 2025-05-15 10:25:07 +08:00
lin
98e6cfcc4c Merge branch 'master' into dev/1078-newUI 2025-05-15 10:00:40 +08:00
lin
081a146f2a [1078] 合并新UI 2025-05-14 18:01:12 +08:00
648540858
68f7d3ef74 [1078] 适配新UI 2025-05-14 15:48:35 +08:00
648540858
1a7f517c5a Merge branch 'refs/heads/master' into dev/1078-newUI 2025-05-13 21:22:01 +08:00
lin
e4a0a37f0b [1078] 合并新UI 2025-05-12 18:01:10 +08:00
648540858
c4ab55a456 [部标1078] 适配新UI 2025-05-11 08:01:45 +08:00
648540858
10c75036f5 Merge branch 'master' into dev/1078-newUI 2025-05-11 07:00:10 +08:00
648540858
3b7ba3eb46 Merge branch 'master' into dev/1078-newUI
# Conflicts:
#	src/main/resources/application.yml
2025-05-10 08:59:45 +08:00
648540858
e754d0d804 [1078] 去除测试程序中的调用错误 2025-04-24 22:39:15 +08:00
lin
e284c3857c Merge branch 'master' into 重构/1078 2025-04-09 12:17:22 +08:00
lin
f0eb101130 [1078] 适配新的数据库结构 2025-03-24 17:53:43 +08:00
lin
fd5079a652 Merge branch 'refs/heads/master' into 重构/1078 2025-03-24 17:28:43 +08:00
lin
20135726eb Merge branch 'master' into 重构/1078 2025-03-24 15:19:07 +08:00
lin
242062bda3 [1078] 合并主线 2025-03-18 16:35:40 +08:00
lin
0329c8f5d1 Merge remote-tracking branch 'origin/master' into 重构/1078
# Conflicts:
#	src/main/java/com/genersoft/iot/vmp/gb28181/dao/CommonGBChannelMapper.java
#	src/main/java/com/genersoft/iot/vmp/gb28181/dao/PlatformChannelMapper.java
#	src/main/java/com/genersoft/iot/vmp/gb28181/dao/provider/ChannelProvider.java
#	src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/DeviceChannelServiceImpl.java
#	数据库/2.7.3/初始化-mysql-2.7.3.sql
#	数据库/2.7.3/初始化-postgresql-kingbase-2.7.3.sql
2025-03-18 15:30:35 +08:00
648540858
51f126e571 Merge branch 'master' into 重构/1078
# Conflicts:
#	src/main/java/com/genersoft/iot/vmp/service/impl/MediaServiceImpl.java
#	数据库/2.7.3/初始化-mysql-2.7.3.sql
#	数据库/2.7.3/初始化-postgresql-kingbase-2.7.3.sql
2024-12-19 23:19:09 +08:00
648540858
4e48eb6cab 修复添加通道时未设置设备ID 2024-12-09 14:41:14 +08:00
648540858
1323d081e8 Merge remote-tracking branch 'origin/重构/1078' into 重构/1078 2024-12-05 11:06:06 +08:00
648540858
f528735119 Merge branch 'master' into 重构/1078 2024-12-05 11:05:44 +08:00
648540858
d3d7ea8fbb 合并主线通道编辑样式 2024-11-15 23:14:37 +08:00
648540858
991dd0ea41 合并主线云台控制页面样式 2024-11-15 22:31:06 +08:00
648540858
1dfbb875b2 Merge branch 'master' into 重构/1078 2024-11-15 21:45:40 +08:00
648540858
a4ca333abb 合并主线 2024-11-10 22:09:13 +08:00
648540858
e5fd66ef96 Merge branch 'master' into 重构/1078
# Conflicts:
#	pom.xml
#	src/main/java/com/genersoft/iot/vmp/conf/SpringDocConfig.java
#	src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/DeviceChannelServiceImpl.java
#	src/main/java/com/genersoft/iot/vmp/service/impl/MediaServiceImpl.java
2024-11-10 15:29:53 +08:00
648540858
556f0ebf2f 临时提交 2024-10-29 22:11:46 +08:00
648540858
13b896ce23 修复启动异常 2024-10-21 06:57:53 +08:00
648540858
f62b655602 合并主线 2024-10-19 19:59:14 +08:00
648540858
46fa390387 临时提交 2024-10-19 00:04:32 +08:00
648540858
277f2db137 Merge branch 'master' into 重构/1078
# Conflicts:
#	pom.xml
#	src/main/java/com/genersoft/iot/vmp/gb28181/bean/CommonGBChannel.java
#	src/main/java/com/genersoft/iot/vmp/jt1078/codec/decode/Jt808Decoder.java
#	src/main/java/com/genersoft/iot/vmp/jt1078/codec/netty/Jt808Handler.java
#	src/main/java/com/genersoft/iot/vmp/jt1078/codec/netty/TcpServer.java
#	src/main/java/com/genersoft/iot/vmp/jt1078/proc/request/Re.java
#	src/main/java/com/genersoft/iot/vmp/media/service/IMediaNodeServerService.java
#	src/main/java/com/genersoft/iot/vmp/media/service/IMediaServerService.java
#	src/main/java/com/genersoft/iot/vmp/media/service/impl/MediaServerServiceImpl.java
#	src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMMediaNodeServerService.java
#	src/main/java/com/genersoft/iot/vmp/service/impl/MediaServiceImpl.java
#	src/main/java/com/genersoft/iot/vmp/utils/CivilCodeUtil.java
#	src/main/resources/application.yml
#	web_src/src/layout/UiHeader.vue
#	web_src/src/router/index.js
2024-10-18 13:55:23 +08:00
panlinlin
601daa1092 1078-移除暂未实现的按钮 2024-06-27 22:05:31 +08:00
panlinlin
03497c55f0 Merge branch 'refs/heads/master' into 1078
# Conflicts:
#	src/main/resources/application.yml
2024-06-27 21:52:59 +08:00
panlinlin
a5b48e5b19 1078-添加国标级联中管理部标通道 2024-06-23 08:21:24 +08:00
panlinlin
b22e894e94 1078-通道信息增加数据库ID 2024-06-21 21:46:55 +08:00
panlinlin
282e0db96e 1078-调整通道信息 2024-06-21 21:30:15 +08:00
panlinlin
5db39a2265 1078-完善接入国标通道页面以及属性 2024-06-20 06:21:20 +08:00
panlinlin
edeea61318 1078-完善接入国标通道页面以及属性 2024-06-19 00:02:08 +08:00
panlinlin
a94b18bde9 1078-添加接入国标通道页面以及属性 2024-06-18 20:42:09 +08:00
648540858
5846a4ed5b 丰富表单内容 2024-06-18 12:50:54 +08:00
panlinlin
358799a391 1078-添加接入国标通道页面以及属性 2024-06-18 05:55:42 +08:00
panlinlin
4ba04661ab 1078-添加接入国标通道表 2024-06-16 09:14:35 +08:00
panlinlin
36e15c80b0 1078-增加位置信息并发处理能力 2024-06-16 06:41:57 +08:00
648540858
449b215367 Merge branch 'refs/heads/master' into dev/abl支持 2024-06-14 09:47:27 +08:00
panlinlin
b034faad62 Merge branch 'refs/heads/master' into dev/abl支持 2024-06-14 00:04:04 +08:00
panlinlin
261945ca62 Merge branch 'refs/heads/master' into dev/abl支持
# Conflicts:
#	src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java
2024-06-13 23:41:29 +08:00
648540858
ff975b47ba Merge branch 'refs/heads/master' into dev/abl支持 2024-06-13 18:13:54 +08:00
648540858
93532a6b3b Merge remote-tracking branch 'origin/1078' into 1078 2024-06-12 12:49:58 +08:00
648540858
e0adc7306b Merge branch 'refs/heads/master' into 1078 2024-06-12 12:49:47 +08:00
panlinlin
291a87e1f7 1078-支持自动点播 2024-06-12 00:22:16 +08:00
panlinlin
46bf5b7a39 1078-支持无人观看自动停流 2024-06-11 23:49:55 +08:00
panlinlin
824690a37f 1078-终端参数回显 2024-06-10 15:20:48 +08:00
panlinlin
3410fae879 1078-添加终端参数的前端UI 2024-06-10 08:30:22 +08:00
panlinlin
c0dea69839 1078-添加接口的前端UI 2024-06-10 00:48:18 +08:00
panlinlin
f564ff0aba 1078-支持设备录像FTP方式下载 2024-06-10 00:33:55 +08:00
panlinlin
a030c15c8f 1078-支持设备录像播放以及播放控制 2024-06-09 22:09:04 +08:00
panlinlin
4b90298c99 1078-支持设备录像检索播放 2024-06-09 20:50:59 +08:00
panlinlin
b4dddb0b08 1078-支持云台控制 2024-06-08 23:55:06 +08:00
panlinlin
9c2c4a92b1 1078-支持编辑通道 2024-06-08 23:11:56 +08:00
panlinlin
18cfba612b 1078-支持快照的展示 2024-06-08 22:58:23 +08:00
panlinlin
6074638f5b 1078-支持控制是否要音频 2024-06-08 22:47:25 +08:00
panlinlin
dbb2492640 1078-修复断开连接时设备未下线的BUG 2024-06-08 21:54:58 +08:00
panlinlin
7ffe773175 1078-调整数据库建表语句 2024-06-08 21:17:37 +08:00
648540858
942a41c630 1078-增加流地址标识 2024-06-08 00:56:05 +08:00
648540858
595d9be283 1078-优化点播以及通道表结构 2024-06-08 00:46:08 +08:00
648540858
6ae623d639 1078-临时提交 2024-06-07 14:35:07 +08:00
648540858
0103d5819b 1078-调整页面 2024-06-07 14:03:41 +08:00
648540858
972ef30f8d 1078-部标通道添加音频控制 2024-06-07 07:21:40 +08:00
648540858
913d358a11 1078-部标通道添加音频控制 2024-06-07 00:20:52 +08:00
648540858
5d5d654410 1078-添加部标通道页面 2024-06-07 00:10:36 +08:00
648540858
f7d811a299 1078-调整业务信息 2024-06-06 07:26:20 +08:00
648540858
5c826ef449 1078-添加通道信息 2024-06-06 00:23:16 +08:00
648540858
0de2bb54cd 1078-完成录像文件下载 2024-06-04 23:59:08 +08:00
648540858
83875a5905 1078-修复ftp-server对文件上传的通知 2024-06-04 07:15:05 +08:00
648540858
3728219177 1078-添加录像上传 2024-06-02 00:50:45 +08:00
648540858
62ae1ee978 调整录像下载 2024-05-31 22:54:08 +08:00
648540858
e8d832d0a5 1078-添加ftpserver 2024-05-30 23:41:22 +08:00
648540858
89101b2731 1078-增加ftp-server 2024-05-30 18:36:24 +08:00
648540858
56fdbd34f4 1078-优化回放流地址格式 2024-05-30 11:34:18 +08:00
648540858
6efff9daf9 1078-优化回放 2024-05-30 10:29:14 +08:00
648540858
74c98c8636 1078-录像回放控制 2024-05-29 23:53:20 +08:00
648540858
15a551d983 1078-标记待实现 9105 2024-05-29 18:40:31 +08:00
648540858
2b1645729b 1078-切换码流类型 2024-05-29 18:36:19 +08:00
648540858
84ef932964 1078-修复双向对讲 2024-05-29 18:27:10 +08:00
648540858
2aef6ab6f1 1078-支持语音广播 2024-05-29 17:34:38 +08:00
648540858
de6a3ceb76 1078-双向对讲完成 2024-05-29 17:26:28 +08:00
648540858
87ecf68332 1078-双向对讲 2024-05-29 16:55:07 +08:00
648540858
01fbf102c2 Merge branch 'refs/heads/master' into 1078 2024-05-29 15:03:20 +08:00
648540858
3e9def7aac 支持abl录像下载 2024-05-29 10:52:28 +08:00
648540858
a945078788 1078-语音对讲 2024-05-29 00:02:31 +08:00
648540858
9ece77d54a 1078-点播添加类型 2024-05-28 18:58:16 +08:00
648540858
37b79633f0 Merge branch 'refs/heads/master' into 1078 2024-05-28 18:40:44 +08:00
648540858
98c62b93f7 支持abl录像下载中 2024-05-28 17:39:14 +08:00
648540858
bae9b2571a Merge branch 'refs/heads/master' into dev/abl支持
# Conflicts:
#	src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java
2024-05-28 16:07:41 +08:00
648540858
2c0c576d93 临时提交 2024-05-28 15:55:26 +08:00
648540858
5011a6b74a 去除多余依赖 2024-05-28 11:03:15 +08:00
648540858
271bb19c99 Merge branch 'refs/heads/master' into dev/abl支持 2024-05-28 11:02:05 +08:00
648540858
adfce4464d 1078-终端上传乘客流量 2024-05-27 23:55:44 +08:00
648540858
c8ddee905f 1078-补充终端音视频参数设置 + 查询终端音视频属性 2024-05-27 23:29:59 +08:00
648540858
8be6979911 1078-图像分析报警参数设置 2024-05-24 00:15:52 +08:00
648540858
1e9cdfe87f 1078-单独视频通道参数设置+特殊报警录像参数设置+视频相关报警屏蔽字 2024-05-22 21:24:47 +08:00
648540858
9817bf3fb7 1078-音视频参数设置+音视频通道列表设置 2024-05-21 23:58:23 +08:00
648540858
82ab524fc4 1078-音视频参数设置+音视频通道列表设置 2024-05-21 23:56:51 +08:00
648540858
e085258d74 1078-数据下行透传+数据上行透传 + 数据压缩上报 + 平台 RSA公钥 + 终端 RSA公钥 2024-05-20 00:04:04 +08:00
648540858
2f1ebca335 1078-单条存储多媒体数据检索上传命令 2024-05-19 23:50:37 +08:00
648540858
b626a583f4 1078-录音 2024-05-19 17:50:40 +08:00
648540858
dcc20d0d15 1078-存储多媒体数据上传接口优化 2024-05-19 17:08:31 +08:00
648540858
6af9b8da1f 1078-存储多媒体数据上传 2024-05-18 16:52:02 +08:00
648540858
e9562d7d31 1078-存储多媒体数据上传命令 2024-05-18 07:29:15 +08:00
648540858
b0e25ef784 1078-修复分包消息处理 2024-05-18 05:59:23 +08:00
648540858
7ddf066878 1078-修复存储多媒体数据检索 2024-05-17 07:43:28 +08:00
648540858
9161a090f6 1078-存储多媒体数据检索接口 2024-05-15 13:15:14 +08:00
648540858
7bf548492a 1078-修复摄像头立即拍摄命令应答 2024-05-14 23:21:57 +08:00
648540858
e02a047eb2 1078-存储多媒体数据检索 + 存储多媒体数据检索应答 2024-05-14 13:13:58 +08:00
648540858
aaa1d3a46f 1078-摄像头立即拍摄命令 2024-05-12 07:36:29 +08:00
648540858
db4ba4035f Merge branch 'refs/heads/master' into 1078 2024-05-12 06:53:53 +08:00
648540858
cc71b7d9ca 1078-定位数据批量上传+多媒体事件信息上传+多媒体数据上传 2024-05-09 00:03:54 +08:00
648540858
c6e3df685a 1078-上报驾驶员身份信息请求+驾驶员身份信息采集上报 2024-05-08 22:51:29 +08:00
648540858
ad67155d73 1078-查询区域或线路数据 2024-05-06 23:58:17 +08:00
648540858
2112fffc26 1078-查询区域或线路数据应答... 2024-05-06 18:00:26 +08:00
648540858
364d613ccb 1078-修复删除路线 2024-05-06 16:05:16 +08:00
648540858
c53e4f6fbc 1078-设置路线 2024-05-06 15:55:14 +08:00
648540858
cc91db30c5 1078-查询区域或线路数据 2024-05-05 23:02:49 +08:00
648540858
00749619da 1078-设置路线... 2024-05-05 21:54:56 +08:00
648540858
9280b57974 1078-设置路线... 2024-05-04 23:19:27 +08:00
648540858
a3149139e2 1078-设置多边形区域+删除多边形区域 2024-05-04 21:56:47 +08:00
648540858
58401b1444 1078-设置多边形区域... 2024-05-04 14:57:48 +08:00
648540858
4a5de5a2db 1078-设置矩形区域+删除矩形区域 2024-05-04 14:35:45 +08:00
648540858
faa0a01b9f 1078-设置圆形区域 2024-05-04 00:09:12 +08:00
648540858
5dd49b3d44 1078-设置圆形区域... 2024-05-03 18:58:49 +08:00
648540858
4011e54dd8 1078-设置圆形区域... 2024-05-03 01:02:00 +08:00
648540858
738b3b6a8e 1078-车辆控制应答 2024-05-02 07:35:44 +08:00
648540858
a5bfe5049d 1078-车辆控制 2024-05-02 07:29:00 +08:00
648540858
c946b97514 1078-优化消息汇报消息体的解析 2024-05-02 06:43:59 +08:00
648540858
0fc0cd6e41 1078-优化编码 2024-05-02 06:25:09 +08:00
648540858
734f0c7e04 1078-设置电话本+电话回拨 2024-05-02 05:21:50 +08:00
648540858
16bc3dabd6 1078-修改文本信息下发标记类型注释 2024-05-02 04:46:34 +08:00
648540858
7c833f3d12 1078-文本信息下发 2024-05-01 15:07:38 +08:00
648540858
e5acf7f1e4 1078-人工确认报警消息+链路检测 2024-05-01 10:05:33 +08:00
648540858
eb43ffd98f 1078-临时提交 2024-05-01 00:01:55 +08:00
648540858
e45b2479d3 1078-临时位置跟踪控制+位置信息查询 2024-04-30 23:37:44 +08:00
648540858
7bdde6907a 1078-添加设备属性查询接口 2024-04-30 12:13:49 +08:00
648540858
5be7c7636e 1078-查询终端属性完成 2024-04-30 00:42:22 +08:00
648540858
76580d8fdc 1078-查询终端属性... 2024-04-30 00:28:40 +08:00
648540858
5b489d7c26 1078-设置终端参数-添加接口 2024-04-29 23:06:15 +08:00
648540858
5a392372cb 1078-添加设备控制 2024-04-29 22:15:21 +08:00
648540858
8aa97ba695 1078-添加设备控制 2024-04-29 22:12:27 +08:00
648540858
516c5ce3d1 1078-添加设备控制 2024-04-29 22:01:26 +08:00
648540858
9facff13b1 1078-添加发送分包支持 2024-04-29 21:24:08 +08:00
648540858
91b81ceb7a 1078-添加发送分包支持 2024-04-29 16:27:01 +08:00
648540858
06b27beedc 1078-设置终端参数... 2024-04-29 07:00:00 +08:00
648540858
bc356849c7 1078-设置终端参数... 2024-04-29 00:05:04 +08:00
648540858
225940825b 1078-设置终端参数... 2024-04-24 23:34:21 +08:00
648540858
62122f95f0 1078-完善查询终端参数接口 2024-04-24 23:15:07 +08:00
648540858
67b846fe2f 1078-支持8103 修改注释错误 2024-04-24 22:21:47 +08:00
648540858
714e1ff62c 1078-支持8103 设置终端参数 2024-04-21 23:54:06 +08:00
648540858
0058f1b0a9 1078-解析104... 2024-04-21 00:24:24 +08:00
648540858
34b6b516ab 1078-解析104... 2024-04-21 00:16:07 +08:00
648540858
f9c22fcb3d 1078-解析104中... 2024-04-20 18:59:23 +08:00
648540858
c5ac7e218a 1078-解析104中... 2024-04-20 14:23:05 +08:00
648540858
975e94eee1 1078-支持分包消息 2024-04-20 13:03:39 +08:00
648540858
50e2565643 1078-处理分包发送 2024-04-20 00:07:37 +08:00
648540858
dd5ab573f2 1078-解析104... 2024-04-19 07:19:40 +08:00
648540858
a6236a2c13 1078-解析104... 2024-04-19 00:01:20 +08:00
648540858
16143a3fff 1078-解析104中 2024-04-18 20:11:13 +08:00
648540858
fce96def9f 1078-添加查询终端参数 2024-04-15 00:40:36 +08:00
648540858
570307669e 1078-添加查询指定终端参数 2024-04-15 00:31:11 +08:00
648540858
205e529660 1078-补充终端设置参数 2024-04-14 23:03:43 +08:00
648540858
21e7ca0e46 1078-临时提交 2024-04-12 23:36:02 +08:00
648540858
6729df4992 合并主线 2024-04-12 22:15:26 +08:00
648540858
c6bd4ac352 添加导包 2024-04-12 11:23:57 +08:00
648540858
9f3cab6486 Merge branch 'master' into 1078 2024-04-12 10:38:45 +08:00
648540858
be787d1a14 添加日志 2024-04-12 09:55:42 +08:00
648540858
8716160d96 支持推流鉴权 2024-04-11 23:36:06 +08:00
648540858
9800fd6e7b Merge branch 'refs/heads/master' into dev/abl支持
# Conflicts:
#	src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java
2024-04-11 22:47:03 +08:00
648540858
4005a12403 Merge remote-tracking branch 'origin/1078' into 1078 2024-04-11 22:46:03 +08:00
648540858
59c91bdaf8 1078-暂时注释位置附加信息读取 2024-04-11 22:45:50 +08:00
648540858
7d08b56267 Merge branch 'master' into 1078 2024-04-11 09:39:12 +08:00
648540858
05c83cf6ef Merge branch 'master' into 1078 2024-04-11 09:39:04 +08:00
648540858
1d36382986 修改抓拍存储 2024-04-10 16:52:39 +08:00
648540858
bb350e847d 修复抓拍存储 2024-04-10 16:35:47 +08:00
648540858
d410a3ca18 添加抓拍支持 2024-04-10 16:26:46 +08:00
648540858
b08f00104e abl添加getMediaInfo接口实现 2024-04-10 00:03:45 +08:00
648540858
2dc7eecb47 abl添加checkMediaServer实现 2024-04-09 23:41:48 +08:00
648540858
48a0e88b95 Merge branch 'refs/heads/master' into dev/abl支持 2024-04-09 22:52:33 +08:00
648540858
0077df29d4 临时提交 2024-04-09 21:42:08 +08:00
648540858
5457407601 恢复abl实现 2024-04-09 20:56:41 +08:00
648540858
ae239c8848 Merge branch 'master' into 1078 2024-04-08 18:15:06 +08:00
648540858
9badf1c7fe 1078-添加位置附加信息定义 2024-04-08 18:15:02 +08:00
648540858
d54787f323 1078-添加读取位置信息汇报附加信息读取 2024-04-07 23:50:58 +08:00
648540858
8a2dc6031e 1078-实现云台控制接口 2024-04-07 22:06:41 +08:00
648540858
9255ea802f 1078-添加云台控制接口 2024-04-07 20:59:21 +08:00
648540858
349b0442d6 Merge remote-tracking branch 'origin/1078' into 1078 2024-04-07 20:42:32 +08:00
648540858
403eb4499d Merge branch 'master' into 1078 2024-04-07 20:42:10 +08:00
648540858
6757f4b719 1078-云台变倍控制 2024-04-07 07:21:21 +08:00
648540858
8ba30e83ef 1078-修复错别字 2024-04-07 07:19:02 +08:00
648540858
98d9eb5314 1078-添加云台红外补光控制 2024-04-07 07:17:35 +08:00
648540858
a8a4aecc15 1078-添加云台雨刷控制 2024-04-07 07:15:43 +08:00
648540858
b649464753 1078-添加云台光圈控制 2024-04-07 07:12:51 +08:00
648540858
ebdd9ab534 1078-添加云台焦距控制 2024-04-07 07:09:49 +08:00
648540858
a1ab834875 1078-添加云台旋转 2024-04-07 07:07:27 +08:00
648540858
4ec4d618d6 1078-添加文件上传控制 2024-04-07 07:02:06 +08:00
648540858
5fc1000fcc 1078-添加文件上传完成通知 2024-04-07 06:56:39 +08:00
648540858
302eb98d51 1078-添加文件上传指令 2024-04-07 06:44:52 +08:00
648540858
984d8743be 1078-优化录像回放开始和停止 2024-04-06 00:42:54 +08:00
648540858
26bbeac6c7 1078-添加录像回放开始和停止 2024-04-06 00:06:40 +08:00
648540858
81c2b5715c 1078-添加录像回放列表查询 2024-04-04 16:54:08 +08:00
648540858
3e5da98539 1078-支持点播暂停/继续 2024-04-04 07:19:46 +08:00
648540858
a7b7371e74 1078-增加结束点播 2024-04-03 18:00:48 +08:00
648540858
0f420c43ac 1078-优化点播 2024-04-03 16:59:33 +08:00
648540858
abc3766556 1078-优化点播 2024-04-03 16:33:49 +08:00
648540858
603ce18573 1078-添加点播支持 2024-04-02 23:26:40 +08:00
648540858
6acc395ad2 Merge branch 'master' into 1078 2024-04-02 18:33:53 +08:00
648540858
da33471dfd 1078-修改9101编码为GBK 2024-03-17 23:45:08 +08:00
648540858
98199ec657 1078-优化BCD码解析 2024-03-16 23:41:29 +08:00
648540858
3e672ca38c 1078-支持位置汇报 2024-03-16 23:22:07 +08:00
648540858
9bc9dbe43b 1078-解析位置汇报 2024-03-16 00:29:30 +08:00
648540858
60d51cf23a 1078-支持展示车牌颜色 2024-03-15 22:51:49 +08:00
648540858
93946407e8 1078-简化设备注册取值写法 2024-03-15 17:50:03 +08:00
648540858
23a72e94e6 1078-优化列表展示效果 2024-03-14 18:04:28 +08:00
648540858
d4c531dc12 Merge branch 'master' into 1078 2024-03-14 14:55:03 +08:00
648540858
dff7b8e31f 添加设备新增页面 2024-03-13 23:33:03 +08:00
648540858
e400c92f53 添加设备新增接口 2024-03-13 23:21:49 +08:00
648540858
4eb0163e43 添加设备查询和设备更新接口 2024-03-13 23:16:01 +08:00
648540858
d78f76e58b 1078-设备注册支持从数据库校验是否合法 2024-03-13 18:18:23 +08:00
648540858
44f17c723b Merge remote-tracking branch 'origin/1078' into 1078 2024-03-13 16:46:31 +08:00
648540858
18bd959541 Merge branch 'master' into 1078 2024-03-13 16:46:21 +08:00
648540858
dc38df6288 支持从数据库查询注册的设备是否合法 2024-03-13 00:04:52 +08:00
648540858
613452b3fc 1078-设备注册兼容1078-2013 2024-03-12 18:21:10 +08:00
648540858
9494b6dc85 优化架构,获取设备注册时的设备相关信息 2024-03-12 17:32:10 +08:00
648540858
79dc7e79d2 Merge branch 'master' into 1078 2024-03-08 16:22:13 +08:00
648540858
6275372455 添加service 2023-07-31 17:34:44 +08:00
529 changed files with 36523 additions and 4625 deletions

1
.dockerignore Normal file
View File

@ -0,0 +1 @@
docker/volumes

75
.github/workflows/build.yml vendored Normal file
View File

@ -0,0 +1,75 @@
name: release-ubuntu
on:
push:
tags:
- "v*.*.*" # 触发条件是推送标签 如git tag v2.7.4 git push origin v2.7.4
jobs:
build-ubuntu:
runs-on: ubuntu-latest
strategy:
matrix:
arch: [amd64]
max-parallel: 1 # 最大并行数
steps:
- name: Checkout
uses: actions/checkout@v4 # github action运行环境
- name: Create release # 创建文件夹
run: |
rm -rf release
mkdir release
echo ${{ github.sha }} > Release.txt
cp Release.txt LICENSE release/
cat Release.txt
- name: Set up JDK 1.8
uses: actions/setup-java@v4
with:
# Eclipse基金会维护的开源Java发行版 因为github action参考java的用这个 所以用这个
# 还有microsoft(微软维护的openjdk发行版) oracle(商用SDK)等
distribution: 'temurin'
java-version: '8'
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: '20.x' # Node.js版本 20系列的最新稳定版
- name: Compile backend
run: |
mvn package
mvn package -P war
- name: Compile frontend
run: |
cd ./web
npm install
npm run build:prod
cd ../
- name: Package Files
run: |
cp -r ./src/main/resources/static release/ # 复制前端文件
cp ./target/*.jar release/ # 复制 JAR 文件
cp ./src/main/resources/application-dev.yml release/application.yml
BRANCH=${{ github.event.base_ref }}
BRANCH_NAME=$(echo "$BRANCH" | grep -oP 'refs/heads/\K.*')
echo "BRANCH_NAME= ${BRANCH_NAME}"
# 如果无法获取,使用默认分支
if [[ -z "BRANCH_NAME" ]]; then
BRANCH_NAME="${{ github.event.repository.default_branch }}"
fi
TAG_NAME="${GITHUB_REF#refs/tags/}"
ZIP_FILE_NAME="${BRANCH_NAME}-${TAG_NAME}.zip"
zip -r "$ZIP_FILE_NAME" release
echo "ZIP_FILE_NAME=$ZIP_FILE_NAME" >> $GITHUB_ENV
- name: Release
uses: softprops/action-gh-release@v2
if: startsWith(github.ref, 'refs/tags/')
with:
files: ${{ env.ZIP_FILE_NAME }}

2
.gitignore vendored
View File

@ -28,3 +28,5 @@ hs_err_pid*
/src/main/resources/static/
certificates
/.vs
/docker/volumes

View File

@ -1,5 +1,5 @@
![logo](doc/_media/logo.png)
# 开箱即用的28181协议视频平台
# 开箱即用的国标28181和部标808+1078协议视频平台
[![Build Status](https://travis-ci.org/xia-chu/ZLMediaKit.svg?branch=master)](https://travis-ci.org/xia-chu/ZLMediaKit)
[![license](http://img.shields.io/badge/license-MIT-green.svg)](https://github.com/xia-chu/ZLMediaKit/blob/master/LICENSE)
@ -8,7 +8,7 @@
[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-yellow.svg)](https://github.com/xia-chu/ZLMediaKit/pulls)
WEB VIDEO PLATFORM是一个基于GB28181-2016标准实现的开箱即用的网络视频平台负责实现核心信令与设备管理后台部分支持NAT穿透支持海康、大华、宇视等品牌的IPC、NVR接入。支持国标级联支持将不带国标功能的摄像机/直播流/直播推流转发到其他国标平台。
WEB VIDEO PLATFORM是一个基于GB28181-2016、部标808、部标1078标准实现的开箱即用的网络视频平台负责实现核心信令与设备管理后台部分支持NAT穿透支持海康、大华、宇视等品牌的IPC、NVR接入。支持国标级联支持将不带国标功能的摄像机/直播流/直播推流转发到其他国标平台。
流媒体服务基于@夏楚 ZLMediaKit [https://github.com/ZLMediaKit/ZLMediaKit](https://github.com/ZLMediaKit/ZLMediaKit)
播放器使用@dexter jessibuca [https://github.com/langhuihui/jessibuca/tree/v3](https://github.com/langhuihui/jessibuca/tree/v3)
@ -27,15 +27,6 @@ WEB VIDEO PLATFORM是一个基于GB28181-2016标准实现的开箱即用的网
wvp使用文档 [https://doc.wvp-pro.cn](https://doc.wvp-pro.cn)
ZLM使用文档 [https://github.com/ZLMediaKit/ZLMediaKit](https://github.com/ZLMediaKit/ZLMediaKit)
# 付费社群
[![社群](doc/_media/shequ.png "shequ")](https://t.zsxq.com/0d8VAD3Dm)
> 收费是为了提供更好的服务,也是对作者更大的激励。加入星球的用户三天后可以私信我留下微信号,我会拉大家入群。
> 加入三天内不满意可以直接自行推出,星球会直接退款给大家。需要发票可以在星球app中直接咨询星球客服获取。
> 星球还提供了包括闭源的全功能试用包, 会随时更新。
> 付费社群即可以对作者提供支持,也可以为大家更加快速的解决问题。如果暂时无法加入,给项目点个星也是极大的鼓励。
# gitee仓库
https://gitee.com/pan648540858/wvp-GB28181-pro.git
@ -129,13 +120,38 @@ https://gitee.com/pan648540858/wvp-GB28181-pro.git
- [X] 支持MysqlPostgresql金仓等数据库
- [X] 支持录制计划, 根据设定的时间对通道进行录制. 暂不支持将录制的内容转发到国标上级
- [X] 支持国标信令集群
- [X] 新增支持部标808和部标1078大量新特性不一一列表了。支持作为网关被国标上级调用部标设备
# 闭源内容
- [X] 支持ONVIF协议设备检索支持点播云台控制国标级联点播自动点播等。
- [X] 支持部标1078+808协议支持点播云台控制录像回放位置上报自动点播等。
- [X] 支持国标28181-2022协议支持巡航轨迹查询PTZ精准控制存储卡格式化设备软件升级OSD配置h265+aac支持辅码流录像倒放等。
- [X] 支持国网B接口协议。支持注册获取资源预览, 云台控制,预置位控制等,可免费定制支持语音对讲、录像回放和抓拍图像。
- [X] 国标增强版: 支持国标28181-2022协议支持巡航轨迹查询PTZ精准控制存储卡格式化设备软件升级OSD配置h265+aac支持辅码流录像倒放等。
- [X] 全功能版:
- [X] 支持开源所有功能
- [X] ONVIF协议
- 设备检索
- 实时图像预览
- 录像回放、回放倍速控制
- 云台控制、预置位控制、云台绝对定位、看守位
- 聚焦控制
- 设备重启
- 设备时间设置以及跟系统时间的差值比较
- 恢复出厂设置
- 自动获取设备品牌等信息、支持展示DNS信息、支持协议的展示
- 国标级联点播、自动点播等。
- [X] 国网B接口协议
- 设备注册
- 资源获取
- 预览
- 云台控制
- 预置位控制等,
- 可免费定制支持语音对讲、录像回放和抓拍图像。
- [X] 支持按权限分配可以使用的通道
- [X] 支持电子地图。支持展示通道位置支持在地图上修改通道位置。可扩展接入高德地图API支持搜索位置附近设备。
- [X] 支持表格导出
- [X] 拉流代理支持按照品牌拼接url。
- [X] 播放鉴权,更加安全。
- [X] 此版本后续开发功能支持直接更新提供,无需二次付费。
- [X] 提供源码不限制部署次数和支持路数。
# 授权协议
@ -143,6 +159,17 @@ https://gitee.com/pan648540858/wvp-GB28181-pro.git
# 技术支持
# 付费社群
<img src="doc/_media/shequ.png" width="50%" height="50%">
> 收费是为了提供更好的服务,也是对作者更大的激励。加入星球的用户三天后可以私信我留下微信号,我会拉大家入群。
> 加入三天内不满意可以直接自行推出,星球会直接退款给大家。需要发票可以在星球app中直接咨询星球客服获取。
> 星球还提供了包括闭源的全功能试用包, 会随时更新。
> 付费社群即可以对作者提供支持,也可以为大家更加快速的解决问题。如果暂时无法加入,给项目点个星也是极大的鼓励。
[知识星球](https://t.zsxq.com/0d8VAD3Dm)专栏列表:,
- [使用入门系列一WVP-PRO能做什么](https://t.zsxq.com/0dLguVoSp)

View File

@ -18,6 +18,9 @@ WVP支持三种图像输入方式直播[拉流代理](_content/ability/pro
1. 默认情况下WVP收到推流信息后列表中出现这条推流信息如果你需要共享推流信息到其他国标平台,那么你需要编辑/国标通道配置,配置国标编码.
2. WVP也支持推流前导入大量通道直接推送给上级点击“下载模板”按钮根据示例修改模板后点击“通道导入”按钮导入通道数据.
## 生成推流地址
可以在推流列表里点击‘生成推流地址’按钮,得到新地址后直接复制到推流设备。
## 推拉流鉴权规则
为了保护服务器的WVP默认开启推流鉴权目前不支持关闭此功能

19
docker/.env Normal file
View File

@ -0,0 +1,19 @@
MediaRtmp=10001
MediaRtsp=10002
MediaRtp=10003
WebHttp=8080
WebHttps=8081
Stream_IP=127.0.0.1
SDP_IP=127.0.0.1
SIP_ShowIP=127.0.0.1
SIP_Port=8160
SIP_Domain=3502000000
SIP_Id=35020000002000000001
SIP_Password=wvp_sip_password
RecordSip=true
RecordPushLive=

10
docker/README.md Normal file
View File

@ -0,0 +1,10 @@
可以在当前目录下:
使用`docker compose up -d`直接运行。
使用`docker compose up -d -build -force-recreate`强制重新构建所有服务的镜像并删除旧容器重新运行
`.env`用来配置环境变量,在这里配好之后,其它的配置会自动联动的。
`build.sh`用来以日期为tag构建镜像推送到指定的容器注册表内Windows下可以使用`Git Bash`运行)
其它的文件的作用暂不明确

View File

@ -1,45 +1,79 @@
#/bin/bash
set -e
#!/bin/bash
version=2.7.3
# 获取当前日期作为标签格式YYYYMMDD
date_tag=$(date +%Y%m%d)
git clone https://gitee.com/pan648540858/wvp-GB28181-pro.git
cd wvp-GB28181-pro/web_src && \
npm install && \
npm run build
# 切换到脚本所在目录的上一级目录作为工作目录
cd "$(dirname "$0")/.." || {
echo "错误:无法切换到上级目录"
exit 1
}
echo "已切换工作目录到:$(pwd)"
cd ../../
mkdir -p ./nginx/dist
cp -r wvp-GB28181-pro/src/main/resources/static/* ./nginx/dist
# 检查私有仓库环境变量
if [ -z "$DOCKER_REGISTRY" ]; then
echo "未设置DOCKER_REGISTRY环境变量"
read -p "请输入私有Docker注册库地址如不推送请留空: " input_registry
docker_registry="$input_registry"
else
docker_registry="$DOCKER_REGISTRY"
fi
echo "构建ZLM容器"
cd ./media/
chmod +x ./build.sh
./build.sh
cd ../
# 定义要构建的镜像和对应的Dockerfile路径相对当前工作目录
images=(
"wvp-service:docker/wvp/Dockerfile"
"wvp-nginx:docker/nginx/Dockerfile"
)
echo "构建数据库容器"
cd ./mysql/
chmod +x ./build.sh
./build.sh
cd ../
# 构建镜像的函数
build_image() {
local image_name="$1"
local dockerfile_path="$2"
echo "构建Redis容器"
cd ./redis/
chmod +x ./build.sh
./build.sh
cd ../
# 检查Dockerfile是否存在
if [ ! -f "$dockerfile_path" ]; then
echo "错误未找到Dockerfile - \"$dockerfile_path\",跳过构建"
return 1
fi
echo "构建WVP容器"
cd ./wvp/
chmod +x ./build.sh
./build.sh
cd ../
# 构建镜像
local full_image_name="${image_name}:${date_tag}"
echo
echo "=============================================="
echo "开始构建镜像:${full_image_name}"
echo "Dockerfile路径${dockerfile_path}"
echo "构建Nginx容器"
cd ./nginx/
chmod +x ./build.sh
./build.sh
cd ../
docker build -t "${full_image_name}" -f "${dockerfile_path}" .
if [ $? -ne 0 ]; then
echo "镜像${full_image_name}构建失败"
return 1
fi
./push.sh
# 推送镜像(如果设置了仓库地址)
if [ -n "$docker_registry" ]; then
local registry_image="${docker_registry}/${full_image_name}"
echo "给镜像打标签:${registry_image}"
docker tag "${full_image_name}" "${registry_image}"
echo "推送镜像到注册库"
docker push "${registry_image}"
if [ $? -eq 0 ]; then
echo "镜像${registry_image}推送成功"
else
echo "镜像${registry_image}推送失败"
fi
else
echo "未提供注册库地址,不执行推送"
fi
echo "=============================================="
echo
}
# 循环构建所有镜像
for item in "${images[@]}"; do
IFS=':' read -r image_name dockerfile_path <<< "$item"
build_image "$image_name" "$dockerfile_path"
done
echo "所有镜像处理完成"
exit 0

View File

@ -1,7 +1,7 @@
version: '3'
services:
polaris-redis:
image: polaris-tian-docker.pkg.coding.net/qt/polaris/polaris-redis:latest
image: redis:latest # 使用官方Redis镜像
restart: unless-stopped
healthcheck:
test: [ "CMD", "redis-cli", "--raw", "incr", "ping" ]
@ -11,8 +11,8 @@ services:
start_period: 10s
networks:
- media-net
ports:
- 6379:6379
# ports:
# - 6379:6379
volumes:
- ./redis/conf/redis.conf:/opt/polaris/redis/redis.conf
- ./volumes/redis/data/:/data
@ -21,7 +21,7 @@ services:
command: redis-server /opt/polaris/redis/redis.conf --appendonly yes
polaris-mysql:
image: polaris-tian-docker.pkg.coding.net/qt/polaris/polaris-mysql:latest
image: mysql:8 # 使用官方MySQL 8镜像
restart: unless-stopped
healthcheck:
test: [ "CMD", "bash", "-c", "cat < /dev/null > /dev/tcp/127.0.0.1/3306" ]
@ -34,18 +34,18 @@ services:
environment:
MYSQL_DATABASE: wvp
MYSQL_ROOT_PASSWORD: root
MYSQL_USER: root
MYSQL_PASSWORD: root
MYSQL_USER: wvp_user
MYSQL_PASSWORD: wvp_password
TZ: Asia/Shanghai
ports:
- 3306:3306
# ports:
# - 3306:3306
volumes:
- ./mysql/conf:/etc/mysql/conf.d
- ./logs/mysql:/logs
- ./volumes/mysql/data:/var/lib/mysql
- ../数据库/2.7.4/初始化-mysql-2.7.4.sql:/docker-entrypoint-initdb.d/init.sql # 初始化SQL脚本目录
command: [
'mysqld',
'--default-authentication-plugin=mysql_native_password',
# '--default-authentication-plugin=mysql_native_password',
'--innodb-buffer-pool-size=80M',
'--character-set-server=utf8mb4',
'--collation-server=utf8mb4_general_ci',
@ -54,69 +54,99 @@ services:
]
polaris-media:
image: polaris-tian-docker.pkg.coding.net/qt/polaris/polaris-media:latest
image: zlmediakit/zlmediakit:master # 替换为官方镜像
restart: always
networks:
- media-net
ports:
- "10935:10935"
- "5540:5540"
- "6080:6080"
#- "6080:80/tcp" # [播流]HTTP 安全考虑-非测试阶段需要注释掉改为由nginx代理播流地址
#- "4443:443/tcp" # [播流]HTTPS 安全考虑-非测试阶段需要注释掉改为由nginx代理播流地址
- "${MediaRtmp:-10935}:${MediaRtmp:-10935}/tcp" # [收流]RTMP
- "${MediaRtmp:-10935}:${MediaRtmp:-10935}/udp" # [收流]RTMP
#- "41935:41935/tcp" # [收流]RTMPS 无效
- "${MediaRtsp:-5540}:${MediaRtsp:-5540}/tcp" # [收流]RTSP
- "${MediaRtsp:-5540}:${MediaRtsp:-5540}/udp" # [收流]RTSP
#- "45540:45540/tcp" # [收流]RTSPS 无效
- "${MediaRtp:-10000}:${MediaRtp:-10000}/tcp" # [收流]RTP
- "${MediaRtp:-10000}:${MediaRtp:-10000}/udp" # [收流]RTP
volumes:
- ./volumes/video:/opt/media/www/record/
- ./volumes/video:/opt/media/bin/www/record/
- ./logs/media:/opt/media/log/
- ./media/config.ini:/conf/config.ini
command: [
'MediaServer',
'-c', '/conf/config.ini',
'-l', '0'
]
polaris-wvp:
image: polaris-tian-docker.pkg.coding.net/qt/polaris/polaris-wvp:latest
# 显式指定构建上下文和Dockerfile路径
build:
context: .. # 构建上下文的根路径
dockerfile: ./docker/wvp/Dockerfile # 相对于上下文路径的Dockerfile位置
restart: always
networks:
- media-net
ports:
- "18978:18978"
- "8116:8116/udp"
- "8116:8116/tcp"
- "${SIP_Port:-8116}:${SIP_Port:-8116}/udp"
- "${SIP_Port:-8116}:${SIP_Port:-8116}/tcp"
depends_on:
- polaris-redis
- polaris-mysql
- polaris-media
links:
- polaris-redis
- polaris-mysql
- polaris-media
volumes:
- ./wvp/wvp/:/opt/wvp/wvp/
- ./wvp/wvp/:/opt/ylcx/wvp/
- ./logs/wvp:/opt/wvp/logs/
environment:
TZ: "Asia/Shanghai"
# 本机的IP
SIP_HOST: 127.0.0.1
STREAM_HOST: 127.0.0.1
# 流链接的IP
Stream_IP: ${Stream_IP}
# SDP里的IP
SDP_IP: ${SDP_IP}
# [可选] zlm服务器访问WVP所使用的IP, 默认使用127.0.0.1zlm和wvp没有部署在同一台服务器时必须配置
ZLM_HOOK_HOST: polaris-wvp
ZLM_HOST: polaris-media
ZLM_PORT: 6080
ZLM_SERCERT: su6TiedN2rVAmBbIDX0aa0QTiBJLBdcf
MediaHttp: ${WebHttp:-8080}
#MediaHttps: ${WebHttps:-8081}
MediaRtmp: ${MediaRtmp:-10935}
MediaRtsp: ${MediaRtsp:-5540}
MediaRtp: ${MediaRtp:-10000}
REDIS_HOST: polaris-redis
REDIS_PORT: 6379
DATABASE_HOST: polaris-mysql
DATABASE_PORT: 3306
DATABASE_USER: wvp
DATABASE_PASSWORD: wvp
# 前端跨域配置nginx容器所在物理机IP
NGINX_HOST: http://127.0.0.1:8080
DATABASE_USER: wvp_user
DATABASE_PASSWORD: wvp_password
SIP_ShowIP: ${SIP_ShowIP}
SIP_Port: ${SIP_Port:-8116}
SIP_Domain: ${SIP_Domain}
SIP_Id: ${SIP_Id}
SIP_Password: ${SIP_Password}
RecordSip: ${RecordSip}
RecordPushLive: ${RecordPushLive}
polaris-nginx:
image: polaris-tian-docker.pkg.coding.net/qt/polaris/polaris-nginx:latest
# 显式指定构建上下文和Dockerfile路径
build:
context: .. # 构建上下文的根路径
dockerfile: ./docker/nginx/Dockerfile # 相对于上下文路径的Dockerfile位置
ports:
- "8080:8080"
- "${WebHttp:-8080}:8080"
depends_on:
- polaris-wvp
links:
- polaris-wvp
environment:
WVP_HOST: polaris-wvp
WVP_PORT: 18978
volumes:
- ./nginx/conf/nginx.conf:/etc/nginx/nginx.conf
- ./nginx/templates/:/etc/nginx/templates
- ./logs/nginx:/var/log/nginx
environment:
# 流链接的IP
Stream_IP: ${Stream_IP}
networks:
- media-net

View File

@ -52,21 +52,21 @@ alive_interval=10.0
enable=1
on_flow_report=
on_http_access=
on_play=
on_publish=
on_record_mp4=
on_play=http://polaris-wvp:18978/index/hook/on_play
on_publish=http://polaris-wvp:18978/index/hook/on_publish
on_record_mp4=http://polaris-wvp:18978/index/hook/on_record_mp4
on_record_ts=
on_rtp_server_timeout=
on_rtp_server_timeout=http://polaris-wvp:18978/index/hook/on_rtp_server_timeout
on_rtsp_auth=
on_rtsp_realm=
on_send_rtp_stopped=
on_send_rtp_stopped=http://polaris-wvp:18978/index/hook/on_send_rtp_stopped
on_server_exited=
on_server_keepalive=
on_server_started=
on_server_keepalive=http://polaris-wvp:18978/index/hook/on_server_keepalive
on_server_started=http://polaris-wvp:18978/index/hook/on_server_started
on_shell_login=
on_stream_changed=
on_stream_none_reader=
on_stream_not_found=
on_stream_changed=http://polaris-wvp:18978/index/hook/on_stream_changed
on_stream_none_reader=http://polaris-wvp:18978/index/hook/on_stream_none_reader
on_stream_not_found=http://polaris-wvp:18978/index/hook/on_stream_not_found
retry=1
retry_delay=3.0
stream_changed_schemas=rtsp/rtmp/fmp4/ts/hls/hls.fmp4
@ -82,10 +82,10 @@ forwarded_ip_header=
keepAliveSecond=30
maxReqSize=40960
notFound=<html><head><title>404 Not Found</title></head><body bgcolor="white"><center><h1>您访问的资源不存在!</h1></center><hr><center>ZLMediaKit(git hash:8ccb4e9/%aI,branch:master,build time:2024-11-07T10:34:19)</center></body></html>
port=6080
port=80
rootPath=./www
sendBufSize=65536
sslport=4443
sslport=443
virtualPath=
[multicast]
@ -99,7 +99,7 @@ auto_close=0
continue_push_ms=3000
enable_audio=1
enable_fmp4=1
enable_hls=1
enable_hls=0
enable_hls_fmp4=0
enable_mp4=0
enable_rtmp=1
@ -111,7 +111,7 @@ hls_save_path=./www
modify_stamp=2
mp4_as_player=0
mp4_max_second=3600
mp4_save_path=/home
mp4_save_path=/opt/media/bin/www
paced_sender_ms=0
rtmp_demand=0
rtsp_demand=0
@ -119,13 +119,14 @@ ts_demand=0
[record]
appName=record
enableFmp4=0
enableFmp4=1
fastStart=0
fileBufSize=65536
fileRepeat=0
sampleMS=500
[rtc]
bfilter=0
datachannel_echo=0
externIP=
maxRtpCacheMS=5000
@ -150,7 +151,7 @@ directProxy=1
enhanced=0
handshakeSecond=15
keepAliveSecond=15
port=10935
port=10001
sslport=0
[rtp]
@ -165,8 +166,9 @@ dumpDir=
gop_cache=1
h264_pt=98
h265_pt=99
merge_frame=1
opus_pt=100
port=10000
port=10003
port_range=30000-30500
ps_pt=96
rtp_g711_dur_ms=100
@ -179,7 +181,7 @@ directProxy=1
handshakeSecond=15
keepAliveSecond=15
lowLatency=0
port=5540
port=10002
rtpTransportType=-1
sslport=0
@ -189,6 +191,7 @@ port=0
[srt]
latencyMul=4
passPhrase=
pktBufSize=8192
port=9000
timeoutSec=5

View File

@ -1,19 +1,28 @@
FROM ubuntu:24.04 AS builder
RUN apt-get update && \
apt-get install -y nodejs npm && \
rm -rf /var/lib/apt/lists/*
COPY ./web /build
WORKDIR /build
RUN npm --registry=https://registry.npmmirror.com install
RUN npm run build:prod
WORKDIR /src/main/resources
RUN ls
WORKDIR /src/main/resources/static
RUN ls
FROM nginx:alpine
RUN apk add --no-cache bash
ARG TZ=Asia/Shanghai
RUN \
sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories && \
apk update && \
apk add tzdata
RUN ln -sf /usr/share/zoneinfo/${TZ} /etc/localtime && \
echo '${TZ}' > /etc/timezone
RUN rm -rf /etc/nginx/conf.d/*
RUN mkdir /opt/dist
COPY ./dist /opt/dist
COPY ./conf/nginx.conf /etc/nginx/conf.d
COPY --from=builder /src/main/resources/static /opt/dist
CMD ["nginx","-g","daemon off;"]

View File

@ -1,55 +0,0 @@
#user nobody;
worker_processes 1;
#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
#pid logs/nginx.pid;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
#gzip on;
server {
listen 8080;
server_name localhost;
location / {
root /opt/dist;
index index.html index.htm;
}
location /record_proxy/{
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header REMOTE-HOST $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://polaris-wvp:18978/;
}
location /api/ {
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header REMOTE-HOST $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://polaris-wvp:18978;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}

View File

@ -0,0 +1,110 @@
server {
listen 8080;
server_name localhost;
location / {
root /opt/dist;
index index.html index.htm;
}
location /record_proxy/{
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header REMOTE-HOST $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://polaris-wvp:18978/;
}
location /api/ {
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header REMOTE-HOST $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://polaris-wvp:18978;
# 从环境变量获取原始主机地址x.x.x.x
set $original_host ${Stream_IP};
# 执行字符串替换
# 将媒体资源文件替换为Nginx输出的相对地址
sub_filter "http://$original_host/index/api/downloadFile" "mediaserver/api/downloadFile";
sub_filter "http://$original_host:80/index/api/downloadFile" "mediaserver/api/downloadFile";
sub_filter "https://$original_host/index/api/downloadFile" "mediaserver/api/downloadFile";
sub_filter "https://$original_host:443/index/api/downloadFile" "mediaserver/api/downloadFile";
sub_filter "http://$original_host/mp4_record" "mp4_record";
sub_filter "http://$original_host:80/mp4_record" "mp4_record";
sub_filter "https://$original_host/mp4_record" "mp4_record";
sub_filter "https://$original_host:443/mp4_record" "mp4_record";
# 设置为off表示替换所有匹配项而不仅仅是第一个
sub_filter_once off;
# 确保响应被正确处理
sub_filter_types application/json; # 只对JSON响应进行处理
}
# 将mediaserver/record转发到目标地址
location /mediaserver/api/downloadFile {
# 目标服务器地址
proxy_pass http://polaris-media:80/index/api/downloadFile;
# 以下是常用的反向代理设置
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# 超时设置,根据需要调整
proxy_connect_timeout 300s;
proxy_send_timeout 300s;
proxy_read_timeout 300s;
}
# 仅允许代理/rtp/开头的路径
location ^~ /rtp/ {
# 代理到ZLMediakit服务
proxy_pass http://polaris-media:80;
# 基础HTTP代理配置
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# WebSocket支持配置
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
# 超时设置,根据实际需求调整
proxy_connect_timeout 60s;
proxy_read_timeout 3600s;
proxy_send_timeout 60s;
}
# 仅允许代理/rtp/开头的路径
location ^~ /mp4_record/ {
# 代理到ZLMediakit服务
proxy_pass http://polaris-media:80;
# 基础HTTP代理配置
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# WebSocket支持配置
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
# 超时设置,根据实际需求调整
proxy_connect_timeout 60s;
proxy_read_timeout 3600s;
proxy_send_timeout 60s;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}

View File

@ -1,64 +1,84 @@
FROM ubuntu:20.04 AS build
ARG Platfrom=amd64
ARG JDK_NAME
FROM ringcentral/jdk:11 AS builder
EXPOSE 18978/tcp
EXPOSE 8116/tcp
EXPOSE 8116/udp
EXPOSE 8080/tcp
RUN apt-get update && \
DEBIAN_FRONTEND="noninteractive" \
apt-get install -y --no-install-recommends \
wget \
cmake \
maven \
git \
ca-certificates \
tzdata \
curl \
libpcre3 \
libpcre3-dev \
zlib1g-dev \
openssl \
libssl-dev \
gdb && \
apt-get autoremove -y && \
apt-get clean -y && \
rm -rf /var/lib/apt/lists/*
#RUN apt-get update && \
#DEBIAN_FRONTEND="noninteractive" \
#apt-get install -y --no-install-recommends \
#wget \
#cmake \
#maven \
#git \
#ca-certificates \
#tzdata \
#curl \
#libpcre3 \
#libpcre3-dev \
#zlib1g-dev \
#openssl \
#libssl-dev \
#gdb && \
#apt-get autoremove -y && \
#apt-get clean -y && \
#rm -rf /var/lib/apt/lists/*
# install jdk1.8
RUN mkdir -p /opt/download
WORKDIR /opt/download
RUN if [ "$Platfrom" = "arm64" ]; \
then \
wget https://polaris-tian-generic.pkg.coding.net/qt/autopliot/jdk-8u411-linux-aarch64.tar.gz?version=latest --no-check-certificate -O jdk-8.tar.gz && \
tar -zxvf /opt/download/jdk-8.tar.gz -C /usr/local/ --transform 's/jdk1.8.0_411/java/' && \
rm /opt/download/jdk-8.tar.gz; \
else \
wget https://polaris-tian-generic.pkg.coding.net/qt/autopliot/jdk-8u202-linux-x64.tar.gz?version=latest --no-check-certificate -O jdk-8.tar.gz && \
tar -zxvf /opt/download/jdk-8.tar.gz -C /usr/local/ --transform 's/jdk1.8.0_202/java/' && \
rm /opt/download/jdk-8.tar.gz; \
fi
## install jdk1.8
#RUN mkdir -p /opt/download
#WORKDIR /opt/download
#RUN if [ "$Platfrom" = "arm64" ]; \
#then \
#wget https://polaris-tian-generic.pkg.coding.net/qt/autopliot/jdk-8u411-linux-aarch64.tar.gz?version=latest --no-check-certificate -O jdk-8.tar.gz && \
#tar -zxvf /opt/download/jdk-8.tar.gz -C /usr/local/ --transform 's/jdk1.8.0_411/java/' && \
#rm /opt/download/jdk-8.tar.gz; \
#else \
#wget https://polaris-tian-generic.pkg.coding.net/qt/autopliot/jdk-8u202-linux-x64.tar.gz?version=latest --no-check-certificate -O jdk-8.tar.gz && \
#tar -zxvf /opt/download/jdk-8.tar.gz -C /usr/local/ --transform 's/jdk1.8.0_202/java/' && \
#rm /opt/download/jdk-8.tar.gz; \
#fi
ENV JAVA_HOME /usr/local/java/
ENV JRE_HOME ${JAVA_HOME}/jre
ENV CLASSPATH .:${JAVA_HOME}/lib:${JRE_HOME}/lib
ENV PATH ${JAVA_HOME}/bin:$PATH
#ENV JAVA_HOME /usr/local/java/
#ENV JRE_HOME ${JAVA_HOME}/jre
#ENV CLASSPATH .:${JAVA_HOME}/lib:${JRE_HOME}/lib
#ENV PATH ${JAVA_HOME}/bin:$PATH
RUN java -version && javac -version
#RUN sed -i 's/deb.debian.org/mirrors.aliyun.com/g' /etc/apt/sources.list.d/debian.sources && \
RUN apt-get update && \
apt-get install -y maven && \
rm -rf /var/lib/apt/lists/*
COPY . /build
WORKDIR /build
RUN ls && mvn clean package -Dmaven.test.skip=true
WORKDIR /build/target
RUN mv wvp-pro-*.jar wvp.jar
FROM ringcentral/jdk:11
RUN mkdir -p /opt/wvp
WORKDIR /opt/wvp
COPY ./wvp /opt/wvp
WORKDIR /home
RUN cd /home && \
git clone https://gitee.com/pan648540858/wvp-GB28181-pro.git
RUN cd /home/wvp-GB28181-pro && \
mvn clean package -Dmaven.test.skip=true && \
cp /home/wvp-GB28181-pro/target/*.jar /opt/wvp/wvp.jar
WORKDIR /opt/wvp
COPY --from=builder /build/target /opt/wvp
COPY ./docker/wvp/wvp /opt/wvp
ENTRYPOINT ["java", "-Xms512m", "-Xmx1024m", "-XX:+HeapDumpOnOutOfMemoryError", "-XX:HeapDumpPath=/opt/ylcx/", "-jar", "wvp.jar", "--spring.config.location=/opt/ylcx/wvp/application.yml"]
#RUN mkdir -p /opt/wvp
#WORKDIR /opt/wvp
#COPY ./wvp /opt/wvp
#
#WORKDIR /home
#RUN cd /home && \
#git clone https://gitee.com/pan648540858/wvp-GB28181-pro.git
#
#RUN cd /home/wvp-GB28181-pro && \
#mvn clean package -Dmaven.test.skip=true && \
#cp /home/wvp-GB28181-pro/target/*.jar /opt/wvp/wvp.jar
#
#WORKDIR /opt/wvp
#ENTRYPOINT ["java", "-Xms512m", "-Xmx1024m", "-XX:+HeapDumpOnOutOfMemoryError", "-XX:HeapDumpPath=/opt/ylcx/", "-jar", "wvp.jar", "--spring.config.location=/opt/ylcx/wvp/application.yml"]

View File

@ -1,10 +1,12 @@
spring:
cache:
type: redis
thymeleaf:
cache: false
# 设置接口超时时间
mvc:
async:
request-timeout: 20000
thymeleaf:
cache: false
# [可选]上传文件大小限制
servlet:
multipart:
@ -21,9 +23,16 @@ spring:
# [可选] 访问密码,若你的redis服务器没有设置密码就不需要用密码去连接
password:
# [可选] 超时时间
timeout: 30000
# mysql数据源
timeout: 10000
## [可选] 一个pool最多可分配多少个jedis实例
#poolMaxTotal: 1000
## [可选] 一个pool最多有多少个状态为idle(空闲)的jedis实例
#poolMaxIdle: 500
## [可选] 最大的等待时间(秒)
#poolMaxWait: 5
# [必选] jdbc数据库配置
datasource:
# mysql数据源
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://${DATABASE_HOST:127.0.0.1}:${DATABASE_PORT:3306}/wvp?useUnicode=true&characterEncoding=UTF8&rewriteBatchedStatements=true&serverTimezone=PRC&useSSL=false&allowMultiQueries=true&allowPublicKeyRetrieval=true
@ -35,39 +44,64 @@ server:
port: 18978
ssl:
# [可选] 是否开启HTTPS访问
# docker里运行内部不需要HTTPS
enabled: false
# 作为28181服务器的配置
sip:
# [必须修改] 本机的IP
ip: ${SIP_HOST:127.0.0.1}
# [必须修改] 本机的IP对应你的网卡监听什么ip就是使用什么网卡
# 如果要监听多张网卡可以使用逗号分隔多个IP 例如: 192.168.1.4,10.0.0.4
# 如果不明白就使用0.0.0.0,大部分情况都是可以的
# 请不要使用127.0.0.1任何包括localhost在内的域名都是不可以的。
ip: 0.0.0.0
# [可选] 没有任何业务需求,仅仅是在前端展示的时候用
show-ip: ${SIP_ShowIP}
# [可选]
port: 8116
port: ${SIP_Port:8116}
# 根据国标6.1.2中规定domain宜采用ID统一编码的前十位编码。国标附录D中定义前8位为中心编码由省级、市级、区级、基层编号组成参照GB/T 2260-2007
# 后两位为行业编码定义参照附录D.3
# 3701020049标识山东济南历下区 信息行业接入
# [可选]
domain: 3402000000
domain: ${SIP_Domain:3402000000}
# [可选]
id: 34020000002000000001
password:
id: ${SIP_Id:34020000002000000001}
# [可选] 默认设备认证密码,后续扩展使用设备单独密码, 移除密码将不进行校验
password: ${SIP_Password}
# [可选] 国标级联注册失败,再次发起注册的时间间隔。 默认60秒
register-time-interval: 60
# [可选] 云台控制速度
ptz-speed: 50
# TODO [可选] 收到心跳后自动上线, 重启服务后会将所有设备置为离线默认false等待注册后上线。设置为true则收到心跳设置为上线。
# keepalliveToOnline: false
# 是否存储alarm信息
alarm: true
# 命令发送等待回复的超时时间, 单位:毫秒
timeout: 1000
# 默认服务器配置
media:
id: polaris
# [必须修改] ZLM 内网IP与端口
ip: ${ZLM_HOST:127.0.0.1}
http-port: ${ZLM_PORT:6080}
http-port: 80
# [可选] 返回流地址时的ip置空使用 media.ip
stream-ip: ${STREAM_HOST:127.0.0.1}
stream-ip: ${Stream_IP}
# [可选] wvp在国标信令中使用的ip此ip为摄像机可以访问到的ip 置空使用 media.ip
sdp-ip: ${SIP_HOST:127.0.0.1}
# [可选] Hook IP, 默认使用sip.ip
hook-ip: ${SIP_HOST:127.0.0.1}
sdp-ip: ${SDP_IP}
# [可选] zlm服务器访问WVP所使用的IP, 默认使用127.0.0.1zlm和wvp没有部署在同一台服务器时必须配置
hook-ip: ${ZLM_HOOK_HOST}
# [可选] sslport
http-ssl-port: 4443
rtp-proxy-port: 10000
rtmp-port: 10935
rtmp-ssl-port: 41935
rtsp-port: 5540
rtsp-ssl-port: 45540
http-ssl-port: 0
flv-port: ${MediaHttp:}
flv-ssl-port: ${MediaHttps:}
ws-flv-port: ${MediaHttp:}
ws-flv-ssl-port: ${MediaHttps:}
rtp-proxy-port: ${MediaRtp:}
rtmp-port: ${MediaRtmp:}
rtmp-ssl-port: 0
rtsp-port: ${MediaRtsp:}
rtsp-ssl-port: 0
# [可选] 是否自动配置ZLM, 如果希望手动配置ZLM, 可以设为false, 不建议新接触的用户修改
auto-config: true
# [可选]
secret: ${ZLM_SERCERT}
# 启用多端口模式, 多端口模式使用端口区分每路流,兼容性更好。 单端口使用流的ssrc区分 点播超时建议使用多端口测试
@ -79,28 +113,28 @@ media:
# [可选]
send-port-range: 50502,50506
record-path: /opt/media/record
record-path: /opt/media/bin/www/record/
record-day: 7
record-assist-port: 0
user-settings:
auto-apply-play: true
play-timeout: 30000
wait-track: false
record-push-live: false
record-sip: false
record-push-live: ${RecordPushLive:false}
record-sip: ${RecordSip:false}
stream-on-demand: true
interface-authentication: false
interface-authentication: true
broadcast-for-platform: TCP-PASSIVE
push-stream-after-ack: true
send-to-platforms-when-id-lost: true
interface-authentication-excludes:
- /api/**
push-authority: false
allowed-origins:
- http://localhost:8080
- http://127.0.0.1:8080
- http://0.0.0.0:8080
- ${NGINX_HOST}
# - /api/**
push-authority: true
# allowed-origins:
# - http://localhost:8080
# - http://127.0.0.1:8080
# - http://0.0.0.0:8080
# - ${NGINX_HOST}
logging:
config: classpath:logback-spring.xml

Binary file not shown.

137
pom.xml
View File

@ -6,7 +6,7 @@
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.18</version>
<version>3.4.4</version>
</parent>
<groupId>com.genersoft</groupId>
@ -48,7 +48,6 @@
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.build.timestamp.format>MMddHHmm</maven.build.timestamp.format>
<maven-jar-plugin.version>3.1.1</maven-jar-plugin.version>
<!-- 依赖版本 -->
<snippetsDirectory>${project.build.directory}/generated-snippets</snippetsDirectory>
@ -56,6 +55,9 @@
<generated.asciidoc.directory>${project.build.directory}/asciidoc</generated.asciidoc.directory>
<asciidoctor.html.output.directory>${project.build.directory}/asciidoc/html</asciidoctor.html.output.directory>
<asciidoctor.pdf.output.directory>${project.build.directory}/asciidoc/pdf</asciidoctor.pdf.output.directory>
<maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target>
</properties>
<profiles>
@ -113,6 +115,17 @@
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<!-- 日志相关 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
@ -121,7 +134,7 @@
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.2</version>
<version>3.0.4</version>
<exclusions>
<exclusion>
<groupId>com.zaxxer</groupId>
@ -139,14 +152,13 @@
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<!-- 数据库监控页面 -->
<!-- h2 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.23</version>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>2.3.232</version>
</dependency>
<!-- mysql数据库 -->
<dependency>
<groupId>com.mysql</groupId>
@ -180,42 +192,48 @@
<systemPath>${basedir}/libs/jdbc-x86/kingbase8-8.6.0.jar</systemPath>
</dependency>
<!-- <dependency>-->
<!-- <groupId>cn.com.kingbase</groupId>-->
<!-- <artifactId>kingbase8</artifactId>-->
<!-- <version>8.6.0</version>-->
<!-- </dependency>-->
<!--Mybatis分页插件 -->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.4.6</version>
<version>2.1.1</version>
</dependency>
<!--在线文档 -->
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-ui</artifactId>
<version>1.6.10</version>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>2.8.8</version>
</dependency>
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-api</artifactId>
<version>2.8.8</version>
</dependency>
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-security</artifactId>
<version>1.6.10</version>
<version>1.8.0</version>
</dependency>
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-springdoc-ui</artifactId>
<version>3.0.3</version>
<artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId>
<version>4.5.0</version>
</dependency>
<!--参数校验 -->
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
</dependency>
<!-- 日志相关 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<!-- <dependency>-->
<!-- <groupId>javax.validation</groupId>-->
<!-- <artifactId>validation-api</artifactId>-->
<!-- <version>3.0.2</version>-->
<!-- </dependency>-->
<!-- sip协议栈 -->
<dependency>
@ -228,14 +246,14 @@
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>log4j-over-slf4j</artifactId>
<version>1.7.36</version>
<version>2.0.17</version>
</dependency>
<!-- xml解析库 -->
<dependency>
<groupId>org.dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>2.1.3</version>
<version>2.1.4</version>
</dependency>
<!-- json解析库fastjson2 -->
@ -259,21 +277,21 @@
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>4.10.0</version>
<version>4.12.0</version>
</dependency>
<!-- okhttp 调试日志 -->
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>logging-interceptor</artifactId>
<version>4.10.0</version>
<version>4.12.0</version>
</dependency>
<!-- okhttp-digest -->
<dependency>
<groupId>io.github.rburgst</groupId>
<artifactId>okhttp-digest</artifactId>
<version>2.7</version>
<version>3.1.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/net.sf.kxml/kxml2 -->
@ -287,21 +305,20 @@
<dependency>
<groupId>org.bitbucket.b_c</groupId>
<artifactId>jose4j</artifactId>
<version>0.9.3</version>
<version>0.9.6</version>
</dependency>
<!--反向代理-->
<dependency>
<groupId>org.mitre.dsmiley.httpproxy</groupId>
<artifactId>smiley-http-proxy-servlet</artifactId>
<version>1.12.1</version>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.14</version>
</dependency>
<!--excel解析库-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>3.3.2</version>
<version>4.0.3</version>
<exclusions>
<exclusion>
<groupId>org.apache.commons</groupId>
@ -312,43 +329,44 @@
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-compress</artifactId>
<version>1.24.0</version>
<version>1.27.1</version>
</dependency>
<!-- 获取系统信息 -->
<dependency>
<groupId>com.github.oshi</groupId>
<artifactId>oshi-core</artifactId>
<version>6.2.2</version>
<version>6.6.5</version>
</dependency>
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-core</artifactId>
</dependency>
<!-- 检测文件编码 -->
<!-- https://mvnrepository.com/artifact/cpdetector/cpdetector -->
<!--<dependency>-->
<!-- <groupId>cpdetector</groupId>-->
<!-- <artifactId>cpdetector</artifactId>-->
<!-- <version>1.0.8</version>-->
<!--</dependency>-->
<!-- https://mvnrepository.com/artifact/com.google.guava/guava -->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>32.1.3-jre</version>
<version>33.4.8-jre</version>
</dependency>
<!--ftp server-->
<dependency>
<groupId>org.apache.ftpserver</groupId>
<artifactId>ftpserver-core</artifactId>
<version>1.2.1</version>
</dependency>
<dependency>
<groupId>org.apache.ftpserver</groupId>
<artifactId>ftplet-api</artifactId>
<version>1.2.1</version>
</dependency>
<!-- 自动化生成代码工具 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.30</version>
<version>1.18.38</version>
<scope>provided</scope>
</dependency>
<!--LogViewer-->
<!-- <dependency>-->
<!-- <groupId>io.github.sevdokimov.logviewer</groupId>-->
@ -361,6 +379,7 @@
<artifactId>log-viewer-spring-boot</artifactId>
<version>1.0.10</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
@ -374,7 +393,7 @@
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.7.2</version>
<version>3.4.10</version>
<configuration>
<includeSystemScope>true</includeSystemScope>
<executable>true</executable>
@ -384,10 +403,10 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<version>3.14.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<source>21</source>
<target>21</target>
<annotationProcessorPaths>
<path>
<groupId>org.projectlombok</groupId>
@ -401,7 +420,7 @@
<plugin>
<groupId>pl.project13.maven</groupId>
<artifactId>git-commit-id-plugin</artifactId>
<version>3.0.1</version>
<version>4.9.10</version>
<configuration>
<offline>true</offline>
<failOnNoGitDirectory>false</failOnNoGitDirectory>
@ -412,7 +431,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.2</version>
<version>3.2.5</version>
<configuration>
<skipTests>true</skipTests>
</configuration>
@ -421,7 +440,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.3.0</version>
<version>3.4.2</version>
<configuration>
<excludes>
<exclude>**/配置详情.yml</exclude>

View File

@ -13,10 +13,10 @@ import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.scheduling.annotation.EnableScheduling;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.SessionCookieConfig;
import javax.servlet.SessionTrackingMode;
import jakarta.servlet.ServletContext;
import jakarta.servlet.ServletException;
import jakarta.servlet.SessionCookieConfig;
import jakarta.servlet.SessionTrackingMode;
import java.util.Collections;
/**

View File

@ -79,6 +79,8 @@ public class StreamInfo implements Serializable, Cloneable{
private String startTime;
@Schema(description = "结束时间")
private String endTime;
@Schema(description = "时长(回放时使用)")
private Double duration;
@Schema(description = "进度(录像下载使用)")
private double progress;
@Schema(description = "文件下载地址(录像下载使用)")
@ -101,87 +103,112 @@ public class StreamInfo implements Serializable, Cloneable{
@Schema(description = "使用的WVP ID")
private String serverId;
public void setRtmp(String host, int port, int sslPort, String app, String stream, String callIdParam) {
@Schema(description = "流绑定的流媒体操作key")
private String key;
public void setRtmp(String host, Integer port, Integer sslPort, String app, String stream, String callIdParam) {
String file = String.format("%s/%s%s", app, stream, callIdParam);
if (port > 0) {
if (port != null && port > 0) {
this.rtmp = new StreamURL("rtmp", host, port, file);
}
if (sslPort > 0) {
if (sslPort != null && sslPort > 0) {
this.rtmps = new StreamURL("rtmps", host, sslPort, file);
}
}
public void setRtsp(String host, int port, int sslPort, String app, String stream, String callIdParam) {
public void setRtsp(String host, Integer port, Integer sslPort, String app, String stream, String callIdParam) {
String file = String.format("%s/%s%s", app, stream, callIdParam);
if (port > 0) {
if (port != null && port > 0) {
this.rtsp = new StreamURL("rtsp", host, port, file);
}
if (sslPort > 0) {
if (sslPort != null && sslPort > 0) {
this.rtsps = new StreamURL("rtsps", host, sslPort, file);
}
}
public void setFlv(String host, int port, int sslPort, String file) {
if (port > 0) {
public void setFlv(String host, Integer port, Integer sslPort, String file) {
if (port != null && port > 0) {
this.flv = new StreamURL("http", host, port, file);
}
this.ws_flv = new StreamURL("ws", host, port, file);
if (sslPort > 0) {
if (sslPort != null && sslPort > 0) {
this.https_flv = new StreamURL("https", host, sslPort, file);
this.wss_flv = new StreamURL("wss", host, sslPort, file);
}
}
public void setWsFlv(String host, int port, int sslPort, String file) {
if (port > 0) {
public void setWsFlv(String host, Integer port, Integer sslPort, String file) {
if (port != null && port > 0) {
this.ws_flv = new StreamURL("ws", host, port, file);
}
if (sslPort > 0) {
if (sslPort != null && sslPort > 0) {
this.wss_flv = new StreamURL("wss", host, sslPort, file);
}
}
public void setFmp4(String host, int port, int sslPort, String app, String stream, String callIdParam) {
String file = String.format("%s/%s.live.mp4%s", app, stream, callIdParam);
if (port > 0) {
public void setFmp4(String host, Integer port, Integer sslPort, String file) {
if (port != null && port > 0) {
this.fmp4 = new StreamURL("http", host, port, file);
}
if (sslPort != null && sslPort > 0) {
this.https_fmp4 = new StreamURL("https", host, sslPort, file);
}
}
public void setWsMp4(String host, Integer port, Integer sslPort, String file) {
if (port != null && port > 0) {
this.ws_fmp4 = new StreamURL("ws", host, port, file);
}
if (sslPort > 0) {
this.https_fmp4 = new StreamURL("https", host, sslPort, file);
if (sslPort != null && sslPort > 0) {
this.wss_fmp4 = new StreamURL("wss", host, sslPort, file);
}
}
public void setHls(String host, int port, int sslPort, String app, String stream, String callIdParam) {
public void setHls(String host, Integer port, Integer sslPort, String app, String stream, String callIdParam) {
String file = String.format("%s/%s/hls.m3u8%s", app, stream, callIdParam);
if (port > 0) {
if (port != null && port > 0) {
this.hls = new StreamURL("http", host, port, file);
}
if (sslPort != null && sslPort > 0) {
this.https_hls = new StreamURL("https", host, sslPort, file);
}
}
public void setWsHls(String host, Integer port, Integer sslPort, String app, String stream, String callIdParam) {
String file = String.format("%s/%s/hls.m3u8%s", app, stream, callIdParam);
if (port != null && port > 0) {
this.ws_hls = new StreamURL("ws", host, port, file);
}
if (sslPort > 0) {
this.https_hls = new StreamURL("https", host, sslPort, file);
if (sslPort != null && sslPort > 0) {
this.wss_hls = new StreamURL("wss", host, sslPort, file);
}
}
public void setTs(String host, int port, int sslPort, String app, String stream, String callIdParam) {
public void setTs(String host, Integer port, Integer sslPort, String app, String stream, String callIdParam) {
String file = String.format("%s/%s.live.ts%s", app, stream, callIdParam);
if (port > 0) {
if (port != null && port > 0) {
this.ts = new StreamURL("http", host, port, file);
}
if (sslPort != null && sslPort > 0) {
this.https_ts = new StreamURL("https", host, sslPort, file);
}
}
public void setWsTs(String host, Integer port, Integer sslPort, String app, String stream, String callIdParam) {
String file = String.format("%s/%s.live.ts%s", app, stream, callIdParam);
if (port != null && port > 0) {
this.ws_ts = new StreamURL("ws", host, port, file);
}
if (sslPort > 0) {
this.https_ts = new StreamURL("https", host, sslPort, file);
if (sslPort != null && sslPort > 0) {
this.wss_ts = new StreamURL("wss", host, sslPort, file);
}
}
public void setRtc(String host, int port, int sslPort, String app, String stream, String callIdParam, boolean isPlay) {
public void setRtc(String host, Integer port, Integer sslPort, String app, String stream, String callIdParam, boolean isPlay) {
if (callIdParam != null) {
callIdParam = Objects.equals(callIdParam, "") ? callIdParam : callIdParam.replace("?", "&");
}
// String file = String.format("%s/%s?type=%s%s", app, stream, isPlay?"play":"push", callIdParam);
String file = String.format("index/api/webrtc?app=%s&stream=%s&type=%s%s", app, stream, isPlay?"play":"push", callIdParam);
if (port > 0) {
this.rtc = new StreamURL("http", host, port, file);

View File

@ -75,6 +75,21 @@ public class VideoManagerConstants {
*/
public static final String VM_MSG_PUSH_STREAM_LIST_CHANGE = "VM_MSG_PUSH_STREAM_LIST_CHANGE";
/**
* 请求同步三方组织结构
*/
public static final String VM_MSG_GROUP_LIST_REQUEST = "VM_MSG_GROUP_LIST_REQUEST";
/**
* 同步三方组织结构回复
*/
public static final String VM_MSG_GROUP_LIST_RESPONSE = "VM_MSG_GROUP_LIST_RESPONSE";
/**
* 同步三方组织结构回复
*/
public static final String VM_MSG_GROUP_LIST_CHANGE = "VM_MSG_GROUP_LIST_CHANGE";
/**
* redis 消息通知设备推流到平台
*/
@ -153,4 +168,15 @@ public class VideoManagerConstants {
*/
public static final String REDIS_RECORD_INFO_RES_COUNT_PRE = "GB_RECORD_INFO_RES_COUNT:";
//************************** 1078 ****************************************
public static final String INVITE_INFO_1078_POSITION = "INVITE_INFO_1078_POSITION:";
public static final String INVITE_INFO_1078_PLAY = "INVITE_INFO_1078_PLAY:";
public static final String INVITE_INFO_1078_PLAYBACK = "INVITE_INFO_1078_PLAYBACK:";
public static final String INVITE_INFO_1078_TALK = "INVITE_INFO_1078_TALK:";
public static final String RECORD_LIST_1078 = "RECORD_LIST_1078:";
}

View File

@ -4,18 +4,18 @@ package com.genersoft.iot.vmp.common.enums;
* 支持的通道数据类型
*/
public enum ChannelDataType {
public class ChannelDataType {
GB28181(1,"国标28181"),
STREAM_PUSH(2,"推流设备"),
STREAM_PROXY(3,"拉流代理");
public final static int GB28181 = 1;
public final static int STREAM_PUSH = 2;
public final static int STREAM_PROXY = 3;
public final static int JT_1078 = 200;
public final static String PLAY_SERVICE = "sourceChannelPlayService";
public final static String PLAYBACK_SERVICE = "sourceChannelPlaybackService";
public final static String DOWNLOAD_SERVICE = "sourceChannelDownloadService";
public final static String PTZ_SERVICE = "sourceChannelPTZService";
public final int value;
public final String desc;
ChannelDataType(Integer value, String desc) {
this.value = value;
this.desc = desc;
}
}

View File

@ -6,7 +6,7 @@ import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import jakarta.annotation.PostConstruct;
import java.time.Instant;
import java.util.Date;
import java.util.Map;

View File

@ -2,6 +2,7 @@ package com.genersoft.iot.vmp.conf;
import com.genersoft.iot.vmp.media.bean.MediaServer;
import com.genersoft.iot.vmp.utils.DateUtil;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
@ -15,6 +16,7 @@ import java.util.regex.Pattern;
@Slf4j
@Configuration("mediaConfig")
@Order(0)
@Data
public class MediaConfig{
// 修改必须配置不再支持自动获取
@ -45,6 +47,9 @@ public class MediaConfig{
@Value("${media.flv-port:0}")
private Integer flvPort = 0;
@Value("${media.mp4-port:0}")
private Integer mp4Port = 0;
@Value("${media.ws-flv-port:0}")
private Integer wsFlvPort = 0;
@ -66,6 +71,9 @@ public class MediaConfig{
@Value("${media.rtp-proxy-port:0}")
private Integer rtpProxyPort = 0;
@Value("${media.jtt-proxy-port:0}")
private Integer jttProxyPort = 0;
@Value("${media.rtsp-port:0}")
private Integer rtspPort = 0;
@ -99,33 +107,7 @@ public class MediaConfig{
@Value("${media.type:zlm}")
private String type;
public String getId() {
return id;
}
public String getIp() {
return ip;
}
public String getHookIp() {
return hookIp;
}
public int getHttpPort() {
return httpPort;
}
public int getHttpSSlPort() {
return httpSSlPort;
}
public int getRtmpPort() {
return rtmpPort;
}
public int getRtmpSSlPort() {
return rtmpSSlPort;
}
public int getRtpProxyPort() {
if (rtpProxyPort == null) {
@ -136,32 +118,12 @@ public class MediaConfig{
}
public int getRtspPort() {
return rtspPort;
public Integer getJttProxyPort() {
if (jttProxyPort == null) {
return 0;
}else {
return jttProxyPort;
}
public int getRtspSSLPort() {
return rtspSSLPort;
}
public boolean isAutoConfig() {
return autoConfig;
}
public String getSecret() {
return secret;
}
public boolean isRtpEnable() {
return rtpEnable;
}
public String getRtpPortRange() {
return rtpPortRange;
}
public int getRecordAssistPort() {
return recordAssistPort;
}
public String getSdpIp() {
@ -191,10 +153,6 @@ public class MediaConfig{
}
}
public String getSipDomain() {
return sipDomain;
}
public MediaServer getMediaSerItem(){
MediaServer mediaServer = new MediaServer();
mediaServer.setId(id);
@ -204,31 +162,17 @@ public class MediaConfig{
mediaServer.setSdpIp(getSdpIp());
mediaServer.setStreamIp(getStreamIp());
mediaServer.setHttpPort(httpPort);
if (flvPort == 0) {
mediaServer.setFlvPort(httpPort);
}else {
mediaServer.setFlvPort(flvPort);
}
if (wsFlvPort == 0) {
mediaServer.setWsFlvPort(httpPort);
}else {
mediaServer.setMp4Port(mp4Port);
mediaServer.setWsFlvPort(wsFlvPort);
}
if (flvSSlPort == 0) {
mediaServer.setFlvSSLPort(httpSSlPort);
}else {
mediaServer.setFlvSSLPort(flvSSlPort);
}
if (wsFlvSSlPort == 0) {
mediaServer.setWsFlvSSLPort(httpSSlPort);
}else {
mediaServer.setWsFlvSSLPort(wsFlvSSlPort);
}
mediaServer.setHttpSSlPort(httpSSlPort);
mediaServer.setRtmpPort(rtmpPort);
mediaServer.setRtmpSSlPort(rtmpSSlPort);
mediaServer.setRtpProxyPort(getRtpProxyPort());
mediaServer.setJttProxyPort(getJttProxyPort());
mediaServer.setRtspPort(rtspPort);
mediaServer.setRtspSSLPort(rtspSSLPort);
mediaServer.setAutoConfig(autoConfig);
@ -250,42 +194,10 @@ public class MediaConfig{
return mediaServer;
}
public Integer getRecordDay() {
return recordDay;
}
public void setRecordDay(Integer recordDay) {
this.recordDay = recordDay;
}
public String getRecordPath() {
return recordPath;
}
public void setRecordPath(String recordPath) {
this.recordPath = recordPath;
}
public String getRtpSendPortRange() {
return rtpSendPortRange;
}
public void setRtpSendPortRange(String rtpSendPortRange) {
this.rtpSendPortRange = rtpSendPortRange;
}
private boolean isValidIPAddress(String ipAddress) {
if ((ipAddress != null) && (!ipAddress.isEmpty())) {
return Pattern.matches("^([1-9]|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])(\\.(\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])){3}$", ipAddress);
}
return false;
}
public String getWanIp() {
return wanIp;
}
public void setWanIp(String wanIp) {
this.wanIp = wanIp;
}
}

View File

@ -1,301 +0,0 @@
package com.genersoft.iot.vmp.conf;
import com.genersoft.iot.vmp.media.bean.MediaServer;
import com.genersoft.iot.vmp.media.service.IMediaServerService;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpHost;
import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
import org.mitre.dsmiley.httpproxy.ProxyServlet;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.util.ObjectUtils;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.ConnectException;
/**
* @author lin
*/
@SuppressWarnings(value = {"rawtypes", "unchecked"})
@Configuration
@Order(1)
@Slf4j
public class ProxyServletConfig {
@Autowired
private IMediaServerService mediaServerService;
@Value("${server.port}")
private int serverPort;
@Bean
public ServletRegistrationBean zlmServletRegistrationBean(){
ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new ZlmProxyServlet(),"/zlm/*");
servletRegistrationBean.setName("zlm_Proxy");
servletRegistrationBean.addInitParameter("targetUri", "http://127.0.0.1:6080");
servletRegistrationBean.addUrlMappings();
if (log.isDebugEnabled()) {
servletRegistrationBean.addInitParameter("log", "true");
}
return servletRegistrationBean;
}
class ZlmProxyServlet extends ProxyServlet{
@Override
protected String rewriteQueryStringFromRequest(HttpServletRequest servletRequest, String queryString) {
String queryStr = super.rewriteQueryStringFromRequest(servletRequest, queryString);
MediaServer mediaInfo = getMediaInfoByUri(servletRequest.getRequestURI());
if (mediaInfo != null) {
if (!ObjectUtils.isEmpty(queryStr)) {
queryStr += "&secret=" + mediaInfo.getSecret();
}else {
queryStr = "secret=" + mediaInfo.getSecret();
}
}
return queryStr;
}
@Override
protected HttpResponse doExecute(HttpServletRequest servletRequest, HttpServletResponse servletResponse,
HttpRequest proxyRequest) throws IOException {
HttpResponse response = super.doExecute(servletRequest, servletResponse, proxyRequest);
response.removeHeaders("Access-Control-Allow-Origin");
response.setHeader("Access-Control-Allow-Credentials","true");
response.removeHeaders("Access-Control-Allow-Credentials");
return response;
}
/**
* 异常处理
*/
@Override
protected void handleRequestException(HttpRequest proxyRequest, HttpResponse proxyResonse, Exception e){
try {
super.handleRequestException(proxyRequest, proxyResonse, e);
} catch (ServletException servletException) {
log.error("zlm 代理失败: ", e);
} catch (IOException ioException) {
if (ioException instanceof ConnectException) {
log.error("zlm 连接失败");
} else {
log.error("zlm 代理失败: ", e);
}
} catch (RuntimeException exception){
log.error("zlm 代理失败: ", e);
}
}
/**
* 对于为按照格式请求的可以直接返回404
*/
@Override
protected String getTargetUri(HttpServletRequest servletRequest) {
String requestURI = servletRequest.getRequestURI();
MediaServer mediaInfo = getMediaInfoByUri(requestURI);
String uri = null;
if (mediaInfo != null) {
// String realRequestURI = requestURI.substring(requestURI.indexOf(mediaInfo.getId())+ mediaInfo.getId().length());
uri = String.format("http://%s:%s", mediaInfo.getIp(), mediaInfo.getHttpPort());
}else {
uri = "http://127.0.0.1:" + serverPort +"/index/hook/null"; // 只是一个能返回404的请求而已 其他的也可以
}
return uri;
}
/**
* 动态替换请求目标
*/
@Override
protected HttpHost getTargetHost(HttpServletRequest servletRequest) {
String requestURI = servletRequest.getRequestURI();
MediaServer mediaInfo = getMediaInfoByUri(requestURI);
HttpHost host;
if (mediaInfo != null) {
host = new HttpHost(mediaInfo.getIp(), mediaInfo.getHttpPort());
}else {
host = new HttpHost("127.0.0.1", serverPort);
}
return host;
}
/**
* 根据uri获取流媒体信息
*/
MediaServer getMediaInfoByUri(String uri){
String[] split = uri.split("/");
String mediaServerId = split[2];
if ("default".equalsIgnoreCase(mediaServerId)) {
return mediaServerService.getDefaultMediaServer();
}else {
return mediaServerService.getOne(mediaServerId);
}
}
/**
* 去掉url中的标志信息
*/
@Override
protected String rewriteUrlFromRequest(HttpServletRequest servletRequest) {
String requestURI = servletRequest.getRequestURI();
MediaServer mediaInfo = getMediaInfoByUri(requestURI);
String url = super.rewriteUrlFromRequest(servletRequest);
if (mediaInfo == null) {
log.error("[ZLM服务访问代理]错误处理url信息时未找到流媒体信息=>{}", requestURI);
return url;
}
if (!ObjectUtils.isEmpty(mediaInfo.getId())) {
url = url.replace(mediaInfo.getId() + "/", "");
}
return url.replace("default/", "");
}
}
@Bean
public ServletRegistrationBean recordServletRegistrationBean(){
ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new RecordProxyServlet(),"/record_proxy/*");
servletRegistrationBean.setName("record_proxy");
servletRegistrationBean.addInitParameter("targetUri", "http://127.0.0.1:18081");
servletRegistrationBean.addUrlMappings();
if (log.isDebugEnabled()) {
servletRegistrationBean.addInitParameter("log", "true");
}
return servletRegistrationBean;
}
class RecordProxyServlet extends ProxyServlet{
@Override
protected String rewriteQueryStringFromRequest(HttpServletRequest servletRequest, String queryString) {
String queryStr = super.rewriteQueryStringFromRequest(servletRequest, queryString);
MediaServer mediaInfo = getMediaInfoByUri(servletRequest.getRequestURI());
if (mediaInfo == null) {
return null;
}
String remoteHost = String.format("http://%s:%s", mediaInfo.getStreamIp(), mediaInfo.getRecordAssistPort());
if (!ObjectUtils.isEmpty(queryStr)) {
queryStr += "&remoteHost=" + remoteHost;
}else {
queryStr = "remoteHost=" + remoteHost;
}
return queryStr;
}
@Override
protected HttpResponse doExecute(HttpServletRequest servletRequest, HttpServletResponse servletResponse,
HttpRequest proxyRequest) throws IOException {
HttpResponse response = super.doExecute(servletRequest, servletResponse, proxyRequest);
String origin = servletRequest.getHeader("origin");
response.setHeader("Access-Control-Allow-Origin",origin);
response.setHeader("Access-Control-Allow-Credentials","true");
return response;
}
/**
* 异常处理
*/
@Override
protected void handleRequestException(HttpRequest proxyRequest, HttpResponse proxyResponse, Exception e){
try {
super.handleRequestException(proxyRequest, proxyResponse, e);
} catch (ServletException servletException) {
log.error("录像服务 代理失败: ", e);
} catch (IOException ioException) {
if (ioException instanceof ConnectException) {
log.error("录像服务 连接失败");
// }else if (ioException instanceof ClientAbortException) {
// /**
// * TODO 使用这个代理库实现代理在遇到代理视频文件时如果是206结果会遇到报错蛋市目前功能正常
// * TODO 暂时去除异常处理后续使用其他代理框架修改测试
// */
}else {
log.error("录像服务 代理失败: ", e);
}
} catch (RuntimeException exception){
log.error("录像服务 代理失败: ", e);
}
}
/**
* 对于为按照格式请求的可以直接返回404
*/
@Override
protected String getTargetUri(HttpServletRequest servletRequest) {
String requestURI = servletRequest.getRequestURI();
MediaServer mediaInfo = getMediaInfoByUri(requestURI);
String uri = null;
if (mediaInfo != null) {
// String realRequestURI = requestURI.substring(requestURI.indexOf(mediaInfo.getId())+ mediaInfo.getId().length());
uri = String.format("http://%s:%s", mediaInfo.getIp(), mediaInfo.getRecordAssistPort());
}else {
uri = "http://127.0.0.1:" + serverPort +"/index/hook/null"; // 只是一个能返回404的请求而已 其他的也可以
}
return uri;
}
/**
* 动态替换请求目标
*/
@Override
protected HttpHost getTargetHost(HttpServletRequest servletRequest) {
String requestURI = servletRequest.getRequestURI();
MediaServer mediaInfo = getMediaInfoByUri(requestURI);
HttpHost host;
if (mediaInfo != null) {
host = new HttpHost(mediaInfo.getIp(), mediaInfo.getRecordAssistPort());
}else {
host = new HttpHost("127.0.0.1", serverPort);
}
return host;
}
/**
* 根据uri获取流媒体信息
*/
MediaServer getMediaInfoByUri(String uri){
String[] split = uri.split("/");
String mediaServerId = split[2];
if ("default".equalsIgnoreCase(mediaServerId)) {
return mediaServerService.getDefaultMediaServer();
}else {
return mediaServerService.getOne(mediaServerId);
}
}
/**
* 去掉url中的标志信息
*/
@Override
protected String rewriteUrlFromRequest(HttpServletRequest servletRequest) {
String requestURI = servletRequest.getRequestURI();
MediaServer mediaInfo = getMediaInfoByUri(requestURI);
String url = super.rewriteUrlFromRequest(servletRequest);
if (mediaInfo == null) {
log.error("[录像服务访问代理]错误处理url信息时未找到流媒体信息=>{}", requestURI);
return url;
}
if (!ObjectUtils.isEmpty(mediaInfo.getId())) {
url = url.replace(mediaInfo.getId() + "/", "");
}
return url.replace("default/", "");
}
}
}

View File

@ -1,5 +1,6 @@
package com.genersoft.iot.vmp.conf;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.web.context.WebServerInitializedEvent;
import org.springframework.context.ApplicationListener;
@ -9,17 +10,14 @@ import org.springframework.stereotype.Component;
@Component
public class ServiceInfo implements ApplicationListener<WebServerInitializedEvent> {
@Getter
private static int serverPort;
public static int getServerPort() {
return serverPort;
}
@Override
public void onApplicationEvent(WebServerInitializedEvent event) {
// 项目启动获取启动的端口号
ServiceInfo.serverPort = event.getWebServer().getPort();
log.info("项目启动获取启动的端口号: " + ServiceInfo.serverPort);
log.info("项目启动获取启动的端口号: {}", ServiceInfo.serverPort);
}
public void setServerPort(int serverPort) {

View File

@ -98,4 +98,12 @@ public class SpringDocConfig {
.packagesToScan("com.genersoft.iot.vmp.user")
.build();
}
@Bean
public GroupedOpenApi publicApi7() {
return GroupedOpenApi.builder()
.group("6. 部标设备")
.packagesToScan("com.genersoft.iot.vmp.jt1078.controller")
.build();
}
}

View File

@ -204,6 +204,19 @@ public class UserSetting {
*/
private boolean sipCacheServerConnections = true;
/**
* 禁用date头变相禁用了校时
*/
private boolean disableDateHeader = false;
/**
* 同步业务分组时自动生成分组国标编号的模板不配置则默认参考当前的sip域信息生成
*/
private String groupSyncDeviceTemplate;
/**
* 与第三方进行分组同步时使用别名而不是分组ID 如果没有设置此项为true那么分组编号就是必须传递的如果是设置为true则自动为别名的分组生成新的编号
*/
private boolean useAliasForGroupSync = false;
}

View File

@ -0,0 +1,8 @@
package com.genersoft.iot.vmp.conf.ftpServer;
import java.io.OutputStream;
public interface FileCallback {
OutputStream run(String path);
}

View File

@ -0,0 +1,17 @@
package com.genersoft.iot.vmp.conf.ftpServer;
import org.apache.ftpserver.ftplet.Authority;
import org.apache.ftpserver.ftplet.AuthorizationRequest;
public class FtpAuthority implements Authority {
@Override
public boolean canAuthorize(AuthorizationRequest authorizationRequest) {
return true;
}
@Override
public AuthorizationRequest authorize(AuthorizationRequest authorizationRequest) {
return authorizationRequest;
}
}

View File

@ -0,0 +1,33 @@
package com.genersoft.iot.vmp.conf.ftpServer;
import org.apache.ftpserver.ftplet.FileSystemFactory;
import org.apache.ftpserver.ftplet.FileSystemView;
import org.apache.ftpserver.ftplet.FtpException;
import org.apache.ftpserver.ftplet.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.io.OutputStream;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@Component
public class FtpFileSystemFactory implements FileSystemFactory {
private final Map<String, OutputStream> outputStreamMap = new ConcurrentHashMap<>();
@Override
public FileSystemView createFileSystemView(User user) throws FtpException {
return new FtpFileSystemView(user, path -> {
return outputStreamMap.get(path);
});
}
public void addOutputStream(String filePath, OutputStream outputStream) {
outputStreamMap.put(filePath, outputStream);
}
public void removeOutputStream(String filePath) {
outputStreamMap.remove(filePath);
}
}

View File

@ -0,0 +1,63 @@
package com.genersoft.iot.vmp.conf.ftpServer;
import org.apache.ftpserver.ftplet.FileSystemView;
import org.apache.ftpserver.ftplet.FtpException;
import org.apache.ftpserver.ftplet.FtpFile;
import org.apache.ftpserver.ftplet.User;
import java.io.OutputStream;
public class FtpFileSystemView implements FileSystemView {
private User user;
private FileCallback fileCallback;
public FtpFileSystemView(User user, FileCallback fileCallback) {
this.user = user;
this.fileCallback = fileCallback;
}
public static String HOME_PATH = "root";
public FtpFile workDir = VirtualFtpFile.getDir(HOME_PATH);
@Override
public FtpFile getHomeDirectory() throws FtpException {
return VirtualFtpFile.getDir(HOME_PATH);
}
@Override
public FtpFile getWorkingDirectory() throws FtpException {
return workDir;
}
@Override
public boolean changeWorkingDirectory(String dir) throws FtpException {
workDir = VirtualFtpFile.getDir(dir);
return true;
}
@Override
public FtpFile getFile(String file) throws FtpException {
VirtualFtpFile ftpFile = VirtualFtpFile.getFile(file);
if (fileCallback != null) {
OutputStream outputStream = fileCallback.run(workDir.getName());
if (outputStream != null) {
ftpFile.setOutputStream(outputStream);
}
}
return ftpFile;
}
@Override
public boolean isRandomAccessible() throws FtpException {
return true;
}
@Override
public void dispose() {
}
}

View File

@ -0,0 +1,69 @@
package com.genersoft.iot.vmp.conf.ftpServer;
import lombok.extern.slf4j.Slf4j;
import org.apache.ftpserver.*;
import org.apache.ftpserver.ftplet.FtpException;
import org.apache.ftpserver.listener.Listener;
import org.apache.ftpserver.listener.ListenerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.HashMap;
import java.util.Map;
@Configuration
@ConditionalOnProperty(value = "ftp.enable", havingValue = "true")
@Slf4j
public class FtpServerConfig {
@Autowired
private UserManager userManager;
@Autowired
private FtpFileSystemFactory fileSystemFactory;
@Autowired
private Ftplet ftplet;
@Autowired
private FtpSetting ftpSetting;
/**
* ftp server init
*/
@Bean
public FtpServer ftpServer() {
FtpServerFactory serverFactory = new FtpServerFactory();
ListenerFactory listenerFactory = new ListenerFactory();
// 1设置服务端口
listenerFactory.setPort(ftpSetting.getPort());
// 2设置被动模式数据上传的接口范围,云服务器需要开放对应区间的端口给客户端
DataConnectionConfigurationFactory dataConnectionConfFactory = new DataConnectionConfigurationFactory();
dataConnectionConfFactory.setPassivePorts(ftpSetting.getPassivePorts());
listenerFactory.setDataConnectionConfiguration(dataConnectionConfFactory.createDataConnectionConfiguration());
// 4替换默认的监听器
Listener listener = listenerFactory.createListener();
serverFactory.addListener("default", listener);
// 5配置自定义用户事件
Map<String, org.apache.ftpserver.ftplet.Ftplet> ftpLets = new HashMap<>();
ftpLets.put("ftpService", ftplet);
serverFactory.setFtplets(ftpLets);
// 6读取用户的配置信息
// 6.2设置用信息
serverFactory.setUserManager(userManager);
serverFactory.setFileSystem(fileSystemFactory);
// 7实例化FTP Server
FtpServer server = serverFactory.createServer();
try {
server.start();
if (!server.isStopped()) {
log.info("[FTP服务] 已启动, 端口: {}", ftpSetting.getPort());
}
} catch (FtpException e) {
log.info("[FTP服务] 启动失败 ", e);
}
return server;
}
}

View File

@ -0,0 +1,21 @@
package com.genersoft.iot.vmp.conf.ftpServer;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
/**
* 配置文件 user-settings 映射的配置信息
*/
@Component
@ConfigurationProperties(prefix = "ftp", ignoreInvalidFields = true)
@Order(0)
@Data
public class FtpSetting {
private Boolean enable = Boolean.FALSE;
private int port = 21;
private String passivePorts = "10000-10500";
}

View File

@ -0,0 +1,59 @@
package com.genersoft.iot.vmp.conf.ftpServer;
import com.genersoft.iot.vmp.jt1078.event.FtpUploadEvent;
import org.apache.ftpserver.ftplet.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Component;
import java.io.IOException;
@Component
public class Ftplet extends DefaultFtplet {
private final Logger logger = LoggerFactory.getLogger(Ftplet.class);
@Autowired
private ApplicationEventPublisher applicationEventPublisher;
@Override
public FtpletResult onUploadEnd(FtpSession session, FtpRequest request) throws FtpException, IOException {
FtpFile file = session.getFileSystemView().getFile(request.getArgument());
if (file == null) {
return super.onUploadEnd(session, request);
}
sendEvent(file.getAbsolutePath());
return super.onUploadUniqueEnd(session, request);
}
@Override
public FtpletResult onAppendEnd(FtpSession session, FtpRequest request) throws FtpException, IOException {
FtpFile file = session.getFileSystemView().getFile(request.getArgument());
if (file == null) {
return super.onUploadEnd(session, request);
}
sendEvent(file.getAbsolutePath());
return super.onUploadUniqueEnd(session, request);
}
@Override
public FtpletResult onUploadUniqueEnd(FtpSession session, FtpRequest request) throws FtpException, IOException {
FtpFile file = session.getFileSystemView().getFile(request.getArgument());
if (file == null) {
return super.onUploadEnd(session, request);
}
sendEvent(file.getAbsolutePath());
return super.onUploadUniqueEnd(session, request);
}
private void sendEvent(String filePath){
FtpUploadEvent event = new FtpUploadEvent(this);
logger.info("[文件已上传]: {}", filePath);
event.setFileName(filePath);
applicationEventPublisher.publishEvent(event);
}
}

View File

@ -0,0 +1,86 @@
package com.genersoft.iot.vmp.conf.ftpServer;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.ftpserver.ftplet.*;
import org.apache.ftpserver.usermanager.UsernamePasswordAuthentication;
import org.apache.ftpserver.usermanager.impl.BaseUser;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import java.io.File;
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
@Component
public class UserManager implements org.apache.ftpserver.ftplet.UserManager {
private static final String PREFIX = "VMP_FTP_USER_";
@Autowired
private RedisTemplate<Object, Object> redisTemplate;
@Override
public User getUserByName(String username) throws FtpException {
return (BaseUser)redisTemplate.opsForValue().get(PREFIX + username);
}
@Override
public String[] getAllUserNames() throws FtpException {
return new String[0];
}
@Override
public void delete(String username) throws FtpException {
}
@Override
public void save(User user) throws FtpException {}
@Override
public boolean doesExist(String username) throws FtpException {
return redisTemplate.opsForValue().get(PREFIX + username) != null;
}
@Override
public User authenticate(Authentication authentication) throws AuthenticationFailedException {
UsernamePasswordAuthentication usernamePasswordAuthentication = (UsernamePasswordAuthentication) authentication;
BaseUser user = (BaseUser)redisTemplate.opsForValue().get(PREFIX + usernamePasswordAuthentication.getUsername());
if (user != null && usernamePasswordAuthentication.getPassword().equals(user.getPassword())) {
return user;
}
return null;
}
@Override
public String getAdminName() throws FtpException {
return null;
}
@Override
public boolean isAdmin(String username) throws FtpException {
return false;
}
public BaseUser getRandomUser(){
BaseUser use = new BaseUser();
use.setName(RandomStringUtils.randomAlphabetic(6).toLowerCase());
use.setPassword(RandomStringUtils.randomAlphabetic(6).toLowerCase());
use.setEnabled(true);
use.setHomeDirectory("/");
List<Authority> authorities = new ArrayList<>();
authorities.add(new FtpAuthority());
use.setAuthorities(authorities);
String key = PREFIX + use.getName();
// 随机用户信息十分钟自动失效
Duration duration = Duration.ofMinutes(10);
redisTemplate.opsForValue().set(key, use, duration);
return use;
}
}

View File

@ -0,0 +1,166 @@
package com.genersoft.iot.vmp.conf.ftpServer;
import lombok.Setter;
import org.apache.ftpserver.ftplet.FtpFile;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Collections;
import java.util.List;
public class VirtualFtpFile implements FtpFile {
@Setter
private String name;
@Setter
private boolean hidden = false;
@Setter
private boolean directory = false;
@Setter
private String ownerName;
private Long lastModified = null;
@Setter
private long size = 0;
@Setter
private OutputStream outputStream;
public static VirtualFtpFile getFile(String name) {
VirtualFtpFile virtualFtpFile = new VirtualFtpFile();
virtualFtpFile.setName(name);
return virtualFtpFile;
}
public static VirtualFtpFile getDir(String name) {
if (name.endsWith("/")) {
name = name.replaceAll("/", "");
}
VirtualFtpFile virtualFtpFile = new VirtualFtpFile();
virtualFtpFile.setName(name);
virtualFtpFile.setDirectory(true);
return virtualFtpFile;
}
@Override
public String getAbsolutePath() {
return FtpFileSystemView.HOME_PATH + "/" + name;
}
@Override
public String getName() {
return name;
}
@Override
public boolean isHidden() {
return hidden;
}
@Override
public boolean isDirectory() {
return directory;
}
@Override
public boolean isFile() {
return !directory;
}
@Override
public boolean doesExist() {
return false;
}
@Override
public boolean isReadable() {
return true;
}
@Override
public boolean isWritable() {
return true;
}
@Override
public boolean isRemovable() {
return true;
}
@Override
public String getOwnerName() {
return ownerName;
}
@Override
public String getGroupName() {
return "root";
}
@Override
public int getLinkCount() {
return 0;
}
@Override
public long getLastModified() {
if (lastModified == null) {
lastModified = System.currentTimeMillis();
}
return lastModified;
}
@Override
public boolean setLastModified(long time) {
lastModified = time;
return true;
}
@Override
public long getSize() {
return size;
}
@Override
public Object getPhysicalFile() {
System.err.println("getPhysicalFile");
return null;
}
@Override
public boolean mkdir() {
return true;
}
@Override
public boolean delete() {
return true;
}
@Override
public boolean move(FtpFile destination) {
this.name = destination.getName();
return true;
}
@Override
public List<? extends FtpFile> listFiles() {
return Collections.emptyList();
}
@Override
public OutputStream createOutputStream(long offset) throws IOException {
return outputStream;
}
@Override
public InputStream createInputStream(long offset) throws IOException {
System.out.println("createInputStream----");
return null;
}
}

View File

@ -34,6 +34,11 @@ public class RedisMsgListenConfig {
@Autowired
private RedisPushStreamListMsgListener pushStreamListMsgListener;
@Autowired
private RedisGroupMsgListener groupMsgListener;
@Autowired
private RedisGroupChangeListener groupChangeListener;
@Autowired
private RedisCloseStreamMsgListener redisCloseStreamMsgListener;
@ -64,6 +69,8 @@ public class RedisMsgListenConfig {
container.addMessageListener(redisCloseStreamMsgListener, new PatternTopic(VideoManagerConstants.VM_MSG_STREAM_PUSH_CLOSE));
container.addMessageListener(redisRpcConfig, new PatternTopic(RedisRpcConfig.REDIS_REQUEST_CHANNEL_KEY));
container.addMessageListener(redisPushStreamCloseResponseListener, new PatternTopic(VideoManagerConstants.VM_MSG_STREAM_PUSH_RESPONSE));
container.addMessageListener(groupMsgListener, new PatternTopic(VideoManagerConstants.VM_MSG_GROUP_LIST_RESPONSE));
container.addMessageListener(groupChangeListener, new PatternTopic(VideoManagerConstants.VM_MSG_GROUP_LIST_CHANGE));
return container;
}
}

View File

@ -42,4 +42,5 @@ public class RedisTemplateConfig {
redisTemplate.setConnectionFactory(redisConnectionFactory);
return redisTemplate;
}
}

View File

@ -10,8 +10,8 @@ import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.charset.StandardCharsets;

View File

@ -11,10 +11,10 @@ import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
@ -83,7 +83,7 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter {
// TODO 处理各个状态
switch (jwtUser.getStatus()){
case EXPIRED:
response.setStatus(400);
response.setStatus(401);
chain.doFilter(request, response);
// 异常
return;

View File

@ -24,7 +24,7 @@ import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import jakarta.annotation.Resource;
import java.io.BufferedReader;
import java.io.File;
import java.io.InputStream;
@ -231,7 +231,7 @@ public class JwtUtils implements InitializingBean {
if (expirationTime != null) {
// 判断是否即将过期, 默认剩余时间小于5分钟未即将过期
// 剩余时间
long timeRemaining = LocalDateTime.now().toEpochSecond(ZoneOffset.ofHours(8)) - expirationTime.getValue();
long timeRemaining = expirationTime.getValue() - LocalDateTime.now().toEpochSecond(ZoneOffset.ofHours(8));
if (timeRemaining < 5 * 60) {
jwtUser.setStatus(JwtUser.TokenStatus.EXPIRING_SOON);
} else {

View File

@ -5,9 +5,9 @@ import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import org.springframework.stereotype.Component;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
/**

View File

@ -7,14 +7,15 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
@ -35,7 +36,7 @@ import java.util.List;
@EnableGlobalMethodSecurity(prePostEnabled = true)
@Order(1)
@Slf4j
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
public class WebSecurityConfig {
@Autowired
private UserSetting userSetting;
@ -55,15 +56,13 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private JwtAuthenticationFilter jwtAuthenticationFilter;
@Bean
public AuthenticationManager authenticationManager(AuthenticationConfiguration config) throws Exception {
return config.getAuthenticationManager();
}
/**
* 配置认证方式
*
* @param auth
* @throws Exception
*/
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
@Bean
public AuthenticationProvider authProvider() {
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
// 设置不隐藏 未找到用户异常
provider.setHideUserNotFoundExceptions(true);
@ -71,11 +70,11 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
provider.setUserDetailsService(userDetailsService);
// 设置密码加密算法
provider.setPasswordEncoder(passwordEncoder());
auth.authenticationProvider(provider);
return provider;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
List<String> defaultExcludes = new ArrayList<>();
defaultExcludes.add("/");
defaultExcludes.add("/#/**");
@ -100,34 +99,32 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
defaultExcludes.add("/index/hook/**");
defaultExcludes.add("/api/device/query/snap/**");
defaultExcludes.add("/index/hook/abl/**");
defaultExcludes.add("/api/jt1078/playback/download");
defaultExcludes.add("/api/jt1078/snap");
if (userSetting.getInterfaceAuthentication() && !userSetting.getInterfaceAuthenticationExcludes().isEmpty()) {
defaultExcludes.addAll(userSetting.getInterfaceAuthenticationExcludes());
}
http.headers().contentTypeOptions().disable()
.and().cors().configurationSource(configurationSource())
.and().csrf().disable()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
http
.headers(headers -> headers.contentTypeOptions(contentType -> contentType.disable()))
.cors(cors -> cors.configurationSource(configurationSource()))
.csrf(csrf -> csrf.disable())
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.ALWAYS))
.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class)
// 配置拦截规则
.and()
.authorizeRequests()
.authorizeHttpRequests(auth -> auth
.requestMatchers(CorsUtils::isPreFlightRequest).permitAll()
.antMatchers(defaultExcludes.toArray(new String[0])).permitAll()
.requestMatchers(defaultExcludes.toArray(new String[0])).permitAll()
.anyRequest().authenticated()
)
// 异常处理器
.and()
.exceptionHandling()
.authenticationEntryPoint(anonymousAuthenticationEntryPoint)
.and().logout().logoutUrl("/api/user/logout").permitAll()
.logoutSuccessHandler(logoutHandler)
;
http.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
.exceptionHandling(exception -> exception.authenticationEntryPoint(anonymousAuthenticationEntryPoint))
.logout(logout -> logout.logoutUrl("/api/user/logout")
.permitAll()
.logoutSuccessHandler(logoutHandler));
return http.build();
}
CorsConfigurationSource configurationSource() {
@ -156,17 +153,7 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
/**
* 描述: 密码加密算法 BCrypt 推荐使用
**/
@Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
/**
* 描述: 注入AuthenticationManager管理器
**/
@Override
@Bean
public AuthenticationManager authenticationManager() throws Exception {
return super.authenticationManager();
}
}

View File

@ -2,8 +2,8 @@ package com.genersoft.iot.vmp.conf.webLog;
import lombok.extern.slf4j.Slf4j;
import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import jakarta.websocket.*;
import jakarta.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

View File

@ -48,7 +48,7 @@ import java.util.Random;
@Slf4j
public class DigestServerAuthenticationHelper {
private MessageDigest messageDigest;
private final MessageDigest messageDigest;
public static final String DEFAULT_ALGORITHM = "MD5";
public static final String DEFAULT_SCHEME = "Digest";
@ -59,19 +59,18 @@ public class DigestServerAuthenticationHelper {
/**
* Default constructor.
* @throws NoSuchAlgorithmException
*/
public DigestServerAuthenticationHelper()
throws NoSuchAlgorithmException {
messageDigest = MessageDigest.getInstance(DEFAULT_ALGORITHM);
}
public static String toHexString(byte b[]) {
public static String toHexString(byte[] b) {
int pos = 0;
char[] c = new char[b.length * 2];
for (int i = 0; i < b.length; i++) {
c[pos++] = toHex[(b[i] >> 4) & 0x0F];
c[pos++] = toHex[b[i] & 0x0f];
for (byte value : b) {
c[pos++] = toHex[(value >> 4) & 0x0F];
c[pos++] = toHex[value & 0x0f];
}
return new String(c);
}
@ -87,8 +86,8 @@ public class DigestServerAuthenticationHelper {
long pad = rand.nextLong();
String nonceString = Long.valueOf(time).toString()
+ Long.valueOf(pad).toString();
byte mdbytes[] = messageDigest.digest(nonceString.getBytes());
return toHexString(mdbytes);
byte[] mdBytes = messageDigest.digest(nonceString.getBytes());
return toHexString(mdBytes);
}
public Response generateChallenge(HeaderFactory headerFactory, Response response, String realm) {
@ -132,8 +131,6 @@ public class DigestServerAuthenticationHelper {
return false;
}
String A2 = request.getMethod().toUpperCase() + ":" + uri.toString();
String HA1 = hashedPassword;
@ -177,12 +174,11 @@ public class DigestServerAuthenticationHelper {
if ( authHeader == null || authHeader.getRealm() == null) {
return false;
}
String realm = authHeader.getRealm().trim();
String username = authHeader.getUsername().trim();
if ( username == null || realm == null ) {
if ( authHeader.getUsername() == null || authHeader.getRealm() == null ) {
return false;
}
String realm = authHeader.getRealm().trim();
String username = authHeader.getUsername().trim();
String nonce = authHeader.getNonce();
URI uri = authHeader.getURI();
@ -199,26 +195,24 @@ public class DigestServerAuthenticationHelper {
// nonce计数器是一个16进制的数值表示同一nonce下客户端发送出请求的数量
int nc = authHeader.getNonceCount();
String ncStr = String.format("%08x", nc).toUpperCase();
// String ncStr = new DecimalFormat("00000000").format(nc);
// String ncStr = new DecimalFormat("00000000").format(Integer.parseInt(nc + "", 16));
String A1 = username + ":" + realm + ":" + pass;
String A2 = request.getMethod().toUpperCase() + ":" + uri.toString();
byte mdbytes[] = messageDigest.digest(A1.getBytes());
byte[] mdbytes = messageDigest.digest(A1.getBytes());
String HA1 = toHexString(mdbytes);
log.debug("A1: " + A1);
log.debug("A2: " + A2);
log.debug("A1: {}", A1);
log.debug("A2: {}", A2);
mdbytes = messageDigest.digest(A2.getBytes());
String HA2 = toHexString(mdbytes);
log.debug("HA1: " + HA1);
log.debug("HA2: " + HA2);
log.debug("HA1: {}", HA1);
log.debug("HA2: {}", HA2);
// String cnonce = authHeader.getCNonce();
log.debug("nonce: " + nonce);
log.debug("nc: " + ncStr);
log.debug("cnonce: " + cnonce);
log.debug("qop: " + qop);
log.debug("nonce: {}", nonce);
log.debug("nc: {}", ncStr);
log.debug("cnonce: {}", cnonce);
log.debug("qop: {}", qop);
String KD = HA1 + ":" + nonce;
if (qop != null && qop.equalsIgnoreCase("auth") ) {
@ -231,12 +225,12 @@ public class DigestServerAuthenticationHelper {
KD += ":" + qop;
}
KD += ":" + HA2;
log.debug("KD: " + KD);
log.debug("KD: {}", KD);
mdbytes = messageDigest.digest(KD.getBytes());
String mdString = toHexString(mdbytes);
log.debug("mdString: " + mdString);
log.debug("mdString: {}", mdString);
String response = authHeader.getResponse();
log.debug("response: " + response);
log.debug("response: {}", response);
return mdString.equals(response);
}

View File

@ -150,6 +150,12 @@ public class CommonGBChannel {
@Schema(description = "更新时间")
private String updateTime;
@Schema(description = "流唯一编号,存在表示正在直播")
private String streamId;
@Schema(description = "是否支持对讲 1支持,0不支持")
private Integer enableBroadcast;
public String encode(String serverDeviceId) {
return encode(null, serverDeviceId);
}
@ -337,6 +343,9 @@ public class CommonGBChannel {
if (this.getGbSvcTimeSupportMode() != null) {
content.append(" <SVCTimeSupportMode>" + this.getGbSvcTimeSupportMode() + "</SVCTimeSupportMode>\n");
}
if (this.getEnableBroadcast() != null) {
content.append(" <EnableBroadcast>" + this.getEnableBroadcast() + "</EnableBroadcast>\n");
}
content.append("</Info>\n");
}
}

View File

@ -0,0 +1,17 @@
package com.genersoft.iot.vmp.gb28181.bean;
import lombok.Data;
@Data
public class CommonRecordInfo {
// 开始时间
private String startTime;
// 结束时间
private String endTime;
// 文件大小 单位byte
private String fileSize;
}

View File

@ -212,4 +212,8 @@ public class Device {
@Schema(description = "所属服务Id")
private String serverId;
public boolean isWgs84() {
return geoCoordSys.equalsIgnoreCase("WGS84");
}
}

View File

@ -21,6 +21,12 @@ public class DeviceChannel extends CommonGBChannel {
@Schema(description = "数据库自增ID")
private int id;
@Schema(description = "父设备编码")
private String parentDeviceId;
@Schema(description = "父设备名称")
private String parentName;
@MessageElementForCatalog("DeviceID")
@Schema(description = "编码")
private String deviceId;
@ -116,7 +122,6 @@ public class DeviceChannel extends CommonGBChannel {
@Schema(description = "经度 WGS-84坐标系")
private Double longitude;
@MessageElementForCatalog("Latitude")
@Schema(description = ",纬度 WGS-84坐标系")
private Double latitude;
@ -173,9 +178,6 @@ public class DeviceChannel extends CommonGBChannel {
@Schema(description = "子设备数")
private int subCount;
@Schema(description = "流唯一编号,存在表示正在直播")
private String streamId;
@Schema(description = "是否含有音频")
private boolean hasAudio;
@ -189,7 +191,7 @@ public class DeviceChannel extends CommonGBChannel {
@Schema(description = "通道类型, 默认0, 0 普通通道1 行政区划 2 业务分组/虚拟组织")
private int channelType;
private Integer dataType = ChannelDataType.GB28181.value;
private Integer dataType = ChannelDataType.GB28181;
public void setPtzType(int ptzType) {
this.ptzType = ptzType;
@ -233,7 +235,11 @@ public class DeviceChannel extends CommonGBChannel {
GbCode gbCode = GbCode.decode(deviceChannel.getDeviceId());
if (gbCode != null && "138".equals(gbCode.getTypeCode())) {
deviceChannel.setHasAudio(true);
if (deviceChannel.getEnableBroadcast() == null && "138".equals(gbCode.getTypeCode())) {
deviceChannel.setEnableBroadcast(1);
}
}
return deviceChannel;
}
@ -249,7 +255,7 @@ public class DeviceChannel extends CommonGBChannel {
commonGBChannel.setGbId(id);
commonGBChannel.setGbDeviceId(deviceId);
commonGBChannel.setGbName(name);
commonGBChannel.setDataType(ChannelDataType.GB28181.value);
commonGBChannel.setDataType(ChannelDataType.GB28181);
commonGBChannel.setDataDeviceId(getDataDeviceId());
return commonGBChannel;
}

View File

@ -1,8 +1,8 @@
package com.genersoft.iot.vmp.gb28181.bean;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import javax.validation.constraints.NotNull;
/**
* 解析收到的前端控制指令

View File

@ -14,7 +14,7 @@ public class FrontEndControlCodeForAuxiliary implements IFrontEndControlCode {
}
/**
* 辅助开关控制指令 1为开 2为关 3为设置自动扫描右边界 4为设置自动扫描速度
* 辅助开关控制指令 1为开 2为关
*/
@Getter
@Setter

View File

@ -27,6 +27,13 @@ public class FrontEndControlCodeForPreset implements IFrontEndControlCode {
@Setter
private Integer presetId;
/**
* 预置位名称
*/
@Getter
@Setter
private String presetName;
@Override
public String encode() {

View File

@ -14,7 +14,7 @@ public class FrontEndControlCodeForScan implements IFrontEndControlCode {
}
/**
* 预置位指令 1为开始自动扫描 2为设置自动扫描左边界 3为设置自动扫描右边界 4为设置自动扫描速度
* 预置位指令 1为开始自动扫描 2为设置自动扫描左边界 3为设置自动扫描右边界 4为设置自动扫描速度 5为停止自动扫描
*/
@Getter
@Setter

View File

@ -14,7 +14,7 @@ public class FrontEndControlCodeForTour implements IFrontEndControlCode {
}
/**
* 巡航指令 1为加入巡航点 2为删除一个巡航点 3为设置巡航速度 4为设置巡航停留时间 5为开始巡航
* 巡航指令 1为加入巡航点 2为删除一个巡航点 3为设置巡航速度 4为设置巡航停留时间 5为开始巡航 6为停止巡航
*/
@Getter
@Setter

View File

@ -0,0 +1,27 @@
package com.genersoft.iot.vmp.gb28181.bean;
import lombok.Getter;
import lombok.Setter;
public class FrontEndControlCodeForWiper implements IFrontEndControlCode {
private final FrontEndControlType type = FrontEndControlType.AUXILIARY;
@Override
public FrontEndControlType getType() {
return type;
}
/**
* 辅助开关控制指令 1为开 2为关
*/
@Getter
@Setter
private Integer code;
@Override
public String encode() {
return "";
}
}

View File

@ -58,12 +58,19 @@ public class Group implements Comparable<Group>{
*/
@Schema(description = "更新时间")
private String updateTime;
/**
* 行政区划
*/
@Schema(description = "行政区划")
private String civilCode;
/**
* 别名
*/
@Schema(description = "别名, 此别名为唯一值可以对接第三方是存储对方的ID")
private String alias;
public static Group getInstance(DeviceChannel channel) {
GbCode gbCode = GbCode.decode(channel.getDeviceId());
if (gbCode == null || (!gbCode.getTypeCode().equals("215") && !gbCode.getTypeCode().equals("216"))) {

View File

@ -0,0 +1,43 @@
package com.genersoft.iot.vmp.gb28181.bean;
import lombok.Getter;
import lombok.Setter;
import org.dom4j.Element;
import org.jetbrains.annotations.NotNull;
import java.util.List;
import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;
public class MessageResponseTask<T> implements Delayed {
@Getter
@Setter
private Element element;
@Getter
@Setter
private List<T> data;
@Getter
@Setter
private String key;
/**
* 超时时间(单位 毫秒)
*/
@Getter
@Setter
private long delayTime;
@Override
public long getDelay(@NotNull TimeUnit unit) {
return unit.convert(delayTime - System.currentTimeMillis(), TimeUnit.MILLISECONDS);
}
@Override
public int compareTo(@NotNull Delayed o) {
return (int) (this.getDelay(TimeUnit.MILLISECONDS) - o.getDelay(TimeUnit.MILLISECONDS));
}
}

View File

@ -2,6 +2,8 @@ package com.genersoft.iot.vmp.gb28181.bean;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Getter;
import lombok.Setter;
import java.time.Instant;
import java.util.List;
@ -11,6 +13,8 @@ import java.util.List;
* @author: swwheihei
* @date: 2020年5月8日 下午2:05:56
*/
@Setter
@Getter
@Schema(description = "设备录像查询结果信息")
public class RecordInfo {
@ -36,67 +40,4 @@ public class RecordInfo {
@Schema(description = "")
private List<RecordItem> recordList;
public String getDeviceId() {
return deviceId;
}
public void setDeviceId(String deviceId) {
this.deviceId = deviceId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getSumNum() {
return sumNum;
}
public void setSumNum(int sumNum) {
this.sumNum = sumNum;
}
public List<RecordItem> getRecordList() {
return recordList;
}
public void setRecordList(List<RecordItem> recordList) {
this.recordList = recordList;
}
public String getChannelId() {
return channelId;
}
public void setChannelId(String channelId) {
this.channelId = channelId;
}
public String getSn() {
return sn;
}
public void setSn(String sn) {
this.sn = sn;
}
public Instant getLastTime() {
return lastTime;
}
public void setLastTime(Instant lastTime) {
this.lastTime = lastTime;
}
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
}

View File

@ -3,6 +3,8 @@ package com.genersoft.iot.vmp.gb28181.bean;
import com.genersoft.iot.vmp.utils.DateUtil;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Getter;
import lombok.Setter;
import org.jetbrains.annotations.NotNull;
import java.time.Instant;
@ -13,6 +15,8 @@ import java.time.temporal.TemporalAccessor;
* @author: swwheihei
* @date: 2020年5月8日 下午2:06:54
*/
@Setter
@Getter
@Schema(description = "设备录像详情")
public class RecordItem implements Comparable<RecordItem>{
@ -40,92 +44,12 @@ public class RecordItem implements Comparable<RecordItem>{
@Schema(description = "保密属性(必选)缺省为0;0:不涉密,1:涉密")
private int secrecy;
@Schema(description = "录像产生类型(可选)time或alarm 或 manua")
@Schema(description = "录像产生类型(可选)time或alarm 或 manual")
private String type;
@Schema(description = "录像触发者ID(可选)")
private String recorderId;
public String getDeviceId() {
return deviceId;
}
public void setDeviceId(String deviceId) {
this.deviceId = deviceId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getFilePath() {
return filePath;
}
public void setFilePath(String filePath) {
this.filePath = filePath;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getStartTime() {
return startTime;
}
public void setStartTime(String startTime) {
this.startTime = startTime;
}
public String getEndTime() {
return endTime;
}
public void setEndTime(String endTime) {
this.endTime = endTime;
}
public int getSecrecy() {
return secrecy;
}
public void setSecrecy(int secrecy) {
this.secrecy = secrecy;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getRecorderId() {
return recorderId;
}
public void setRecorderId(String recorderId) {
this.recorderId = recorderId;
}
public String getFileSize() {
return fileSize;
}
public void setFileSize(String fileSize) {
this.fileSize = fileSize;
}
@Override
public int compareTo(@NotNull RecordItem recordItem) {
TemporalAccessor startTimeNow = DateUtil.formatter.parse(startTime);

View File

@ -0,0 +1,67 @@
package com.genersoft.iot.vmp.gb28181.bean;
import lombok.Data;
@Data
public class RedisGroupMessage {
/**
* 分组国标ID
*/
private String groupGbId;
/**
* 分组别名
*/
private String groupAlias;
/**
* 分组名称
*/
private String groupName;
/**
* 分组所属的行政区划
*/
private String groupCivilCode;
/**
* 分组所属父分组国标ID
*/
private String parentGroupGbId;
/**
* 分组所属父分组别名
*/
private String parentGAlias;
/**
* 分组所属业务分组国标ID
*/
private String topGroupGbId;
/**
* 分组所属业务分组别名
*/
private String topGroupGAlias;
/**
* 分组变化消息中的消息类型取值为 add update delete
*/
private String messageType;
@Override
public String toString() {
return "RedisGroupMessage{" +
"groupGbId='" + groupGbId + '\'' +
", groupAlias='" + groupAlias + '\'' +
", groupName='" + groupName + '\'' +
", groupCivilCode='" + groupCivilCode + '\'' +
", parentGroupGbId='" + parentGroupGbId + '\'' +
", parentGAlias='" + parentGAlias + '\'' +
", topGroupGbId='" + topGroupGbId + '\'' +
", topGroupGAlias='" + topGroupGAlias + '\'' +
'}';
}
}

View File

@ -0,0 +1,19 @@
package com.genersoft.iot.vmp.gb28181.bean;
import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
import lombok.Data;
@Data
public class SipSendFailEvent extends SipSubscribe.EventResult<String> {
private String callId;
private String msg;
public static SipSendFailEvent getInstance(String callId, String msg){
SipSendFailEvent sipSendFailEvent = new SipSendFailEvent();
sipSendFailEvent.setMsg(msg);
sipSendFailEvent.setCallId(callId);
return sipSendFailEvent;
}
}

View File

@ -2,21 +2,20 @@ package com.genersoft.iot.vmp.gb28181.controller;
import com.genersoft.iot.vmp.common.StreamInfo;
import com.genersoft.iot.vmp.conf.UserSetting;
import com.genersoft.iot.vmp.conf.exception.ControllerException;
import com.genersoft.iot.vmp.conf.security.JwtUtils;
import com.genersoft.iot.vmp.gb28181.bean.CommonGBChannel;
import com.genersoft.iot.vmp.gb28181.bean.DeviceType;
import com.genersoft.iot.vmp.gb28181.bean.IndustryCodeType;
import com.genersoft.iot.vmp.gb28181.bean.NetworkIdentificationType;
import com.genersoft.iot.vmp.gb28181.bean.*;
import com.genersoft.iot.vmp.gb28181.controller.bean.ChannelToGroupByGbDeviceParam;
import com.genersoft.iot.vmp.gb28181.controller.bean.ChannelToGroupParam;
import com.genersoft.iot.vmp.gb28181.controller.bean.ChannelToRegionByGbDeviceParam;
import com.genersoft.iot.vmp.gb28181.controller.bean.ChannelToRegionParam;
import com.genersoft.iot.vmp.gb28181.service.IGbChannelPlayService;
import com.genersoft.iot.vmp.gb28181.service.IGbChannelService;
import com.genersoft.iot.vmp.media.service.IMediaServerService;
import com.genersoft.iot.vmp.service.bean.ErrorCallback;
import com.genersoft.iot.vmp.service.bean.InviteErrorCode;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import com.genersoft.iot.vmp.utils.DateUtil;
import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
import com.genersoft.iot.vmp.vmanager.bean.StreamContent;
import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
import com.github.pagehelper.PageInfo;
@ -24,6 +23,7 @@ import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.Assert;
@ -31,17 +31,17 @@ import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.request.async.DeferredResult;
import javax.servlet.http.HttpServletRequest;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.List;
import java.util.concurrent.TimeUnit;
@Tag(name = "全局通道管理")
@RestController
@Slf4j
@RequestMapping(value = "/api/common/channel")
public class CommonChannelController {
public class ChannelController {
@Autowired
private IRedisCatchStorage redisCatchStorage;
@ -49,9 +49,6 @@ public class CommonChannelController {
@Autowired
private IGbChannelService channelService;
@Autowired
private IMediaServerService mediaServerService;
@Autowired
private IGbChannelPlayService channelPlayService;
@ -276,7 +273,94 @@ public class CommonChannelController {
@Operation(summary = "播放通道", security = @SecurityRequirement(name = JwtUtils.HEADER))
@GetMapping("/play")
public DeferredResult<WVPResult<StreamContent>> deleteChannelToGroupByGbDevice(HttpServletRequest request, Integer channelId){
public DeferredResult<WVPResult<StreamContent>> play(HttpServletRequest request, Integer channelId){
Assert.notNull(channelId,"参数异常");
CommonGBChannel channel = channelService.getOne(channelId);
Assert.notNull(channel, "通道不存在");
DeferredResult<WVPResult<StreamContent>> result = new DeferredResult<>(userSetting.getPlayTimeout().longValue());
ErrorCallback<StreamInfo> callback = (code, msg, streamInfo) -> {
if (code == InviteErrorCode.SUCCESS.getCode()) {
WVPResult<StreamContent> wvpResult = WVPResult.success();
if (streamInfo != null) {
if (userSetting.getUseSourceIpAsStreamIp()) {
streamInfo=streamInfo.clone();//深拷贝
String host;
try {
URL url=new URL(request.getRequestURL().toString());
host=url.getHost();
} catch (MalformedURLException e) {
host=request.getLocalAddr();
}
streamInfo.changeStreamIp(host);
}
if (!ObjectUtils.isEmpty(streamInfo.getMediaServer().getTranscodeSuffix())
&& !"null".equalsIgnoreCase(streamInfo.getMediaServer().getTranscodeSuffix())) {
streamInfo.setStream(streamInfo.getStream() + "_" + streamInfo.getMediaServer().getTranscodeSuffix());
}
wvpResult.setData(new StreamContent(streamInfo));
}else {
wvpResult.setCode(code);
wvpResult.setMsg(msg);
}
result.setResult(wvpResult);
}else {
result.setResult(WVPResult.fail(code, msg));
}
};
channelPlayService.play(channel, null, userSetting.getRecordSip(), callback);
return result;
}
@Operation(summary = "停止播放通道", security = @SecurityRequirement(name = JwtUtils.HEADER))
@GetMapping("/play/stop")
public void stopPlay(Integer channelId){
Assert.notNull(channelId,"参数异常");
CommonGBChannel channel = channelService.getOne(channelId);
Assert.notNull(channel, "通道不存在");
channelPlayService.stopPlay(channel, channel.getStreamId());
}
@Operation(summary = "录像查询", security = @SecurityRequirement(name = JwtUtils.HEADER))
@Parameter(name = "channelId", description = "通道ID", required = true)
@Parameter(name = "startTime", description = "开始时间", required = true)
@Parameter(name = "endTime", description = "结束时间", required = true)
@GetMapping("/playback/query")
public DeferredResult<WVPResult<List<CommonRecordInfo>>> queryRecord(Integer channelId, String startTime, String endTime){
DeferredResult<WVPResult<List<CommonRecordInfo>>> result = new DeferredResult<>(Long.valueOf(userSetting.getRecordInfoTimeout()), TimeUnit.MILLISECONDS);
if (!DateUtil.verification(startTime, DateUtil.formatter)){
throw new ControllerException(ErrorCode.ERROR100.getCode(), "startTime格式为" + DateUtil.PATTERN);
}
if (!DateUtil.verification(endTime, DateUtil.formatter)){
throw new ControllerException(ErrorCode.ERROR100.getCode(), "endTime格式为" + DateUtil.PATTERN);
}
CommonGBChannel channel = channelService.getOne(channelId);
Assert.notNull(channel, "通道不存在");
channelPlayService.queryRecord(channel, startTime, endTime, (code, msg, data) -> {
WVPResult<List<CommonRecordInfo>> wvpResult = new WVPResult<>();
wvpResult.setCode(code);
wvpResult.setMsg(msg);
wvpResult.setData(data);
result.setResult(wvpResult);
});
result.onTimeout(()->{
WVPResult<List<CommonRecordInfo>> wvpResult = new WVPResult<>();
wvpResult.setCode(ErrorCode.ERROR100.getCode());
wvpResult.setMsg("timeout");
result.setResult(wvpResult);
});
return result;
}
@Operation(summary = "录像回放", security = @SecurityRequirement(name = JwtUtils.HEADER))
@Parameter(name = "channelId", description = "通道ID", required = true)
@Parameter(name = "startTime", description = "开始时间", required = true)
@Parameter(name = "endTime", description = "结束时间", required = true)
@GetMapping("/playback")
public DeferredResult<WVPResult<StreamContent>> playback(HttpServletRequest request, Integer channelId, String startTime, String endTime){
Assert.notNull(channelId,"参数异常");
CommonGBChannel channel = channelService.getOne(channelId);
Assert.notNull(channel, "通道不存在");
@ -313,7 +397,85 @@ public class CommonChannelController {
result.setResult(WVPResult.fail(code, msg));
}
};
channelPlayService.play(channel, null, userSetting.getRecordSip(), callback);
channelPlayService.playback(channel, DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(startTime),
DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(endTime), callback);
return result;
}
@Operation(summary = "停止录像回放", security = @SecurityRequirement(name = JwtUtils.HEADER))
@Parameter(name = "channelId", description = "通道ID", required = true)
@Parameter(name = "stream", description = "流ID", required = true)
@GetMapping("/playback/stop")
public void stopPlayback(Integer channelId, String stream){
Assert.notNull(channelId,"参数异常");
CommonGBChannel channel = channelService.getOne(channelId);
Assert.notNull(channel, "通道不存在");
channelPlayService.stopPlayback(channel, stream);
}
@Operation(summary = "暂停录像回放", security = @SecurityRequirement(name = JwtUtils.HEADER))
@Parameter(name = "channelId", description = "通道ID", required = true)
@Parameter(name = "stream", description = "流ID", required = true)
@GetMapping("/playback/pause")
public void pausePlayback(Integer channelId, String stream){
Assert.notNull(channelId,"参数异常");
CommonGBChannel channel = channelService.getOne(channelId);
Assert.notNull(channel, "通道不存在");
channelPlayService.playbackPause(channel, stream);
}
@Operation(summary = "恢复录像回放", security = @SecurityRequirement(name = JwtUtils.HEADER))
@Parameter(name = "channelId", description = "通道ID", required = true)
@Parameter(name = "stream", description = "流ID", required = true)
@GetMapping("/playback/resume")
public void resumePlayback(Integer channelId, String stream){
Assert.notNull(channelId,"参数异常");
CommonGBChannel channel = channelService.getOne(channelId);
Assert.notNull(channel, "通道不存在");
channelPlayService.playbackResume(channel, stream);
}
@Operation(summary = "拖动录像回放", security = @SecurityRequirement(name = JwtUtils.HEADER))
@Parameter(name = "channelId", description = "通道ID", required = true)
@Parameter(name = "stream", description = "流ID", required = true)
@Parameter(name = "seekTime", description = "将要播放的时间", required = true)
@GetMapping("/playback/seek")
public void seekPlayback(Integer channelId, String stream, Long seekTime){
Assert.notNull(channelId,"参数异常");
Assert.notNull(seekTime,"参数异常");
CommonGBChannel channel = channelService.getOne(channelId);
Assert.notNull(channel, "通道不存在");
channelPlayService.playbackSeek(channel, stream, seekTime);
}
@Operation(summary = "拖动录像回放", security = @SecurityRequirement(name = JwtUtils.HEADER))
@Parameter(name = "channelId", description = "通道ID", required = true)
@Parameter(name = "stream", description = "流ID", required = true)
@Parameter(name = "speed", description = "倍速", required = true)
@GetMapping("/playback/speed")
public void seekPlayback(Integer channelId, String stream, Double speed){
Assert.notNull(channelId,"参数异常");
Assert.notNull(speed,"参数异常");
CommonGBChannel channel = channelService.getOne(channelId);
Assert.notNull(channel, "通道不存在");
channelPlayService.playbackSpeed(channel, stream, speed);
}
@Operation(summary = "为地图获取通道列表", security = @SecurityRequirement(name = JwtUtils.HEADER))
@Parameter(name = "query", description = "查询内容")
@Parameter(name = "online", description = "是否在线")
@Parameter(name = "hasRecordPlan", description = "是否已设置录制计划")
@Parameter(name = "channelType", description = "通道类型, 0国标设备1推流设备2拉流代理")
@Parameter(name = "geoCoordSys", description = "地理坐标系, WGS84/GCJ02")
@GetMapping("/map/list")
public List<CommonGBChannel> queryListForMap(
@RequestParam(required = false) String query,
@RequestParam(required = false) Boolean online,
@RequestParam(required = false) Boolean hasRecordPlan,
@RequestParam(required = false) Integer channelType){
if (ObjectUtils.isEmpty(query)){
query = null;
}
return channelService.queryListForMap(query, online, hasRecordPlan, channelType);
}
}

View File

@ -0,0 +1,601 @@
package com.genersoft.iot.vmp.gb28181.controller;
import com.genersoft.iot.vmp.conf.exception.ControllerException;
import com.genersoft.iot.vmp.conf.security.JwtUtils;
import com.genersoft.iot.vmp.gb28181.bean.*;
import com.genersoft.iot.vmp.gb28181.service.IGbChannelControlService;
import com.genersoft.iot.vmp.gb28181.service.IGbChannelService;
import com.genersoft.iot.vmp.service.bean.ErrorCallback;
import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.async.DeferredResult;
import java.util.List;
@Tag(name = "全局通道前端控制")
@RestController
@Slf4j
@RequestMapping(value = "/api/common/channel/front-end")
public class ChannelFrontEndController {
@Autowired
private IGbChannelService channelService;
@Autowired
private IGbChannelControlService channelControlService;
@Operation(summary = "云台控制", security = @SecurityRequirement(name = JwtUtils.HEADER))
@Parameter(name = "channelId", description = "通道ID", required = true)
@Parameter(name = "command", description = "控制指令,允许值: left, right, up, down, upleft, upright, downleft, downright, zoomin, zoomout, stop", required = true)
@Parameter(name = "panSpeed", description = "水平速度(0-100)", required = true)
@Parameter(name = "tiltSpeed", description = "垂直速度(0-100)", required = true)
@Parameter(name = "zoomSpeed", description = "缩放速度(0-100)", required = true)
@GetMapping("/ptz")
public DeferredResult<WVPResult<String>> ptz(Integer channelId, String command, Integer panSpeed, Integer tiltSpeed, Integer zoomSpeed){
if (log.isDebugEnabled()) {
log.debug("[通用通道]云台控制 API调用channelId{} command{} panSpeed{} tiltSpeed{} zoomSpeed{}",channelId, command, panSpeed, tiltSpeed, zoomSpeed);
}
CommonGBChannel channel = channelService.getOne(channelId);
Assert.notNull(channel, "通道不存在");
if (panSpeed == null) {
panSpeed = 50;
}else if (panSpeed < 0 || panSpeed > 100) {
throw new ControllerException(ErrorCode.ERROR100.getCode(), "panSpeed 为 0-100的数字");
}
if (tiltSpeed == null) {
tiltSpeed = 50;
}else if (tiltSpeed < 0 || tiltSpeed > 100) {
throw new ControllerException(ErrorCode.ERROR100.getCode(), "tiltSpeed 为 0-100的数字");
}
if (zoomSpeed == null) {
zoomSpeed = 50;
}else if (zoomSpeed < 0 || zoomSpeed > 100) {
throw new ControllerException(ErrorCode.ERROR100.getCode(), "zoomSpeed 为 0-100的数字");
}
FrontEndControlCodeForPTZ controlCode = new FrontEndControlCodeForPTZ();
controlCode.setPanSpeed(panSpeed);
controlCode.setTiltSpeed(tiltSpeed);
controlCode.setZoomSpeed(zoomSpeed);
switch (command){
case "left":
controlCode.setPan(0);
break;
case "right":
controlCode.setPan(1);
break;
case "up":
controlCode.setTilt(0);
break;
case "down":
controlCode.setTilt(1);
break;
case "upleft":
controlCode.setPan(0);
controlCode.setTilt(0);
break;
case "upright":
controlCode.setTilt(0);
controlCode.setPan(1);
break;
case "downleft":
controlCode.setPan(0);
controlCode.setTilt(1);
break;
case "downright":
controlCode.setTilt(1);
controlCode.setPan(1);
break;
case "zoomin":
controlCode.setZoom(1);
break;
case "zoomout":
controlCode.setZoom(0);
break;
default:
break;
}
DeferredResult<WVPResult<String>> result = new DeferredResult<>();
result.onTimeout(()->{
WVPResult<String> wvpResult = WVPResult.fail(ErrorCode.ERROR100.getCode(), "请求超时");
result.setResult(wvpResult);
});
channelControlService.ptz(channel, controlCode, (code, msg, data) -> {
WVPResult<String> wvpResult = new WVPResult<>();
wvpResult.setCode(code);
wvpResult.setMsg(msg);
wvpResult.setData(data);
result.setResult(wvpResult);
});
return result;
}
@Operation(summary = "光圈控制", security = @SecurityRequirement(name = JwtUtils.HEADER))
@Parameter(name = "channelId", description = "通道国标编号", required = true)
@Parameter(name = "command", description = "控制指令,允许值: in, out, stop", required = true)
@Parameter(name = "speed", description = "光圈速度(0-100)", required = true)
@GetMapping("/fi/iris")
public DeferredResult<WVPResult<String>> iris(Integer channelId, String command, Integer speed){
if (log.isDebugEnabled()) {
log.debug("[通用通道]光圈控制 API调用channelId{} command{} speed{} ",channelId, command, speed);
}
CommonGBChannel channel = channelService.getOne(channelId);
Assert.notNull(channel, "通道不存在");
if (speed == null) {
speed = 50;
}else if (speed < 0 || speed > 100) {
throw new ControllerException(ErrorCode.ERROR100.getCode(), "speed 为 0-100的数字");
}
FrontEndControlCodeForFI controlCode = new FrontEndControlCodeForFI();
controlCode.setIrisSpeed(speed);
switch (command){
case "in":
controlCode.setIris(1);
break;
case "out":
controlCode.setIris(0);
break;
default:
break;
}
DeferredResult<WVPResult<String>> result = new DeferredResult<>();
result.onTimeout(()->{
WVPResult<String> wvpResult = WVPResult.fail(ErrorCode.ERROR100.getCode(), "请求超时");
result.setResult(wvpResult);
});
ErrorCallback<String> callback = (code, msg, data) -> {
WVPResult<String> wvpResult = new WVPResult<>();
wvpResult.setCode(code);
wvpResult.setMsg(msg);
wvpResult.setData(data);
result.setResult(wvpResult);
};
channelControlService.fi(channel, controlCode, callback);
return result;
}
@Operation(summary = "聚焦控制", security = @SecurityRequirement(name = JwtUtils.HEADER))
@Parameter(name = "channelId", description = "通道国标编号", required = true)
@Parameter(name = "command", description = "控制指令,允许值: near, far, stop", required = true)
@Parameter(name = "speed", description = "聚焦速度(0-100)", required = true)
@GetMapping("/fi/focus")
public DeferredResult<WVPResult<String>> focus(Integer channelId, String command, Integer speed){
if (log.isDebugEnabled()) {
log.debug("[通用通道]聚焦控制 API调用channelId{} command{} speed{} ", channelId, command, speed);
}
if (speed == null) {
speed = 50;
}else if (speed < 0 || speed > 100) {
throw new ControllerException(ErrorCode.ERROR100.getCode(), "speed 为 0-100的数字");
}
CommonGBChannel channel = channelService.getOne(channelId);
Assert.notNull(channel, "通道不存在");
FrontEndControlCodeForFI controlCode = new FrontEndControlCodeForFI();
controlCode.setFocusSpeed(speed);
switch (command){
case "near":
controlCode.setFocus(0);
break;
case "far":
controlCode.setFocus(1);
break;
default:
break;
}
DeferredResult<WVPResult<String>> result = new DeferredResult<>();
result.onTimeout(()->{
WVPResult<String> wvpResult = WVPResult.fail(ErrorCode.ERROR100.getCode(), "请求超时");
result.setResult(wvpResult);
});
ErrorCallback<String> callback = (code, msg, data) -> {
WVPResult<String> wvpResult = new WVPResult<>();
wvpResult.setCode(code);
wvpResult.setMsg(msg);
wvpResult.setData(data);
result.setResult(wvpResult);
};
channelControlService.fi(channel, controlCode, callback);
return result;
}
@Operation(summary = "查询预置位", security = @SecurityRequirement(name = JwtUtils.HEADER))
@Parameter(name = "channelId", description = "通道国标编号", required = true)
@GetMapping("/preset/query")
public DeferredResult<WVPResult<List<Preset>>> queryPreset(Integer channelId) {
if (log.isDebugEnabled()) {
log.debug("[通用通道] 预置位查询API调用, {}", channelId);
}
CommonGBChannel channel = channelService.getOne(channelId);
Assert.notNull(channel, "通道不存在");
DeferredResult<WVPResult<List<Preset>>> result = new DeferredResult<>();
result.onTimeout(()->{
WVPResult<List<Preset>> wvpResult = WVPResult.fail(ErrorCode.ERROR100.getCode(), "请求超时");
result.setResult(wvpResult);
});
ErrorCallback<List<Preset>> callback = (code, msg, data) -> {
WVPResult<List<Preset>> wvpResult = new WVPResult<>();
wvpResult.setCode(code);
wvpResult.setMsg(msg);
wvpResult.setData(data);
result.setResult(wvpResult);
};
channelControlService.queryPreset(channel, callback);
return result;
}
private DeferredResult<WVPResult<String>> controlPreset(Integer channelId, FrontEndControlCodeForPreset controlCode) {
CommonGBChannel channel = channelService.getOne(channelId);
Assert.notNull(channel, "通道不存在");
DeferredResult<WVPResult<String>> result = new DeferredResult<>();
result.onTimeout(()->{
WVPResult<String> wvpResult = WVPResult.fail(ErrorCode.ERROR100.getCode(), "请求超时");
result.setResult(wvpResult);
});
ErrorCallback<String> callback = (code, msg, data) -> {
WVPResult<String> wvpResult = new WVPResult<>();
wvpResult.setCode(code);
wvpResult.setMsg(msg);
wvpResult.setData(data);
result.setResult(wvpResult);
};
channelControlService.preset(channel, controlCode, callback);
return result;
}
@Operation(summary = "预置位指令-设置预置位", security = @SecurityRequirement(name = JwtUtils.HEADER))
@Parameter(name = "channelId", description = "通道国标编号", required = true)
@Parameter(name = "presetId", description = "预置位编号", required = true)
@Parameter(name = "presetName", description = "预置位名称", required = true)
@GetMapping("/preset/add")
public DeferredResult<WVPResult<String>> addPreset(Integer channelId, Integer presetId, String presetName) {
FrontEndControlCodeForPreset controlCode = new FrontEndControlCodeForPreset();
controlCode.setCode(1);
controlCode.setPresetId(presetId);
controlCode.setPresetName(presetName);
return controlPreset(channelId, controlCode);
}
@Operation(summary = "预置位指令-调用预置位", security = @SecurityRequirement(name = JwtUtils.HEADER))
@Parameter(name = "channelId", description = "通道国标编号", required = true)
@Parameter(name = "presetId", description = "预置位编号(1-100)", required = true)
@GetMapping("/preset/call")
public DeferredResult<WVPResult<String>> callPreset(Integer channelId, Integer presetId) {
FrontEndControlCodeForPreset controlCode = new FrontEndControlCodeForPreset();
controlCode.setCode(2);
controlCode.setPresetId(presetId);
return controlPreset(channelId, controlCode);
}
@Operation(summary = "预置位指令-删除预置位", security = @SecurityRequirement(name = JwtUtils.HEADER))
@Parameter(name = "channelId", description = "通道国标编号", required = true)
@Parameter(name = "presetId", description = "预置位编号(1-100)", required = true)
@GetMapping("/preset/delete")
public DeferredResult<WVPResult<String>> deletePreset(Integer channelId, Integer presetId) {
FrontEndControlCodeForPreset controlCode = new FrontEndControlCodeForPreset();
controlCode.setCode(3);
controlCode.setPresetId(presetId);
return controlPreset(channelId, controlCode);
}
private DeferredResult<WVPResult<String>> tourControl(Integer channelId, FrontEndControlCodeForTour controlCode) {
CommonGBChannel channel = channelService.getOne(channelId);
Assert.notNull(channel, "通道不存在");
DeferredResult<WVPResult<String>> result = new DeferredResult<>();
result.onTimeout(()->{
WVPResult<String> wvpResult = WVPResult.fail(ErrorCode.ERROR100.getCode(), "请求超时");
result.setResult(wvpResult);
});
ErrorCallback<String> callback = (code, msg, data) -> {
WVPResult<String> wvpResult = new WVPResult<>();
wvpResult.setCode(code);
wvpResult.setMsg(msg);
wvpResult.setData(data);
result.setResult(wvpResult);
};
channelControlService.tour(channel, controlCode, callback);
return result;
}
@Operation(summary = "巡航指令-加入巡航点", security = @SecurityRequirement(name = JwtUtils.HEADER))
@Parameter(name = "channelId", description = "通道国标编号", required = true)
@Parameter(name = "tourId", description = "巡航组号", required = true)
@Parameter(name = "presetId", description = "预置位编号", required = true)
@GetMapping("/tour/point/add")
public DeferredResult<WVPResult<String>> addTourPoint(Integer channelId, Integer tourId, Integer presetId) {
FrontEndControlCodeForTour controlCode = new FrontEndControlCodeForTour();
controlCode.setCode(1);
controlCode.setPresetId(presetId);
controlCode.setTourId(tourId);
return tourControl(channelId, controlCode);
}
@Operation(summary = "巡航指令-删除一个巡航点", security = @SecurityRequirement(name = JwtUtils.HEADER))
@Parameter(name = "channelId", description = "通道国标编号", required = true)
@Parameter(name = "tourId", description = "巡航组号(1-100)", required = true)
@Parameter(name = "presetId", description = "预置位编号(0-100, 为0时删除整个巡航)", required = true)
@GetMapping("/tour/point/delete")
public DeferredResult<WVPResult<String>> deleteCruisePoint(Integer channelId, Integer tourId, Integer presetId) {
FrontEndControlCodeForTour controlCode = new FrontEndControlCodeForTour();
controlCode.setCode(2);
controlCode.setPresetId(presetId);
controlCode.setTourId(tourId);
return tourControl(channelId, controlCode);
}
@Operation(summary = "巡航指令-设置巡航速度", security = @SecurityRequirement(name = JwtUtils.HEADER))
@Parameter(name = "channelId", description = "通道国标编号", required = true)
@Parameter(name = "tourId", description = "巡航组号(0-100)", required = true)
@Parameter(name = "speed", description = "巡航速度(1-4095)", required = true)
@Parameter(name = "presetId", description = "预置位编号", required = true)
@GetMapping("/tour/speed")
public DeferredResult<WVPResult<String>> setCruiseSpeed(Integer channelId, Integer tourId, Integer speed, Integer presetId) {
FrontEndControlCodeForTour controlCode = new FrontEndControlCodeForTour();
controlCode.setCode(3);
controlCode.setTourSpeed(speed);
controlCode.setTourId(tourId);
controlCode.setPresetId(presetId);
return tourControl(channelId, controlCode);
}
@Operation(summary = "巡航指令-设置巡航停留时间", security = @SecurityRequirement(name = JwtUtils.HEADER))
@Parameter(name = "channelId", description = "通道国标编号", required = true)
@Parameter(name = "tourId", description = "巡航组号", required = true)
@Parameter(name = "time", description = "巡航停留时间(1-4095)", required = true)
@Parameter(name = "presetId", description = "预置位编号", required = true)
@GetMapping("/tour/time")
public DeferredResult<WVPResult<String>> setCruiseTime(Integer channelId, Integer tourId, Integer time, Integer presetId) {
FrontEndControlCodeForTour controlCode = new FrontEndControlCodeForTour();
controlCode.setCode(4);
controlCode.setTourTime(time);
controlCode.setTourId(tourId);
controlCode.setPresetId(presetId);
return tourControl(channelId, controlCode);
}
@Operation(summary = "巡航指令-开始巡航", security = @SecurityRequirement(name = JwtUtils.HEADER))
@Parameter(name = "channelId", description = "通道国标编号", required = true)
@Parameter(name = "tourId", description = "巡航组号)", required = true)
@GetMapping("/tour/start")
public DeferredResult<WVPResult<String>> startCruise(Integer channelId, Integer tourId) {
FrontEndControlCodeForTour controlCode = new FrontEndControlCodeForTour();
controlCode.setCode(5);
controlCode.setTourId(tourId);
return tourControl(channelId, controlCode);
}
@Operation(summary = "巡航指令-停止巡航", security = @SecurityRequirement(name = JwtUtils.HEADER))
@Parameter(name = "channelId", description = "通道国标编号", required = true)
@Parameter(name = "tourId", description = "巡航组号", required = true)
@GetMapping("/tour/stop")
public DeferredResult<WVPResult<String>> stopCruise(Integer channelId, Integer tourId) {
FrontEndControlCodeForTour controlCode = new FrontEndControlCodeForTour();
controlCode.setCode(6);
controlCode.setTourId(tourId);
return tourControl(channelId, controlCode);
}
private DeferredResult<WVPResult<String>> scanControl(Integer channelId, FrontEndControlCodeForScan controlCode) {
CommonGBChannel channel = channelService.getOne(channelId);
Assert.notNull(channel, "通道不存在");
DeferredResult<WVPResult<String>> result = new DeferredResult<>();
result.onTimeout(()->{
WVPResult<String> wvpResult = WVPResult.fail(ErrorCode.ERROR100.getCode(), "请求超时");
result.setResult(wvpResult);
});
ErrorCallback<String> callback = (code, msg, data) -> {
WVPResult<String> wvpResult = new WVPResult<>();
wvpResult.setCode(code);
wvpResult.setMsg(msg);
wvpResult.setData(data);
result.setResult(wvpResult);
};
channelControlService.scan(channel, controlCode, callback);
return result;
}
@Operation(summary = "扫描指令-开始自动扫描", security = @SecurityRequirement(name = JwtUtils.HEADER))
@Parameter(name = "channelId", description = "通道国标编号", required = true)
@Parameter(name = "scanId", description = "扫描组号(0-100)", required = true)
@GetMapping("/scan/start")
public DeferredResult<WVPResult<String>> startScan(Integer channelId, Integer scanId) {
FrontEndControlCodeForScan controlCode = new FrontEndControlCodeForScan();
controlCode.setCode(1);
controlCode.setScanId(scanId);
return scanControl(channelId, controlCode);
}
@Operation(summary = "扫描指令-停止自动扫描", security = @SecurityRequirement(name = JwtUtils.HEADER))
@Parameter(name = "channelId", description = "通道国标编号", required = true)
@Parameter(name = "scanId", description = "扫描组号(0-100)", required = true)
@GetMapping("/scan/stop")
public DeferredResult<WVPResult<String>> stopScan(Integer channelId, Integer scanId) {
FrontEndControlCodeForScan controlCode = new FrontEndControlCodeForScan();
controlCode.setCode(5);
controlCode.setScanId(scanId);
return scanControl(channelId, controlCode);
}
@Operation(summary = "扫描指令-设置自动扫描左边界", security = @SecurityRequirement(name = JwtUtils.HEADER))
@Parameter(name = "channelId", description = "通道国标编号", required = true)
@Parameter(name = "scanId", description = "扫描组号(0-100)", required = true)
@GetMapping("/scan/set/left")
public DeferredResult<WVPResult<String>> setScanLeft(Integer channelId, Integer scanId) {
FrontEndControlCodeForScan controlCode = new FrontEndControlCodeForScan();
controlCode.setCode(2);
controlCode.setScanId(scanId);
return scanControl(channelId, controlCode);
}
@Operation(summary = "扫描指令-设置自动扫描右边界", security = @SecurityRequirement(name = JwtUtils.HEADER))
@Parameter(name = "channelId", description = "通道国标编号", required = true)
@Parameter(name = "scanId", description = "扫描组号(0-100)", required = true)
@GetMapping("/scan/set/right")
public DeferredResult<WVPResult<String>> setScanRight(Integer channelId, Integer scanId) {
FrontEndControlCodeForScan controlCode = new FrontEndControlCodeForScan();
controlCode.setCode(3);
controlCode.setScanId(scanId);
return scanControl(channelId, controlCode);
}
@Operation(summary = "扫描指令-设置自动扫描速度", security = @SecurityRequirement(name = JwtUtils.HEADER))
@Parameter(name = "channelId", description = "通道国标编号", required = true)
@Parameter(name = "scanId", description = "扫描组号(0-100)", required = true)
@Parameter(name = "speed", description = "自动扫描速度(1-4095)", required = true)
@GetMapping("/scan/set/speed")
public DeferredResult<WVPResult<String>> setScanSpeed(Integer channelId, Integer scanId, Integer speed) {
FrontEndControlCodeForScan controlCode = new FrontEndControlCodeForScan();
controlCode.setCode(4);
controlCode.setScanId(scanId);
controlCode.setScanSpeed(speed);
return scanControl(channelId, controlCode);
}
@Operation(summary = "辅助开关控制指令-雨刷控制", security = @SecurityRequirement(name = JwtUtils.HEADER))
@Parameter(name = "channelId", description = "通道国标编号", required = true)
@Parameter(name = "command", description = "控制指令,允许值: on, off", required = true)
@GetMapping("/wiper")
public DeferredResult<WVPResult<String>> wiper(Integer channelId, String command){
CommonGBChannel channel = channelService.getOne(channelId);
Assert.notNull(channel, "通道不存在");
FrontEndControlCodeForWiper controlCode = new FrontEndControlCodeForWiper();
switch (command){
case "on":
controlCode.setCode(1);
break;
case "off":
controlCode.setCode(2);
break;
default:
break;
}
DeferredResult<WVPResult<String>> result = new DeferredResult<>();
result.onTimeout(()->{
WVPResult<String> wvpResult = WVPResult.fail(ErrorCode.ERROR100.getCode(), "请求超时");
result.setResult(wvpResult);
});
ErrorCallback<String> callback = (code, msg, data) -> {
WVPResult<String> wvpResult = new WVPResult<>();
wvpResult.setCode(code);
wvpResult.setMsg(msg);
wvpResult.setData(data);
result.setResult(wvpResult);
};
channelControlService.wiper(channel, controlCode, callback);
return result;
}
@Operation(summary = "辅助开关控制指令", security = @SecurityRequirement(name = JwtUtils.HEADER))
@Parameter(name = "channelId", description = "通道国标编号", required = true)
@Parameter(name = "command", description = "控制指令,允许值: on, off", required = true)
@Parameter(name = "auxiliaryId", description = "开关编号", required = true)
@GetMapping("/auxiliary")
public DeferredResult<WVPResult<String>> auxiliarySwitch(Integer channelId, String command, Integer auxiliaryId){
CommonGBChannel channel = channelService.getOne(channelId);
Assert.notNull(channel, "通道不存在");
FrontEndControlCodeForAuxiliary controlCode = new FrontEndControlCodeForAuxiliary();
controlCode.setAuxiliaryId(auxiliaryId);
switch (command){
case "on":
controlCode.setCode(1);
break;
case "off":
controlCode.setCode(2);
break;
default:
break;
}
DeferredResult<WVPResult<String>> result = new DeferredResult<>();
result.onTimeout(()->{
WVPResult<String> wvpResult = WVPResult.fail(ErrorCode.ERROR100.getCode(), "请求超时");
result.setResult(wvpResult);
});
ErrorCallback<String> callback = (code, msg, data) -> {
WVPResult<String> wvpResult = new WVPResult<>();
wvpResult.setCode(code);
wvpResult.setMsg(msg);
wvpResult.setData(data);
result.setResult(wvpResult);
};
channelControlService.auxiliary(channel, controlCode, callback);
return result;
}
}

View File

@ -70,16 +70,16 @@ public class DeviceControl {
@Operation(summary = "布防/撤防", security = @SecurityRequirement(name = JwtUtils.HEADER))
@Parameter(name = "deviceId", description = "设备国标编号", required = true)
@Parameter(name = "guardCmdStr", description = "命令, 可选值SetGuard布防ResetGuard撤防", required = true)
@Parameter(name = "guardCmd", description = "命令, 可选值SetGuard布防ResetGuard撤防", required = true)
@GetMapping("/guard")
public DeferredResult<WVPResult<String>> guardApi(String deviceId, String guardCmdStr) {
public DeferredResult<WVPResult<String>> guardApi(String deviceId, String guardCmd) {
if (log.isDebugEnabled()) {
log.debug("布防/撤防API调用");
}
Device device = deviceService.getDeviceByDeviceId(deviceId);
Assert.notNull(device, "设备不存在");
DeferredResult<WVPResult<String>> result = new DeferredResult<>();
deviceService.guard(device, guardCmdStr, (code, msg, data) -> {
deviceService.guard(device, guardCmd, (code, msg, data) -> {
result.setResult(new WVPResult<>(code, msg, data));
});
result.onTimeout(() -> {

View File

@ -31,8 +31,8 @@ import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.request.async.DeferredResult;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
@ -113,6 +113,19 @@ public class DeviceQuery {
return deviceChannelService.queryChannelsByDeviceId(deviceId, query, channelType, online, page, count);
}
@GetMapping("/streams")
@Operation(summary = "分页查询存在流的通道", security = @SecurityRequirement(name = JwtUtils.HEADER))
@Parameter(name = "page", description = "当前页", required = true)
@Parameter(name = "count", description = "每页查询数量", required = true)
@Parameter(name = "query", description = "查询内容")
public PageInfo<DeviceChannel> streamChannels(int page, int count,
@RequestParam(required = false) String query) {
if (ObjectUtils.isEmpty(query)) {
query = null;
}
return deviceChannelService.queryChannels(query, true, null, null, true, page, count);
}
@Operation(summary = "同步设备通道", security = @SecurityRequirement(name = JwtUtils.HEADER))
@Parameter(name = "deviceId", description = "设备国标编号", required = true)

View File

@ -31,7 +31,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.async.DeferredResult;
import javax.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletRequest;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

View File

@ -5,6 +5,7 @@ import com.genersoft.iot.vmp.gb28181.bean.Group;
import com.genersoft.iot.vmp.gb28181.bean.GroupTree;
import com.genersoft.iot.vmp.gb28181.service.IGroupService;
import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
import com.github.pagehelper.PageInfo;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
@ -33,7 +34,7 @@ public class GroupController {
groupService.add(group);
}
@Operation(summary = "查询分组")
@Operation(summary = "查询分组节点")
@Parameter(name = "query", description = "要搜索的内容", required = true)
@Parameter(name = "parent", description = "所属分组编号", required = true)
@ResponseBody
@ -49,6 +50,17 @@ public class GroupController {
return groupService.queryForTree(query, parent, hasChannel);
}
@Operation(summary = "查询分组")
@Parameter(name = "query", description = "要搜索的内容", required = true)
@Parameter(name = "channel", description = "true为查询通道false为查询节点", required = true)
@ResponseBody
@GetMapping("/tree/query")
public PageInfo<Group> queryTree(Integer page, Integer count,
@RequestParam(required = true) String query
){
return groupService.queryList(page, count, query);
}
@Operation(summary = "更新分组")
@Parameter(name = "group", description = "Group", required = true)
@ResponseBody

View File

@ -7,19 +7,26 @@ import com.genersoft.iot.vmp.conf.security.SecurityUtils;
import com.genersoft.iot.vmp.conf.security.dto.LoginUser;
import com.genersoft.iot.vmp.media.service.IMediaServerService;
import com.genersoft.iot.vmp.media.zlm.dto.StreamAuthorityInfo;
import com.genersoft.iot.vmp.service.bean.ErrorCallback;
import com.genersoft.iot.vmp.service.bean.InviteErrorCode;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import com.genersoft.iot.vmp.streamProxy.service.IStreamProxyService;
import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
import com.genersoft.iot.vmp.vmanager.bean.StreamContent;
import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.request.async.DeferredResult;
import javax.servlet.http.HttpServletRequest;
import java.net.MalformedURLException;
import java.net.URL;
@Tag(name = "媒体流相关")
@ -52,11 +59,12 @@ public class MediaController {
@Parameter(name = "useSourceIpAsStreamIp", description = "是否使用请求IP作为返回的地址IP")
@GetMapping(value = "/stream_info_by_app_and_stream")
@ResponseBody
public StreamContent getStreamInfoByAppAndStream(HttpServletRequest request, @RequestParam String app,
public DeferredResult<WVPResult<StreamContent>> getStreamInfoByAppAndStream(HttpServletRequest request, @RequestParam String app,
@RequestParam String stream,
@RequestParam(required = false) String mediaServerId,
@RequestParam(required = false) String callId,
@RequestParam(required = false) Boolean useSourceIpAsStreamIp){
DeferredResult<WVPResult<StreamContent>> result = new DeferredResult<>();
boolean authority = false;
if (callId != null) {
// 权限校验
@ -75,9 +83,7 @@ public class MediaController {
authority = true;
}
}
StreamInfo streamInfo;
if (useSourceIpAsStreamIp != null && useSourceIpAsStreamIp) {
String host = request.getHeader("Host");
String localAddr = host.split(":")[0];
@ -88,30 +94,37 @@ public class MediaController {
}
if (streamInfo != null){
return new StreamContent(streamInfo);
WVPResult<StreamContent> wvpResult = WVPResult.success();
wvpResult.setData(new StreamContent(streamInfo));
result.setResult(wvpResult);
}else {
//获取流失败重启拉流后重试一次
streamProxyService.stopByAppAndStream(app,stream);
boolean start = streamProxyService.startByAppAndStream(app, stream);
ErrorCallback<StreamInfo> callback = (code, msg, streamInfoStoStart) -> {
if (code == InviteErrorCode.SUCCESS.getCode()) {
WVPResult<StreamContent> wvpResult = WVPResult.success();
if (useSourceIpAsStreamIp != null && useSourceIpAsStreamIp) {
String host;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
log.error("[线程休眠失败] {}", e.getMessage());
URL url=new URL(request.getRequestURL().toString());
host=url.getHost();
} catch (MalformedURLException e) {
host=request.getLocalAddr();
}
if (useSourceIpAsStreamIp != null && useSourceIpAsStreamIp) {
String host = request.getHeader("Host");
String localAddr = host.split(":")[0];
log.info("使用{}作为返回流的ip", localAddr);
streamInfo = mediaServerService.getStreamInfoByAppAndStreamWithCheck(app, stream, mediaServerId, localAddr, authority);
streamInfoStoStart.changeStreamIp(host);
}
if (!ObjectUtils.isEmpty(streamInfoStoStart.getMediaServer().getTranscodeSuffix())
&& !"null".equalsIgnoreCase(streamInfoStoStart.getMediaServer().getTranscodeSuffix())) {
streamInfoStoStart.setStream(streamInfoStoStart.getStream() + "_" + streamInfoStoStart.getMediaServer().getTranscodeSuffix());
}
wvpResult.setData(new StreamContent(streamInfoStoStart));
result.setResult(wvpResult);
}else {
streamInfo = mediaServerService.getStreamInfoByAppAndStreamWithCheck(app, stream, mediaServerId, authority);
}
if (streamInfo != null){
return new StreamContent(streamInfo);
}else {
throw new ControllerException(ErrorCode.ERROR100);
result.setResult(WVPResult.fail(code, msg));
}
};
//获取流失败重启拉流后重试一次
streamProxyService.startByAppAndStream(app, stream, callback);
}
return result;
}
/**
* 获取推流播放地址

View File

@ -93,9 +93,6 @@ public class PlatformController {
@ResponseBody
public void add(@RequestBody Platform platform) {
if (log.isDebugEnabled()) {
log.debug("保存上级平台信息API调用");
}
Assert.notNull(platform.getName(), "平台名称不可为空");
Assert.notNull(platform.getServerGBId(), "上级平台国标编号不可为空");
Assert.notNull(platform.getServerIp(), "上级平台IP不可为空");
@ -140,9 +137,6 @@ public class PlatformController {
@ResponseBody
public void updatePlatform(@RequestBody Platform parentPlatform) {
if (log.isDebugEnabled()) {
log.debug("保存上级平台信息API调用");
}
if (ObjectUtils.isEmpty(parentPlatform.getName())
|| ObjectUtils.isEmpty(parentPlatform.getServerGBId())
|| ObjectUtils.isEmpty(parentPlatform.getServerGBDomain())
@ -163,16 +157,14 @@ public class PlatformController {
@Parameter(name = "id", description = "上级平台ID")
@DeleteMapping("/delete")
@ResponseBody
public DeferredResult<Object> deletePlatform(Integer id) {
public DeferredResult<WVPResult<?>> deletePlatform(Integer id) {
if (log.isDebugEnabled()) {
log.debug("删除上级平台API调用");
}
DeferredResult<Object> deferredResult = new DeferredResult<>();
DeferredResult<WVPResult<?>> deferredResult = new DeferredResult<>();
platformService.delete(id, (object)->{
deferredResult.setResult(WVPResult.success());
});
platformService.delete(id, (object)-> deferredResult.setResult(WVPResult.success()));
return deferredResult;
}

View File

@ -37,7 +37,7 @@ import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.request.async.DeferredResult;
import javax.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletRequest;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.List;

View File

@ -1,6 +1,5 @@
package com.genersoft.iot.vmp.gb28181.controller;
import com.genersoft.iot.vmp.common.InviteInfo;
import com.genersoft.iot.vmp.common.InviteSessionType;
import com.genersoft.iot.vmp.common.StreamInfo;
import com.genersoft.iot.vmp.conf.UserSetting;
@ -26,6 +25,7 @@ import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
@ -33,7 +33,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.async.DeferredResult;
import javax.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletRequest;
import javax.sip.InvalidArgumentException;
import javax.sip.SipException;
import java.net.MalformedURLException;
@ -165,10 +165,10 @@ public class PlaybackController {
@Operation(summary = "回放暂停", security = @SecurityRequirement(name = JwtUtils.HEADER))
@Parameter(name = "streamId", description = "回放流ID", required = true)
@GetMapping("/pause/{streamId}")
public void playPause(@PathVariable String streamId) {
public void playbackPause(@PathVariable String streamId) {
log.info("[回放暂停] streamId: {}", streamId);
try {
playService.pauseRtp(streamId);
playService.playbackPause(streamId);
} catch (ServiceException e) {
throw new ControllerException(ErrorCode.ERROR400.getCode(), e.getMessage());
} catch (InvalidArgumentException | ParseException | SipException e) {
@ -183,7 +183,7 @@ public class PlaybackController {
public void playResume(@PathVariable String streamId) {
log.info("playResume: "+streamId);
try {
playService.resumeRtp(streamId);
playService.playbackResume(streamId);
} catch (ServiceException e) {
throw new ControllerException(ErrorCode.ERROR400.getCode(), e.getMessage());
} catch (InvalidArgumentException | ParseException | SipException e) {
@ -191,23 +191,14 @@ public class PlaybackController {
}
}
@Operation(summary = "回放拖动播放", security = @SecurityRequirement(name = JwtUtils.HEADER))
@Parameter(name = "streamId", description = "回放流ID", required = true)
@Parameter(name = "seekTime", description = "拖动偏移量单位s", required = true)
@GetMapping("/seek/{streamId}/{seekTime}")
public void playSeek(@PathVariable String streamId, @PathVariable long seekTime) {
public void playbackSeek(@PathVariable String streamId, @PathVariable long seekTime) {
log.info("playSeek: "+streamId+", "+seekTime);
InviteInfo inviteInfo = inviteStreamService.getInviteInfoByStream(InviteSessionType.PLAYBACK, streamId);
if (null == inviteInfo || inviteInfo.getStreamInfo() == null) {
log.warn("streamId不存在!");
throw new ControllerException(ErrorCode.ERROR400.getCode(), "streamId不存在");
}
Device device = deviceService.getDeviceByDeviceId(inviteInfo.getDeviceId());
DeviceChannel channel = channelService.getOneById(inviteInfo.getChannelId());
try {
cmder.playSeekCmd(device, channel, inviteInfo.getStreamInfo(), seekTime);
playService.playbackSeek(streamId, seekTime);
} catch (InvalidArgumentException | ParseException | SipException e) {
throw new ControllerException(ErrorCode.ERROR100.getCode(), e.getMessage());
}
@ -218,17 +209,10 @@ public class PlaybackController {
@Parameter(name = "speed", description = "倍速0.25 0.5 1、2、4、8", required = true)
@GetMapping("/speed/{streamId}/{speed}")
public void playSpeed(@PathVariable String streamId, @PathVariable Double speed) {
Assert.notNull(speed, "倍速不存在");
log.info("playSpeed: "+streamId+", "+speed);
InviteInfo inviteInfo = inviteStreamService.getInviteInfoByStream(InviteSessionType.PLAYBACK, streamId);
if (null == inviteInfo || inviteInfo.getStreamInfo() == null) {
log.warn("streamId不存在!");
throw new ControllerException(ErrorCode.ERROR400.getCode(), "streamId不存在");
}
Device device = deviceService.getDeviceByDeviceId(inviteInfo.getDeviceId());
DeviceChannel channel = channelService.getOneById(inviteInfo.getChannelId());
try {
cmder.playSpeedCmd(device, channel, inviteInfo.getStreamInfo(), speed);
playService.playbackSpeed(streamId, speed);
} catch (InvalidArgumentException | ParseException | SipException e) {
throw new ControllerException(ErrorCode.ERROR100.getCode(), e.getMessage());
}

View File

@ -50,20 +50,29 @@ public class RegionController {
return regionService.query(query, page, count);
}
@Operation(summary = "查询区域")
@Operation(summary = "查询区域节点")
@Parameter(name = "query", description = "要搜索的内容", required = true)
@Parameter(name = "parent", description = "所属行政区划编号", required = true)
@Parameter(name = "hasChannel", description = "是否查询通道", required = true)
@ResponseBody
@GetMapping("/tree/list")
public List<RegionTree> queryForTree(
@RequestParam(required = false) String query,
@RequestParam(required = false) Integer parent,
@RequestParam(required = false) Boolean hasChannel
){
if (ObjectUtils.isEmpty(query)) {
query = null;
return regionService.queryForTree(parent, hasChannel);
}
return regionService.queryForTree(query, parent, hasChannel);
@Operation(summary = "查询区域")
@Parameter(name = "query", description = "要搜索的内容", required = true)
@Parameter(name = "channel", description = "true为查询通道false为查询节点", required = true)
@ResponseBody
@GetMapping("/tree/query")
public PageInfo<Region> queryTree(Integer page, Integer count,
@RequestParam(required = true) String query
){
return regionService.queryList(page, count, query);
}
@Operation(summary = "更新区域")

View File

@ -8,8 +8,8 @@ import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;

View File

@ -57,7 +57,8 @@ public interface CommonGBChannelMapper {
"gb_business_group_id," +
"gb_download_speed," +
"gb_svc_space_support_mod," +
"gb_svc_time_support_mode ) " +
"gb_svc_time_support_mode," +
"enable_broadcast ) " +
"VALUES (" +
"#{gbDeviceId}, " +
"#{dataType}, " +
@ -96,7 +97,8 @@ public interface CommonGBChannelMapper {
"#{gbBusinessGroupId},"+
"#{gbDownloadSpeed},"+
"#{gbSvcSpaceSupportMod},"+
"#{gbSvcTimeSupportMode}"+
"#{gbSvcTimeSupportMode},"+
"#{enableBroadcast}"+
")" +
" </script>")
@Options(useGeneratedKeys = true, keyProperty = "gbId", keyColumn = "id")
@ -144,6 +146,7 @@ public interface CommonGBChannelMapper {
", gb_download_speed = #{gbDownloadSpeed}" +
", gb_svc_space_support_mod = #{gbSvcSpaceSupportMod}" +
", gb_svc_time_support_mode = #{gbSvcTimeSupportMode}" +
", enable_broadcast = #{enableBroadcast}" +
" WHERE id = #{gbId}"+
" </script>"})
int update(CommonGBChannel commonGBChannel);
@ -205,7 +208,8 @@ public interface CommonGBChannelMapper {
"gb_business_group_id," +
"gb_download_speed," +
"gb_svc_space_support_mod," +
"gb_svc_time_support_mode ) " +
"gb_svc_time_support_mode," +
"enable_broadcast ) " +
"VALUES" +
"<foreach collection='commonGBChannels' index='index' item='item' separator=','> " +
"(#{item.gbDeviceId}, #{item.dataType}, #{item.dataDeviceId},#{item.createTime},#{item.updateTime}," +
@ -214,7 +218,7 @@ public interface CommonGBChannelMapper {
"#{item.gbRegisterWay},#{item.gbCertNum},#{item.gbCertifiable},#{item.gbErrCode},#{item.gbEndTime}, #{item.gbSecrecy},#{item.gbIpAddress}," +
"#{item.gbPort},#{item.gbPassword},#{item.gbStatus},#{item.gbLongitude}, #{item.gbLatitude},#{item.gbPtzType},#{item.gbPositionType},#{item.gbRoomType}," +
"#{item.gbUseType},#{item.gbSupplyLightType},#{item.gbDirectionType},#{item.gbResolution},#{item.gbBusinessGroupId},#{item.gbDownloadSpeed}," +
"#{item.gbSvcSpaceSupportMod},#{item.gbSvcTimeSupportMode})" +
"#{item.gbSvcSpaceSupportMod},#{item.gbSvcTimeSupportMode},#{item.enableBroadcast})" +
"</foreach> " +
" </script>")
int batchAdd(List<CommonGBChannel> commonGBChannels);
@ -275,10 +279,8 @@ public interface CommonGBChannelMapper {
" true as is_leaf " +
" from wvp_device_channel " +
" where coalesce(gb_civil_code, civil_code) = #{parentDeviceId} " +
" <if test='query != null'> AND (coalesce(gb_device_id, device_id) LIKE concat('%',#{query},'%') " +
" OR coalesce(gb_name, name) LIKE concat('%',#{query},'%'))</if> " +
" </script>")
List<RegionTree> queryForRegionTreeByCivilCode(@Param("query") String query, @Param("parentDeviceId") String parentDeviceId);
List<RegionTree> queryForRegionTreeByCivilCode(@Param("parentDeviceId") String parentDeviceId);
@Update(value = {" <script>" +
" UPDATE wvp_device_channel " +
@ -426,6 +428,7 @@ public interface CommonGBChannelMapper {
", gb_download_speed=#{item.gbDownloadSpeed}" +
", gb_svc_space_support_mod=#{item.gbSvcSpaceSupportMod}" +
", gb_svc_time_support_mode=#{item.gbSvcTimeSupportMode}" +
", enable_broadcast = #{enableBroadcast}" +
" WHERE id=#{item.gbId}" +
"</foreach>" +
"</script>"})
@ -507,6 +510,7 @@ public interface CommonGBChannelMapper {
" wdc.create_time,\n" +
" wdc.update_time,\n" +
" wdc.record_plan_id,\n" +
" wdc.enable_broadcast,\n" +
" coalesce( wdc.gb_device_id, wdc.device_id) as gb_device_id,\n" +
" coalesce( wdc.gb_name, wdc.name) as gb_name,\n" +
" coalesce( wdc.gb_manufacturer, wdc.manufacturer) as gb_manufacturer,\n" +
@ -582,4 +586,21 @@ public interface CommonGBChannelMapper {
@SelectProvider(type = ChannelProvider.class, method = "queryOnlineListsByGbDeviceId")
List<CommonGBChannel> queryOnlineListsByGbDeviceId(@Param("deviceId") int deviceId);
@Update("UPDATE wvp_device_channel SET stream_id = #{stream} where id = #{gbId}")
void updateStream(int gbId, String stream);
@Update("<script> " +
"<foreach collection='commonGBChannels' index='index' item='item' separator=';'> " +
"UPDATE wvp_device_channel " +
" SET gb_longitude=#{item.gbLongitude}" +
", gb_latitude=#{item.gbLatitude} " +
", gps_speed=#{item.gpsSpeed} " +
", gps_altitude=#{item.gpsAltitude} " +
", gps_direction=#{item.gpsDirection} " +
", gps_time=#{item.gpsTime} " +
"WHERE id = #{item.gbId}" +
"</foreach> " +
"</script>")
void updateGps(List<CommonGBChannel> commonGBChannels);
}

View File

@ -4,7 +4,6 @@ import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
import com.genersoft.iot.vmp.gb28181.controller.bean.ChannelReduce;
import com.genersoft.iot.vmp.gb28181.dao.provider.DeviceChannelProvider;
import com.genersoft.iot.vmp.service.bean.GPSMsgInfo;
import com.genersoft.iot.vmp.web.gb28181.dto.DeviceChannelExtend;
import org.apache.ibatis.annotations.*;
import org.springframework.stereotype.Repository;
@ -23,13 +22,13 @@ public interface DeviceChannelMapper {
"insert into wvp_device_channel " +
"(device_id, data_type, data_device_id, name, manufacturer, model, owner, civil_code, block, " +
"address, parental, parent_id, safety_way, register_way, cert_num, certifiable, err_code, end_time, secrecy, " +
"ip_address, port, password, status, longitude, latitude, ptz_type, position_type, room_type, use_type, " +
"ip_address, port, password, status, longitude, latitude, gb_longitude, gb_latitude, ptz_type, position_type, room_type, use_type, " +
"supply_light_type, direction_type, resolution, business_group_id, download_speed, svc_space_support_mod, " +
"svc_time_support_mode, create_time, update_time, sub_count, stream_id, has_audio, gps_time, stream_identification, channel_type) " +
"values " +
"(#{deviceId}, #{dataType}, #{dataDeviceId}, #{name}, #{manufacturer}, #{model}, #{owner}, #{civilCode}, #{block}, " +
"#{address}, #{parental}, #{parentId}, #{safetyWay}, #{registerWay}, #{certNum}, #{certifiable}, #{errCode}, #{endTime}, #{secrecy}, " +
"#{ipAddress}, #{port}, #{password}, #{status}, #{longitude}, #{latitude}, #{ptzType}, #{positionType}, #{roomType}, #{useType}, " +
"#{ipAddress}, #{port}, #{password}, #{status}, #{longitude}, #{latitude}, #{gbLongitude}, #{gbLatitude}, #{ptzType}, #{positionType}, #{roomType}, #{useType}, " +
"#{supplyLightType}, #{directionType}, #{resolution}, #{businessGroupId}, #{downloadSpeed}, #{svcSpaceSupportMod}," +
" #{svcTimeSupportMode}, #{createTime}, #{updateTime}, #{subCount}, #{streamId}, #{hasAudio}, #{gpsTime}, #{streamIdentification}, #{channelType}) " +
"</script>")
@ -64,6 +63,8 @@ public interface DeviceChannelMapper {
", status=#{status}" +
", longitude=#{longitude}" +
", latitude=#{latitude}" +
", gb_longitude=#{gbLongitude}" +
", gb_latitude=#{gbLatitude}" +
", ptz_type=#{ptzType}" +
", position_type=#{positionType}" +
", room_type=#{roomType}" +
@ -86,10 +87,11 @@ public interface DeviceChannelMapper {
int update(DeviceChannel channel);
@SelectProvider(type = DeviceChannelProvider.class, method = "queryChannels")
List<DeviceChannel> queryChannels(@Param("dataDeviceId") int dataDeviceId, @Param("civilCode") String civilCode,
List<DeviceChannel> queryChannels(@Param("dataDeviceId") Integer dataDeviceId, @Param("civilCode") String civilCode,
@Param("businessGroupId") String businessGroupId, @Param("parentChannelId") String parentChannelId,
@Param("query") String query, @Param("hasSubChannel") Boolean hasSubChannel,
@Param("online") Boolean online, @Param("channelIds") List<String> channelIds);
@Param("query") String query, @Param("queryParent") Boolean queryParent,
@Param("hasSubChannel") Boolean hasSubChannel, @Param("online") Boolean online,
@Param("channelIds") List<String> channelIds, @Param("hasStream") Boolean hasStream);
@SelectProvider(type = DeviceChannelProvider.class, method = "queryChannelsByDeviceDbId")
List<DeviceChannel> queryChannelsByDeviceDbId(@Param("dataDeviceId") int dataDeviceId);
@ -198,14 +200,14 @@ public interface DeviceChannelMapper {
"insert into wvp_device_channel " +
"(device_id, data_type, data_device_id, name, manufacturer, model, owner, civil_code, block, " +
"address, parental, parent_id, safety_way, register_way, cert_num, certifiable, err_code, end_time, secrecy, " +
"ip_address, port, password, status, longitude, latitude, ptz_type, position_type, room_type, use_type, " +
"ip_address, port, password, status, longitude, latitude, gb_longitude, gb_latitude, ptz_type, position_type, room_type, use_type, " +
"supply_light_type, direction_type, resolution, business_group_id, download_speed, svc_space_support_mod, " +
"svc_time_support_mode, create_time, update_time, sub_count, stream_id, has_audio, gps_time, stream_identification, channel_type) " +
"values " +
"<foreach collection='addChannels' index='index' item='item' separator=','> " +
"(#{item.deviceId}, #{item.dataType}, #{item.dataDeviceId}, #{item.name}, #{item.manufacturer}, #{item.model}, #{item.owner}, #{item.civilCode}, #{item.block}, " +
"#{item.address}, #{item.parental}, #{item.parentId}, #{item.safetyWay}, #{item.registerWay}, #{item.certNum}, #{item.certifiable}, #{item.errCode}, #{item.endTime}, #{item.secrecy}, " +
"#{item.ipAddress}, #{item.port}, #{item.password}, #{item.status}, #{item.longitude}, #{item.latitude}, #{item.ptzType}, #{item.positionType}, #{item.roomType}, #{item.useType}, " +
"#{item.ipAddress}, #{item.port}, #{item.password}, #{item.status}, #{item.longitude}, #{item.latitude}, #{item.gbLongitude}, #{item.gbLatitude}, #{item.ptzType}, #{item.positionType}, #{item.roomType}, #{item.useType}, " +
"#{item.supplyLightType}, #{item.directionType}, #{item.resolution}, #{item.businessGroupId}, #{item.downloadSpeed}, #{item.svcSpaceSupportMod}," +
" #{item.svcTimeSupportMode}, #{item.createTime}, #{item.updateTime}, #{item.subCount}, #{item.streamId}, #{item.hasAudio}, #{item.gpsTime}, #{item.streamIdentification}, #{item.channelType}) " +
"</foreach> " +
@ -246,6 +248,8 @@ public interface DeviceChannelMapper {
", status=#{item.status}" +
", longitude=#{item.longitude}" +
", latitude=#{item.latitude}" +
", gb_longitude=#{gbLongitude}" +
", gb_latitude=#{gbLatitude}" +
", ptz_type=#{item.ptzType}" +
", position_type=#{item.positionType}" +
", room_type=#{item.roomType}" +
@ -268,72 +272,13 @@ public interface DeviceChannelMapper {
"</script>"})
int batchUpdate(List<DeviceChannel> updateChannels);
@Update({"<script>" +
"<foreach collection='updateChannels' item='item' separator=';'>" +
" UPDATE" +
" wvp_device_channel" +
" SET update_time=#{item.updateTime}" +
", device_id=#{item.deviceId}" +
", data_type=#{item.dataType}" +
", data_device_id=#{item.dataDeviceId}" +
", name=#{item.name}" +
", manufacturer=#{item.manufacturer}" +
", model=#{item.model}" +
", owner=#{item.owner}" +
", civil_code=#{item.civilCode}" +
", block=#{item.block}" +
", address=#{item.address}" +
", parental=#{item.parental}" +
", parent_id=#{item.parentId}" +
", safety_way=#{item.safetyWay}" +
", register_way=#{item.registerWay}" +
", cert_num=#{item.certNum}" +
", certifiable=#{item.certifiable}" +
", err_code=#{item.errCode}" +
", end_time=#{item.endTime}" +
", secrecy=#{item.secrecy}" +
", ip_address=#{item.ipAddress}" +
", port=#{item.port}" +
", password=#{item.password}" +
", status=#{item.status}" +
", longitude=#{item.longitude}" +
", latitude=#{item.latitude}" +
", ptz_type=#{item.ptzType}" +
", position_type=#{item.positionType}" +
", room_type=#{item.roomType}" +
", use_type=#{item.useType}" +
", supply_light_type=#{item.supplyLightType}" +
", direction_type=#{item.directionType}" +
", resolution=#{item.resolution}" +
", business_group_id=#{item.businessGroupId}" +
", download_speed=#{item.downloadSpeed}" +
", svc_space_support_mod=#{item.svcSpaceSupportMod}" +
", svc_time_support_mode=#{item.svcTimeSupportMode}" +
", sub_count=#{item.subCount}" +
", stream_id=#{item.streamId}" +
", has_audio=#{item.hasAudio}" +
", gps_time=#{item.gpsTime}" +
", stream_identification=#{item.streamIdentification}" +
", channel_type=#{item.channelType}" +
" WHERE data_type = #{item.dataType} and data_device_id = #{item.dataDeviceId} and device_id=#{item.deviceId}" +
"</foreach>" +
"</script>"})
int batchUpdateForNotify(List<DeviceChannel> updateChannels);
@Update(" update wvp_device_channel" +
" set sub_count = (select *" +
" from (select count(0)" +
" from wvp_device_channel" +
" where data_type = 1 and data_device_id = #{dataDeviceId} and parent_id = #{channelId}) as temp)" +
" where data_type = 1 and data_device_id = #{dataDeviceId} and device_id = #{channelId}")
int updateChannelSubCount(@Param("dataDeviceId") int dataDeviceId, @Param("channelId") String channelId);
@Update(value = {" <script>" +
" UPDATE wvp_device_channel " +
" SET " +
" latitude=#{latitude}, " +
" longitude=#{longitude}, " +
" gb_longitude=#{gbLongitude}, " +
" gb_latitude=#{gbLatitude}, " +
" gps_time=#{gpsTime} " +
" WHERE id=#{id} " +
" </script>"})
@ -373,6 +318,8 @@ public interface DeviceChannelMapper {
" status,\n" +
" longitude,\n" +
" latitude,\n" +
" gb_longitude,\n" +
" gb_latitude,\n" +
" ptz_type,\n" +
" position_type,\n" +
" room_type,\n" +
@ -428,6 +375,8 @@ public interface DeviceChannelMapper {
" SET update_time=#{item.updateTime}" +
"<if test='item.longitude != null'>, longitude=#{item.longitude}</if>" +
"<if test='item.latitude != null'>, latitude=#{item.latitude}</if>" +
"<if test='item.gbLongitude != null'>, gb_longitude=#{item.gbLongitude}</if>" +
"<if test='item.gbLatitude != null'>, gb_latitude=#{item.gbLatitude}</if>" +
"<if test='item.gpsTime != null'>, gps_time=#{item.gpsTime}</if>" +
"<if test='item.id > 0'>WHERE id=#{item.id}</if>" +
"<if test='item.id == 0'>WHERE data_type = #{item.dataType} and data_device_id=#{item.dataDeviceId} AND device_id=#{item.deviceId}</if>" +
@ -473,6 +422,8 @@ public interface DeviceChannelMapper {
" status,\n" +
" longitude,\n" +
" latitude,\n" +
" gb_longitude,\n" +
" gb_latitude,\n" +
" ptz_type,\n" +
" position_type,\n" +
" room_type,\n" +
@ -528,6 +479,8 @@ public interface DeviceChannelMapper {
" status,\n" +
" longitude,\n" +
" latitude,\n" +
" gb_longitude,\n" +
" gb_latitude,\n" +
" ptz_type,\n" +
" position_type,\n" +
" room_type,\n" +
@ -555,13 +508,6 @@ public interface DeviceChannelMapper {
" </script>"})
void changeAudio(@Param("channelId") int channelId, @Param("audio") boolean audio);
@Update("<script> " +
"<foreach collection='gpsMsgInfoList' index='index' item='item' separator=';'> " +
"UPDATE wvp_device_channel SET gb_longitude = #{item.lng}, gb_latitude=#{item.lat} WHERE id = #{item.channelId}" +
"</foreach> " +
"</script>")
void updateStreamGPS(List<GPSMsgInfo> gpsMsgInfoList);
@Update("UPDATE wvp_device_channel SET status=#{status} WHERE data_type=#{dataType} and data_device_id=#{dataDeviceId} AND device_id=#{deviceId}")
void updateStatus(DeviceChannel channel);
@ -594,6 +540,8 @@ public interface DeviceChannelMapper {
", status=#{status}" +
", longitude=#{longitude}" +
", latitude=#{latitude}" +
", gb_longitude=#{gbLongitude}" +
", gb_latitude=#{gbLatitude}" +
", ptz_type=#{ptzType}" +
", position_type=#{positionType}" +
", room_type=#{roomType}" +
@ -651,6 +599,8 @@ public interface DeviceChannelMapper {
" status,\n" +
" longitude,\n" +
" latitude,\n" +
" gb_longitude,\n" +
" gb_latitude,\n" +
" ptz_type,\n" +
" position_type,\n" +
" room_type,\n" +

View File

@ -252,6 +252,7 @@ public interface DeviceMapper {
"mobile_position_submission_interval,"+
"subscribe_cycle_for_alarm,"+
"ssrc_check,"+
"media_server_id,"+
"as_message_channel,"+
"broadcast_push_after_ack,"+
"geo_coord_sys,"+

View File

@ -12,13 +12,13 @@ import java.util.Set;
@Mapper
public interface GroupMapper {
@Insert("INSERT INTO wvp_common_group (device_id, name, parent_id, parent_device_id, business_group, create_time, update_time, civil_code) " +
"VALUES (#{deviceId}, #{name}, #{parentId}, #{parentDeviceId}, #{businessGroup}, #{createTime}, #{updateTime}, #{civilCode})")
@Insert("INSERT INTO wvp_common_group (device_id, name, parent_id, parent_device_id, business_group, create_time, update_time, civil_code, alias) " +
"VALUES (#{deviceId}, #{name}, #{parentId}, #{parentDeviceId}, #{businessGroup}, #{createTime}, #{updateTime}, #{civilCode}, #{alias})")
@Options(useGeneratedKeys = true, keyProperty = "id", keyColumn = "id")
int add(Group group);
@Insert("INSERT INTO wvp_common_group (device_id, name, business_group, create_time, update_time, civil_code) " +
"VALUES (#{deviceId}, #{name}, #{businessGroup}, #{createTime}, #{updateTime}, #{civilCode})")
@Insert("INSERT INTO wvp_common_group (device_id, name, business_group, create_time, update_time, civil_code, alias) " +
"VALUES (#{deviceId}, #{name}, #{businessGroup}, #{createTime}, #{updateTime}, #{civilCode}, #{alias})")
@Options(useGeneratedKeys = true, keyProperty = "id", keyColumn = "id")
int addBusinessGroup(Group group);
@ -27,7 +27,8 @@ public interface GroupMapper {
@Update(" UPDATE wvp_common_group " +
" SET update_time=#{updateTime}, device_id=#{deviceId}, name=#{name}, parent_id=#{parentId}, " +
" parent_device_id=#{parentDeviceId}, business_group=#{businessGroup}, civil_code=#{civilCode}" +
" parent_device_id=#{parentDeviceId}, business_group=#{businessGroup}, civil_code=#{civilCode}, " +
" alias=#{alias}" +
" WHERE id = #{id}")
int update(Group group);
@ -55,10 +56,12 @@ public interface GroupMapper {
" business_group," +
" create_time," +
" civil_code," +
" alias," +
" update_time) " +
" VALUES " +
" <foreach collection='groupList' index='index' item='item' separator=','> " +
" (#{item.deviceId}, #{item.name}, #{item.parentDeviceId}, #{item.parentId}, #{item.businessGroup},#{item.createTime},#{item.civilCode},#{item.updateTime})" +
" (#{item.deviceId}, #{item.name}, #{item.parentDeviceId}, #{item.parentId}, #{item.businessGroup}," +
"#{item.createTime},#{item.civilCode},#{item.alias},#{item.updateTime})" +
" </foreach> " +
" </script>")
@Options(useGeneratedKeys = true, keyProperty = "id", keyColumn = "id")
@ -156,7 +159,8 @@ public interface GroupMapper {
" wcg.name as gb_name," +
" wcg.business_group as gb_business_group_id," +
" 1 as gb_parental," +
" wcg.parent_device_id as gb_parent_id" +
" wcg.parent_device_id as gb_parent_id," +
" wcg.civil_code as gb_civil_code" +
" from wvp_common_group wcg" +
" left join wvp_platform_group wpg on wpg.group_id = wcg.id" +
" where wpg.platform_id = #{platformId} " +
@ -199,6 +203,13 @@ public interface GroupMapper {
" where w1.id in " +
" <foreach collection='groupListForAdd' item='item' open='(' separator=',' close=')' > #{item.id}</foreach>" +
" </script>", databaseId = "mysql")
@Update(value = " <script>" +
" update wvp_common_group w1 " +
" inner join (select * from wvp_common_group ) w2 on w1.parent_device_id = w2.device_id " +
" set w1.parent_id = w2.id" +
" where w1.id in " +
" <foreach collection='groupListForAdd' item='item' open='(' separator=',' close=')' > #{item.id}</foreach>" +
" </script>", databaseId = "h2")
@Update( value = " <script>" +
" update wvp_common_group w1\n" +
" set parent_id = w2.id\n" +
@ -229,6 +240,18 @@ public interface GroupMapper {
" where w1.id in " +
" <foreach collection='groupListForAdd' item='item' open='(' separator=',' close=')' > #{item.id}</foreach>" +
" </script>", databaseId = "mysql")
@Update(value = " <script>" +
" update wvp_common_group w1 " +
" inner join (select * from wvp_common_group ) w2" +
" on w1.parent_device_id is null" +
" and w2.parent_device_id is null" +
" and w2.device_id = w2.business_group " +
" and w1.business_group = w2.device_id " +
" and w1.device_id != w1.business_group " +
" set w1.parent_id = w2.id" +
" where w1.id in " +
" <foreach collection='groupListForAdd' item='item' open='(' separator=',' close=')' > #{item.id}</foreach>" +
" </script>", databaseId = "h2")
@Update( value = " <script>" +
" update wvp_common_group w1 " +
" set parent_id = w2.id " +
@ -266,4 +289,7 @@ public interface GroupMapper {
@Delete("DELETE FROM wvp_platform_group WHERE group_id = #{groupId}")
void deletePlatformGroup(@Param("groupId") int groupId);
@Select("SELECT * from wvp_common_group WHERE alias = #{alias} ")
Group queryGroupByAlias(@Param("alias") String alias);
}

View File

@ -80,9 +80,8 @@ public interface RegionMapper {
" where " +
" <if test='parentId != null'> parent_id = #{parentId} </if> " +
" <if test='parentId == null'> parent_id is null </if> " +
" <if test='query != null'> AND (device_id LIKE concat('%',#{query},'%') escape '/' OR name LIKE concat('%',#{query},'%') escape '/')</if> " +
" </script>")
List<RegionTree> queryForTree(@Param("query") String query, @Param("parentId") Integer parentId);
List<RegionTree> queryForTree(@Param("parentId") Integer parentId);
@Delete("<script>" +
" DELETE FROM wvp_common_region WHERE id in " +
@ -115,6 +114,13 @@ public interface RegionMapper {
" where w1.id in " +
" <foreach collection='regionListForAdd' item='item' open='(' separator=',' close=')' > #{item.id}</foreach>" +
" </script>", databaseId = "mysql")
@Update(value = " <script>" +
" update wvp_common_region w1 " +
" inner join (select * from wvp_common_region ) w2 on w1.parent_device_id = w2.device_id " +
" set w1.parent_id = w2.id" +
" where w1.id in " +
" <foreach collection='regionListForAdd' item='item' open='(' separator=',' close=')' > #{item.id}</foreach>" +
" </script>", databaseId = "h2")
@Update( value = " <script>" +
" update wvp_common_region w1\n" +
" set parent_id = w2.id\n" +

View File

@ -16,7 +16,9 @@ public class ChannelProvider {
" data_device_id,\n" +
" create_time,\n" +
" update_time,\n" +
" stream_id,\n" +
" record_plan_id,\n" +
" enable_broadcast,\n" +
" coalesce(gb_device_id, device_id) as gb_device_id,\n" +
" coalesce(gb_name, name) as gb_name,\n" +
" coalesce(gb_manufacturer, manufacturer) as gb_manufacturer,\n" +
@ -60,7 +62,9 @@ public class ChannelProvider {
" wdc.data_device_id,\n" +
" wdc.create_time,\n" +
" wdc.update_time,\n" +
" wdc.stream_id,\n" +
" wdc.record_plan_id,\n" +
" wdc.enable_broadcast,\n" +
" coalesce(wdc.gb_device_id, wdc.device_id) as gb_device_id,\n" +
" coalesce(wdc.gb_name, wdc.name) as gb_name,\n" +
" coalesce(wdc.gb_manufacturer, wdc.manufacturer) as gb_manufacturer,\n" +
@ -105,6 +109,7 @@ public class ChannelProvider {
" wdc.data_device_id,\n" +
" wdc.create_time,\n" +
" wdc.update_time,\n" +
" wdc.enable_broadcast,\n" +
" coalesce(wpgc.custom_device_id, wdc.gb_device_id, wdc.device_id) as gb_device_id,\n" +
" coalesce(wpgc.custom_name, wdc.gb_name, wdc.name) as gb_name,\n" +
" coalesce(wpgc.custom_manufacturer, wdc.gb_manufacturer, wdc.manufacturer) as gb_manufacturer,\n" +

View File

@ -20,6 +20,8 @@ public class DeviceChannelProvider {
" dc.gps_time,\n" +
" dc.stream_identification,\n" +
" dc.channel_type,\n" +
" d.device_id as parent_device_id,\n" +
" coalesce(d.custom_name, d.name) as parent_name,\n" +
" coalesce(dc.gb_device_id, dc.device_id) as device_id,\n" +
" coalesce(dc.gb_name, dc.name) as name,\n" +
" coalesce(dc.gb_manufacturer, dc.manufacturer) as manufacturer,\n" +
@ -55,13 +57,17 @@ public class DeviceChannelProvider {
" coalesce(dc.gb_svc_space_support_mod, dc.svc_space_support_mod) as svc_space_support_mod,\n" +
" coalesce(dc.gb_svc_time_support_mode,dc.svc_time_support_mode) as svc_time_support_mode\n" +
" from " +
" wvp_device_channel dc "
" wvp_device_channel dc " +
" left join wvp_device d on d.id = dc.data_device_id "
;
}
public String queryChannels(Map<String, Object> params ){
StringBuilder sqlBuild = new StringBuilder();
sqlBuild.append(getBaseSelectSql());
sqlBuild.append(" where data_type = " + ChannelDataType.GB28181.value + " and dc.data_device_id = #{dataDeviceId} ");
sqlBuild.append(" where data_type = " + ChannelDataType.GB28181);
if (params.get("dataDeviceId") != null) {
sqlBuild.append(" AND dc.data_device_id = #{dataDeviceId} ");
}
if (params.get("businessGroupId") != null ) {
sqlBuild.append(" AND coalesce(dc.gb_business_group_id, dc.business_group_id)=#{businessGroupId} AND coalesce(dc.gb_parent_id, dc.parent_id) is null");
}else if (params.get("parentChannelId") != null ) {
@ -73,8 +79,15 @@ public class DeviceChannelProvider {
}
if (params.get("query") != null && !ObjectUtils.isEmpty(params.get("query"))) {
sqlBuild.append(" AND (coalesce(dc.gb_device_id, dc.device_id) LIKE concat('%',#{query},'%') escape '/'" +
" OR coalesce(dc.gb_name, dc.name) LIKE concat('%',#{query},'%') escape '/')")
;
" OR coalesce(dc.gb_name, dc.name) LIKE concat('%',#{query},'%') escape '/'");
if (params.get("queryParent") != null && (Boolean) params.get("queryParent")) {
sqlBuild.append(" OR d.device_id LIKE concat('%',#{query},'%') escape '/'");
sqlBuild.append(" OR coalesce(d.custom_name, d.name) LIKE concat('%',#{query},'%') escape '/'");
}
sqlBuild.append(")");
}
if (params.get("hasStream") != null && (Boolean) params.get("hasStream")) {
sqlBuild.append(" AND dc.stream_id IS NOT NULL");
}
if (params.get("online") != null && (Boolean)params.get("online")) {
sqlBuild.append(" AND coalesce(gb_status, status) = 'ON'");
@ -101,7 +114,7 @@ public class DeviceChannelProvider {
}
sqlBuild.append(" )");
}
sqlBuild.append(" ORDER BY device_id");
sqlBuild.append(" ORDER BY d.device_id, dc.device_id");
return sqlBuild.toString();
}
@ -109,14 +122,14 @@ public class DeviceChannelProvider {
public String queryChannelsByDeviceDbId(Map<String, Object> params ){
StringBuilder sqlBuild = new StringBuilder();
sqlBuild.append(getBaseSelectSql());
sqlBuild.append(" where data_type = " + ChannelDataType.GB28181.value + " and dc.data_device_id = #{dataDeviceId}");
sqlBuild.append(" where data_type = " + ChannelDataType.GB28181 + " and dc.data_device_id = #{dataDeviceId}");
return sqlBuild.toString();
}
public String queryAllChannels(Map<String, Object> params ){
StringBuilder sqlBuild = new StringBuilder();
sqlBuild.append(getBaseSelectSql());
sqlBuild.append(" where data_type = " + ChannelDataType.GB28181.value + " and dc.data_device_id = #{dataDeviceId}");
sqlBuild.append(" where data_type = " + ChannelDataType.GB28181 + " and dc.data_device_id = #{dataDeviceId}");
return sqlBuild.toString();
}
@ -130,25 +143,25 @@ public class DeviceChannelProvider {
public String getOneByDeviceId(Map<String, Object> params ){
StringBuilder sqlBuild = new StringBuilder();
sqlBuild.append(getBaseSelectSql());
sqlBuild.append(" where data_type = " + ChannelDataType.GB28181.value + " and dc.data_device_id=#{dataDeviceId} and coalesce(dc.gb_device_id, dc.device_id) = #{channelId}");
sqlBuild.append(" where data_type = " + ChannelDataType.GB28181 + " and dc.data_device_id=#{dataDeviceId} and coalesce(dc.gb_device_id, dc.device_id) = #{channelId}");
return sqlBuild.toString();
}
public String queryByDeviceId(Map<String, Object> params ){
return getBaseSelectSql() + " where data_type = " + ChannelDataType.GB28181.value + " and channel_type = 0 and coalesce(gb_device_id, device_id) = #{gbDeviceId}";
return getBaseSelectSql() + " where data_type = " + ChannelDataType.GB28181 + " and channel_type = 0 and coalesce(gb_device_id, device_id) = #{gbDeviceId}";
}
public String queryById(Map<String, Object> params ){
return getBaseSelectSql() + " where data_type = " + ChannelDataType.GB28181.value + " and channel_type = 0 and id = #{gbId}";
return getBaseSelectSql() + " where data_type = " + ChannelDataType.GB28181 + " and channel_type = 0 and id = #{gbId}";
}
public String queryList(Map<String, Object> params ){
StringBuilder sqlBuild = new StringBuilder();
sqlBuild.append(getBaseSelectSql());
sqlBuild.append(" where channel_type = 0 and data_type = " + ChannelDataType.GB28181.value);
sqlBuild.append(" where channel_type = 0 and data_type = " + ChannelDataType.GB28181);
if (params.get("query") != null) {
sqlBuild.append(" AND (coalesce(gb_device_id, device_id) LIKE concat('%',#{query},'%')" +
" OR coalesce(gb_name, name) LIKE concat('%',#{query},'%') )")

View File

@ -50,14 +50,6 @@ public class SipSubscribe {
}
}
public void updateTimeout(String callId) {
SipEvent sipEvent = subscribes.get(callId);
if (sipEvent != null) {
delayQueue.remove(sipEvent);
delayQueue.offer(sipEvent);
}
}
public interface Event { void response(EventResult eventResult);
}

View File

@ -6,7 +6,7 @@ import org.jetbrains.annotations.NotNull;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import jakarta.annotation.Resource;
/**
* 报警事件监听器.

View File

@ -1,18 +1,14 @@
package com.genersoft.iot.vmp.gb28181.service;
import com.genersoft.iot.vmp.gb28181.bean.*;
import com.genersoft.iot.vmp.common.enums.DeviceControlType;
import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
import com.genersoft.iot.vmp.gb28181.bean.MobilePosition;
import com.genersoft.iot.vmp.gb28181.controller.bean.ChannelReduce;
import com.genersoft.iot.vmp.gb28181.bean.*;
import com.genersoft.iot.vmp.service.bean.ErrorCallback;
import com.genersoft.iot.vmp.vmanager.bean.ResourceBaseInfo;
import com.genersoft.iot.vmp.web.gb28181.dto.DeviceChannelExtend;
import com.github.pagehelper.PageInfo;
import jakarta.validation.constraints.NotNull;
import org.dom4j.Element;
import javax.validation.constraints.NotNull;
import java.util.List;
/**
@ -32,28 +28,6 @@ public interface IDeviceChannelService {
*/
ResourceBaseInfo getOverview();
/**
* 查询所有未分配的通道
* @param platformId
* @return
*/
List<ChannelReduce> queryAllChannelList(String platformId);
PageInfo<ChannelReduce> queryAllChannelList(int page, int count, String query, Boolean online, Boolean channelType, String platformId, String catalogId);
/**
* 查询通道所属的设备
*/
List<Device> getDeviceByChannelId(String channelId);
/**
* 批量删除通道
* @param deleteChannelList 待删除的通道列表
*/
int deleteChannelsForNotify(List<DeviceChannel> deleteChannelList);
int updateChannelsStatus(List<DeviceChannel> channels);
/**
* 获取一个通道
*/
@ -61,16 +35,6 @@ public interface IDeviceChannelService {
DeviceChannel getOneForSource(String deviceId, String channelId);
/**
* 直接批量更新通道
*/
void batchUpdateChannelForNotify(List<DeviceChannel> channels);
/**
* 直接批量添加
*/
void batchAddChannel(List<DeviceChannel> deviceChannels);
/**
* 修改通道的码流类型
*/
@ -84,10 +48,6 @@ public interface IDeviceChannelService {
void stopPlay(Integer channelId);
void batchUpdateChannelGPS(List<DeviceChannel> channelList);
void batchAddMobilePosition(List<MobilePosition> addMobilePositionList);
void online(DeviceChannel channel);
void offline(DeviceChannel channel);
@ -104,6 +64,7 @@ public interface IDeviceChannelService {
PageInfo<DeviceChannel> queryChannelsByDeviceId(String deviceId, String query, Boolean channelType, Boolean online, int page, int count);
PageInfo<DeviceChannel> queryChannels(String query, Boolean queryParent, Boolean channelType, Boolean online, Boolean hasStream, int page, int count);
List<Device> queryDeviceWithAsMessageChannel();
@ -127,8 +88,6 @@ public interface IDeviceChannelService {
DeviceChannel getOneBySourceId(int deviceDbId, String channelId);
List<DeviceChannel> queryChaneListByDeviceDbId(Integer deviceDbId);
List<Integer> queryChaneIdListByDeviceDbIds(List<Integer> deviceDbId);
void handlePtzCmd(@NotNull Integer dataDeviceId, @NotNull Integer gbId, Element rootElement, DeviceControlType type, ErrorCallback<String> callback);

View File

@ -200,5 +200,6 @@ public interface IDeviceService {
void deviceInfo(Device device, ErrorCallback<Object> callback);
void queryPreset(Device device, String channelId, ErrorCallback<Object> callback);
void queryPreset(Device device, String channelId, ErrorCallback<List<Preset>> callback);
}

View File

@ -1,16 +1,19 @@
package com.genersoft.iot.vmp.gb28181.service;
import com.genersoft.iot.vmp.gb28181.bean.CommonGBChannel;
import com.genersoft.iot.vmp.gb28181.bean.FrontEndControlCodeForPTZ;
import com.genersoft.iot.vmp.gb28181.bean.*;
import com.genersoft.iot.vmp.service.bean.ErrorCallback;
import java.util.List;
public interface IGbChannelControlService {
void ptz(CommonGBChannel channel, FrontEndControlCodeForPTZ frontEndControlCode, ErrorCallback<String> callback);
void fi(CommonGBChannel channel, FrontEndControlCodeForPTZ frontEndControlCode, ErrorCallback<String> callback);
void preset(CommonGBChannel channel, FrontEndControlCodeForPTZ frontEndControlCode, ErrorCallback<String> callback);
void tour(CommonGBChannel channel, FrontEndControlCodeForPTZ frontEndControlCode, ErrorCallback<String> callback);
void scan(CommonGBChannel channel, FrontEndControlCodeForPTZ frontEndControlCode, ErrorCallback<String> callback);
void auxiliary(CommonGBChannel channel, FrontEndControlCodeForPTZ frontEndControlCode, ErrorCallback<String> callback);
void fi(CommonGBChannel channel, FrontEndControlCodeForFI frontEndControlCode, ErrorCallback<String> callback);
void preset(CommonGBChannel channel, FrontEndControlCodeForPreset frontEndControlCode, ErrorCallback<String> callback);
void tour(CommonGBChannel channel, FrontEndControlCodeForTour frontEndControlCode, ErrorCallback<String> callback);
void scan(CommonGBChannel channel, FrontEndControlCodeForScan frontEndControlCode, ErrorCallback<String> callback);
void wiper(CommonGBChannel channel, FrontEndControlCodeForWiper controlCode, ErrorCallback<String> callback);
void auxiliary(CommonGBChannel channel, FrontEndControlCodeForAuxiliary frontEndControlCode, ErrorCallback<String> callback);
void queryPreset(CommonGBChannel channel, ErrorCallback<List<Preset>> callback);
}

View File

@ -3,31 +3,39 @@ package com.genersoft.iot.vmp.gb28181.service;
import com.genersoft.iot.vmp.common.InviteSessionType;
import com.genersoft.iot.vmp.common.StreamInfo;
import com.genersoft.iot.vmp.gb28181.bean.CommonGBChannel;
import com.genersoft.iot.vmp.gb28181.bean.CommonRecordInfo;
import com.genersoft.iot.vmp.gb28181.bean.InviteMessageInfo;
import com.genersoft.iot.vmp.gb28181.bean.Platform;
import com.genersoft.iot.vmp.service.bean.ErrorCallback;
import java.util.List;
public interface IGbChannelPlayService {
void start(CommonGBChannel channel, InviteMessageInfo inviteInfo, Platform platform, ErrorCallback<StreamInfo> callback);
void startInvite(CommonGBChannel channel, InviteMessageInfo inviteInfo, Platform platform, ErrorCallback<StreamInfo> callback);
void stopPlay(InviteSessionType type, CommonGBChannel channel, String stream);
void stopInvite(InviteSessionType type, CommonGBChannel channel, String stream);
void playback(CommonGBChannel channel, Long startTime, Long stopTime, ErrorCallback<StreamInfo> callback);
void download(CommonGBChannel channel, Long startTime, Long stopTime, Integer downloadSpeed,
ErrorCallback<StreamInfo> callback);
void stopPlay(CommonGBChannel channel, String stream);
void play(CommonGBChannel channel, Platform platform, Boolean record, ErrorCallback<StreamInfo> callback);
void playGbDeviceChannel(CommonGBChannel channel, Boolean record, ErrorCallback<StreamInfo> callback);
void stopPlayback(CommonGBChannel channel, String stream);
void stopPlayDeviceChannel(InviteSessionType type, CommonGBChannel channel, String stream);
void stopDownload(CommonGBChannel channel, String stream);
void playProxy(CommonGBChannel channel, Boolean record, ErrorCallback<StreamInfo> callback);
void playbackPause(CommonGBChannel channel, String streamId);
void stopPlayProxy(CommonGBChannel channel);
void playbackResume(CommonGBChannel channel, String streamId);
void playPush(CommonGBChannel channel, String platformDeviceId, String platformName, ErrorCallback<StreamInfo> callback);
void playbackSeek(CommonGBChannel channel, String stream, long seekTime);
void stopPlayPush(CommonGBChannel channel);
void playbackSpeed(CommonGBChannel channel, String stream, Double speed);
void pauseRtp(String streamId);
void resumeRtp(String streamId);
void queryRecord(CommonGBChannel channel, String startTime, String endTime, ErrorCallback<List<CommonRecordInfo>> callback);
}

View File

@ -1,7 +1,6 @@
package com.genersoft.iot.vmp.gb28181.service;
import com.genersoft.iot.vmp.gb28181.bean.*;
import com.genersoft.iot.vmp.service.bean.ErrorCallback;
import com.genersoft.iot.vmp.service.bean.GPSMsgInfo;
import com.genersoft.iot.vmp.streamPush.bean.StreamPush;
import com.github.pagehelper.PageInfo;
@ -87,8 +86,6 @@ public interface IGbChannelService {
PageInfo<CommonGBChannel> queryList(int page, int count, String query, Boolean online, Boolean hasRecordPlan, Integer channelType);
void queryRecordInfo(CommonGBChannel channel, String startTime, String endTime, ErrorCallback<RecordInfo> callback);
PageInfo<CommonGBChannel> queryListByCivilCodeForUnusual(int page, int count, String query, Boolean online, Integer channelType);
void clearChannelCivilCode(Boolean all, List<Integer> channelIds);
@ -99,4 +96,7 @@ public interface IGbChannelService {
void updateGPSFromGPSMsgInfo(List<GPSMsgInfo> gpsMsgInfoList);
void updateGPS(List<CommonGBChannel> channelList);
List<CommonGBChannel> queryListForMap(String query, Boolean online, Boolean hasRecordPlan, Integer channelType);
}

View File

@ -2,6 +2,7 @@ package com.genersoft.iot.vmp.gb28181.service;
import com.genersoft.iot.vmp.gb28181.bean.Group;
import com.genersoft.iot.vmp.gb28181.bean.GroupTree;
import com.github.pagehelper.PageInfo;
import java.util.List;
@ -16,11 +17,13 @@ public interface IGroupService {
List<GroupTree> queryForTree(String query, Integer parent, Boolean hasChannel);
void syncFromChannel();
boolean delete(int id);
boolean batchAdd(List<Group> groupList);
List<Group> getPath(String deviceId, String businessGroup);
PageInfo<Group> queryList(Integer page, Integer count, String query);
Group queryGroupByAlias(String groupAlias);
}

View File

@ -4,21 +4,18 @@ package com.genersoft.iot.vmp.gb28181.service;
import com.genersoft.iot.vmp.gb28181.bean.CommonGBChannel;
import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.gb28181.bean.Preset;
import com.genersoft.iot.vmp.service.bean.ErrorCallback;
import java.util.List;
public interface IPTZService {
List<Preset> queryPresetList(String deviceId, String channelDeviceId);
void addPreset(Preset preset);
void deletePreset(Integer qq);
void ptz(Device device, String channelId, int cmdCode, int horizonSpeed, int verticalSpeed, int zoomSpeed);
void frontEndCommand(Device device, String channelId, int cmdCode, int parameter1, int parameter2, int combindCode2);
void frontEndCommand(CommonGBChannel channel, Integer cmdCode, Integer parameter1, Integer parameter2, Integer combindCode2);
void queryPresetList(CommonGBChannel channel, ErrorCallback<List<Preset>> callback);
}

View File

@ -48,9 +48,13 @@ public interface IPlayService {
void stopAudioBroadcast(Device device, DeviceChannel channel);
void pauseRtp(String streamId) throws ServiceException, InvalidArgumentException, ParseException, SipException;
void playbackPause(String streamId) throws ServiceException, InvalidArgumentException, ParseException, SipException;
void resumeRtp(String streamId) throws ServiceException, InvalidArgumentException, ParseException, SipException;
void playbackResume(String streamId) throws ServiceException, InvalidArgumentException, ParseException, SipException;
void playbackSeek(String streamId, long seekTime) throws InvalidArgumentException, ParseException, SipException;
void playbackSpeed(String streamId, double speed) throws InvalidArgumentException, ParseException, SipException;
void startPushStream(SendRtpInfo sendRtpItem, DeviceChannel channel, SIPResponse sipResponse, Platform platform, CallIdHeader callIdHeader);

View File

@ -27,7 +27,7 @@ public interface IRegionService {
Region queryRegionByDeviceId(String regionDeviceId);
List<RegionTree> queryForTree(String query, Integer parent, Boolean hasChannel);
List<RegionTree> queryForTree(Integer parent, Boolean hasChannel);
void syncFromChannel();
@ -40,4 +40,6 @@ public interface IRegionService {
String getDescription(String civilCode);
void addByCivilCode(String civilCode);
PageInfo<Region> queryList(int page, int count, String query);
}

View File

@ -0,0 +1,15 @@
package com.genersoft.iot.vmp.gb28181.service;
import com.genersoft.iot.vmp.common.StreamInfo;
import com.genersoft.iot.vmp.gb28181.bean.CommonGBChannel;
import com.genersoft.iot.vmp.service.bean.ErrorCallback;
/**
* 资源能力接入-录像下载
*/
public interface ISourceDownloadService {
void download(CommonGBChannel channel, Long startTime, Long stopTime, Integer downloadSpeed, ErrorCallback<StreamInfo> callback);
void stopDownload(CommonGBChannel channel, String stream);
}

View File

@ -0,0 +1,28 @@
package com.genersoft.iot.vmp.gb28181.service;
import com.genersoft.iot.vmp.gb28181.bean.*;
import com.genersoft.iot.vmp.service.bean.ErrorCallback;
import java.util.List;
/**
* 资源能力接入-云台控制
*/
public interface ISourcePTZService {
void ptz(CommonGBChannel channel, FrontEndControlCodeForPTZ frontEndControlCode, ErrorCallback<String> callback);
void preset(CommonGBChannel channel, FrontEndControlCodeForPreset frontEndControlCode, ErrorCallback<String> callback);
void fi(CommonGBChannel channel, FrontEndControlCodeForFI frontEndControlCode, ErrorCallback<String> callback);
void tour(CommonGBChannel channel, FrontEndControlCodeForTour frontEndControlCode, ErrorCallback<String> callback);
void scan(CommonGBChannel channel, FrontEndControlCodeForScan frontEndControlCode, ErrorCallback<String> callback);
void auxiliary(CommonGBChannel channel, FrontEndControlCodeForAuxiliary frontEndControlCode, ErrorCallback<String> callback);
void wiper(CommonGBChannel channel, FrontEndControlCodeForWiper frontEndControlCode, ErrorCallback<String> callback);
void queryPreset(CommonGBChannel channel, ErrorCallback<List<Preset>> callback);
}

View File

@ -0,0 +1,17 @@
package com.genersoft.iot.vmp.gb28181.service;
import com.genersoft.iot.vmp.common.StreamInfo;
import com.genersoft.iot.vmp.gb28181.bean.CommonGBChannel;
import com.genersoft.iot.vmp.gb28181.bean.Platform;
import com.genersoft.iot.vmp.service.bean.ErrorCallback;
/**
* 资源能力接入-实时录像
*/
public interface ISourcePlayService {
void play(CommonGBChannel channel, Platform platform, Boolean record, ErrorCallback<StreamInfo> callback);
void stopPlay(CommonGBChannel channel, String stream);
}

View File

@ -0,0 +1,28 @@
package com.genersoft.iot.vmp.gb28181.service;
import com.genersoft.iot.vmp.common.StreamInfo;
import com.genersoft.iot.vmp.gb28181.bean.CommonGBChannel;
import com.genersoft.iot.vmp.gb28181.bean.CommonRecordInfo;
import com.genersoft.iot.vmp.service.bean.ErrorCallback;
import java.util.List;
/**
* 资源能力接入-录像回放
*/
public interface ISourcePlaybackService {
void playback(CommonGBChannel channel, Long startTime, Long stopTime, ErrorCallback<StreamInfo> callback);
void stopPlayback(CommonGBChannel channel, String stream);
void playbackPause(CommonGBChannel channel, String stream);
void playbackResume(CommonGBChannel channel, String stream);
void playbackSeek(CommonGBChannel channel, String stream, long seekTime);
void playbackSpeed(CommonGBChannel channel, String stream, Double speed);
void queryRecord(CommonGBChannel channel, String startTime, String endTime, ErrorCallback<List<CommonRecordInfo>> callback);
}

View File

@ -8,7 +8,6 @@ import com.genersoft.iot.vmp.common.enums.DeviceControlType;
import com.genersoft.iot.vmp.conf.UserSetting;
import com.genersoft.iot.vmp.conf.exception.ControllerException;
import com.genersoft.iot.vmp.gb28181.bean.*;
import com.genersoft.iot.vmp.gb28181.controller.bean.ChannelReduce;
import com.genersoft.iot.vmp.gb28181.dao.DeviceChannelMapper;
import com.genersoft.iot.vmp.gb28181.dao.DeviceMapper;
import com.genersoft.iot.vmp.gb28181.dao.DeviceMobilePositionMapper;
@ -24,12 +23,14 @@ import com.genersoft.iot.vmp.gb28181.utils.SipUtils;
import com.genersoft.iot.vmp.service.bean.ErrorCallback;
import com.genersoft.iot.vmp.service.redisMsg.IRedisRpcPlayService;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import com.genersoft.iot.vmp.utils.Coordtransform;
import com.genersoft.iot.vmp.utils.DateUtil;
import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
import com.genersoft.iot.vmp.vmanager.bean.ResourceBaseInfo;
import com.genersoft.iot.vmp.web.gb28181.dto.DeviceChannelExtend;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import jakarta.validation.constraints.NotNull;
import lombok.extern.slf4j.Slf4j;
import org.dom4j.Element;
import org.springframework.beans.factory.annotation.Autowired;
@ -43,7 +44,6 @@ import org.springframework.util.ObjectUtils;
import javax.sip.InvalidArgumentException;
import javax.sip.SipException;
import javax.sip.message.Response;
import javax.validation.constraints.NotNull;
import java.text.ParseException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
@ -209,66 +209,6 @@ public class DeviceChannelServiceImpl implements IDeviceChannelService {
return new ResourceBaseInfo(total, online);
}
@Override
public List<ChannelReduce> queryAllChannelList(String platformId) {
return channelMapper.queryChannelListInAll(null, null, null, platformId, null);
}
@Override
public PageInfo<ChannelReduce> queryAllChannelList(int page, int count, String query, Boolean online, Boolean channelType, String platformId, String catalogId) {
PageHelper.startPage(page, count);
List<ChannelReduce> all = channelMapper.queryChannelListInAll(query, online, channelType, platformId, catalogId);
return new PageInfo<>(all);
}
@Override
public List<Device> getDeviceByChannelId(String channelId) {
return channelMapper.getDeviceByChannelDeviceId(channelId);
}
@Override
@Transactional
public int deleteChannelsForNotify(List<DeviceChannel> channels) {
int limitCount = 1000;
int result = 0;
if (!channels.isEmpty()) {
if (channels.size() > limitCount) {
for (int i = 0; i < channels.size(); i += limitCount) {
int toIndex = i + limitCount;
if (i + limitCount > channels.size()) {
toIndex = channels.size();
}
result += channelMapper.batchDel(channels.subList(i, toIndex));
}
}else {
result += channelMapper.batchDel(channels);
}
}
return result;
}
@Transactional
@Override
public int updateChannelsStatus(List<DeviceChannel> channels) {
int limitCount = 1000;
int result = 0;
if (!channels.isEmpty()) {
if (channels.size() > limitCount) {
for (int i = 0; i < channels.size(); i += limitCount) {
int toIndex = i + limitCount;
if (i + limitCount > channels.size()) {
toIndex = channels.size();
}
result += channelMapper.batchUpdateStatus(channels.subList(i, toIndex));
}
}else {
result += channelMapper.batchUpdateStatus(channels);
}
}
return result;
}
@Override
public void online(DeviceChannel channel) {
channelMapper.online(channel.getId());
@ -312,58 +252,6 @@ public class DeviceChannelServiceImpl implements IDeviceChannelService {
return channelMapper.getOneBySourceChannelId(deviceDbId, channelId);
}
@Override
@Transactional
public synchronized void batchUpdateChannelForNotify(List<DeviceChannel> channels) {
String now = DateUtil.getNow();
for (DeviceChannel channel : channels) {
channel.setUpdateTime(now);
}
int limitCount = 1000;
if (!channels.isEmpty()) {
if (channels.size() > limitCount) {
for (int i = 0; i < channels.size(); i += limitCount) {
int toIndex = i + limitCount;
if (i + limitCount > channels.size()) {
toIndex = channels.size();
}
channelMapper.batchUpdateForNotify(channels.subList(i, toIndex));
}
}else {
channelMapper.batchUpdateForNotify(channels);
}
}
}
@Override
@Transactional
public void batchAddChannel(List<DeviceChannel> channels) {
String now = DateUtil.getNow();
for (DeviceChannel channel : channels) {
channel.setUpdateTime(now);
channel.setCreateTime(now);
}
int limitCount = 1000;
if (!channels.isEmpty()) {
if (channels.size() > limitCount) {
for (int i = 0; i < channels.size(); i += limitCount) {
int toIndex = i + limitCount;
if (i + limitCount > channels.size()) {
toIndex = channels.size();
}
channelMapper.batchAdd(channels.subList(i, toIndex));
}
}else {
channelMapper.batchAdd(channels);
}
}
for (DeviceChannel channel : channels) {
if (channel.getParentId() != null) {
channelMapper.updateChannelSubCount(channel.getDataDeviceId(), channel.getParentId());
}
}
}
@Override
public void updateChannelStreamIdentification(DeviceChannel channel) {
Assert.hasLength(channel.getStreamIdentification(), "码流标识必须存在");
@ -389,11 +277,6 @@ public class DeviceChannelServiceImpl implements IDeviceChannelService {
return channelMapper.queryChannelsByDeviceDbId(device.getId());
}
@Override
public List<DeviceChannel> queryChaneListByDeviceDbId(Integer deviceDbId) {
return channelMapper.queryChannelsByDeviceDbId(deviceDbId);
}
@Override
public List<Integer> queryChaneIdListByDeviceDbIds(List<Integer> deviceDbIds) {
return channelMapper.queryChaneIdListByDeviceDbIds(deviceDbIds);
@ -434,6 +317,17 @@ public class DeviceChannelServiceImpl implements IDeviceChannelService {
@Override
public void updateChannelGPS(Device device, DeviceChannel deviceChannel, MobilePosition mobilePosition) {
if (device.getGeoCoordSys().equalsIgnoreCase("GCJ02")) {
Double[] wgs84Position = Coordtransform.GCJ02ToWGS84(mobilePosition.getLongitude(), mobilePosition.getLatitude());
mobilePosition.setLongitude(wgs84Position[0]);
mobilePosition.setLatitude(wgs84Position[1]);
Double[] wgs84PositionForChannel = Coordtransform.GCJ02ToWGS84(deviceChannel.getLongitude(), deviceChannel.getLatitude());
deviceChannel.setGbLongitude(wgs84PositionForChannel[0]);
deviceChannel.setGbLatitude(wgs84PositionForChannel[1]);
}
if (userSetting.getSavePositionHistory()) {
deviceMobilePositionMapper.insertNewPosition(mobilePosition);
}
@ -497,49 +391,6 @@ public class DeviceChannelServiceImpl implements IDeviceChannelService {
channelMapper.stopPlayById(channelId);
}
@Override
@Transactional
public void batchUpdateChannelGPS(List<DeviceChannel> channelList) {
for (DeviceChannel deviceChannel : channelList) {
deviceChannel.setUpdateTime(DateUtil.getNow());
if (deviceChannel.getGpsTime() == null) {
deviceChannel.setGpsTime(DateUtil.getNow());
}
}
int count = 1000;
if (channelList.size() > count) {
for (int i = 0; i < channelList.size(); i+=count) {
int toIndex = i+count;
if ( i + count > channelList.size()) {
toIndex = channelList.size();
}
List<DeviceChannel> channels = channelList.subList(i, toIndex);
channelMapper.batchUpdatePosition(channels);
}
}else {
channelMapper.batchUpdatePosition(channelList);
}
}
@Override
@Transactional
public void batchAddMobilePosition(List<MobilePosition> mobilePositions) {
// int count = 500;
// if (mobilePositions.size() > count) {
// for (int i = 0; i < mobilePositions.size(); i+=count) {
// int toIndex = i+count;
// if ( i + count > mobilePositions.size()) {
// toIndex = mobilePositions.size();
// }
// List<MobilePosition> mobilePositionsSub = mobilePositions.subList(i, toIndex);
// deviceMobilePositionMapper.batchadd(mobilePositionsSub);
// }
// }else {
// deviceMobilePositionMapper.batchadd(mobilePositions);
// }
deviceMobilePositionMapper.batchadd(mobilePositions);
}
@Override
public void cleanChannelsForDevice(int deviceId) {
channelMapper.cleanChannelsByDeviceId(deviceId);
@ -696,7 +547,7 @@ public class DeviceChannelServiceImpl implements IDeviceChannelService {
.replaceAll("%", "/%")
.replaceAll("_", "/_");
}
List<DeviceChannel> all = channelMapper.queryChannels(deviceDbId, civilCode, businessGroupId, parentId, query, channelType, online,null);
List<DeviceChannel> all = channelMapper.queryChannels(deviceDbId, civilCode, businessGroupId, parentId, query, false, channelType, online, null, null);
return new PageInfo<>(all);
}
@ -717,7 +568,19 @@ public class DeviceChannelServiceImpl implements IDeviceChannelService {
.replaceAll("_", "/_");
}
PageHelper.startPage(page, count);
List<DeviceChannel> all = channelMapper.queryChannels(device.getId(), null,null, null, query, hasSubChannel, online,null);
List<DeviceChannel> all = channelMapper.queryChannels(device.getId(), null, null, null, query, false, hasSubChannel, online, null, null);
return new PageInfo<>(all);
}
@Override
public PageInfo<DeviceChannel> queryChannels(String query, Boolean queryParent, Boolean hasSubChannel, Boolean online, Boolean hasStream, int page, int count) {
PageHelper.startPage(page, count);
if (query != null) {
query = query.replaceAll("/", "//")
.replaceAll("%", "/%")
.replaceAll("_", "/_");
}
List<DeviceChannel> all = channelMapper.queryChannels(null, null, null, null, query, queryParent, hasSubChannel, online, null, hasStream);
return new PageInfo<>(all);
}
@ -768,7 +631,7 @@ public class DeviceChannelServiceImpl implements IDeviceChannelService {
@Override
public void addChannel(DeviceChannel channel) {
channel.setDataType(ChannelDataType.GB28181.value);
channel.setDataType(ChannelDataType.GB28181);
channel.setDataDeviceId(channel.getDataDeviceId());
channelMapper.add(channel);
}
@ -814,7 +677,7 @@ public class DeviceChannelServiceImpl implements IDeviceChannelService {
@Override
public void queryRecordInfo(CommonGBChannel channel, String startTime, String endTime, ErrorCallback<RecordInfo> callback) {
if (channel.getDataType() != ChannelDataType.GB28181.value){
if (channel.getDataType() != ChannelDataType.GB28181){
// 只支持国标的语音喊话
log.warn("[INFO 消息] 非国标设备, 通道ID {}", channel.getGbId());
callback.run(ErrorCode.ERROR100.getCode(), "非国标设备", null);

View File

@ -39,6 +39,7 @@ import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import gov.nist.javax.sip.message.SIPResponse;
import jakarta.validation.constraints.NotNull;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
@ -51,7 +52,6 @@ import org.springframework.util.Assert;
import javax.sip.InvalidArgumentException;
import javax.sip.ResponseEvent;
import javax.sip.SipException;
import javax.validation.constraints.NotNull;
import java.text.ParseException;
import java.time.Instant;
import java.util.*;
@ -691,7 +691,7 @@ public class DeviceServiceImpl implements IDeviceService, CommandLineRunner {
@Override
public List<Device> getAllByStatus(Boolean status) {
return deviceMapper.getDevices(ChannelDataType.GB28181.value, status);
return deviceMapper.getDevices(ChannelDataType.GB28181, status);
}
@Override
@ -852,7 +852,7 @@ public class DeviceServiceImpl implements IDeviceService, CommandLineRunner {
.replaceAll("%", "/%")
.replaceAll("_", "/_");
}
List<Device> all = deviceMapper.getDeviceList(ChannelDataType.GB28181.value, query, status);
List<Device> all = deviceMapper.getDeviceList(ChannelDataType.GB28181, query, status);
return new PageInfo<>(all);
}
@ -863,12 +863,12 @@ public class DeviceServiceImpl implements IDeviceService, CommandLineRunner {
@Override
public Device getDeviceByChannelId(Integer channelId) {
return deviceMapper.queryByChannelId(ChannelDataType.GB28181.value,channelId);
return deviceMapper.queryByChannelId(ChannelDataType.GB28181,channelId);
}
@Override
public Device getDeviceBySourceChannelDeviceId(String channelId) {
return deviceMapper.getDeviceBySourceChannelDeviceId(ChannelDataType.GB28181.value,channelId);
return deviceMapper.getDeviceBySourceChannelDeviceId(ChannelDataType.GB28181,channelId);
}
@Override
@ -1252,9 +1252,9 @@ public class DeviceServiceImpl implements IDeviceService, CommandLineRunner {
}
@Override
public void queryPreset(Device device, String channelId, ErrorCallback<Object> callback) {
public void queryPreset(Device device, String channelId, ErrorCallback<List<Preset>> callback) {
if (!userSetting.getServerId().equals(device.getServerId())) {
WVPResult<Object> result = redisRpcService.queryPreset(device.getServerId(), device, channelId);
WVPResult<List<Preset>> result = redisRpcService.queryPreset(device.getServerId(), device, channelId);
callback.run(result.getCode(), result.getMsg(), result.getData());
return;
}
@ -1267,4 +1267,6 @@ public class DeviceServiceImpl implements IDeviceService, CommandLineRunner {
throw new ControllerException(ErrorCode.ERROR100.getCode(), "命令发送失败: " + e.getMessage());
}
}
}

View File

@ -1,43 +1,128 @@
package com.genersoft.iot.vmp.gb28181.service.impl;
import com.genersoft.iot.vmp.gb28181.bean.CommonGBChannel;
import com.genersoft.iot.vmp.gb28181.bean.FrontEndControlCodeForPTZ;
import com.genersoft.iot.vmp.common.enums.ChannelDataType;
import com.genersoft.iot.vmp.gb28181.bean.*;
import com.genersoft.iot.vmp.gb28181.service.IGbChannelControlService;
import com.genersoft.iot.vmp.gb28181.service.ISourcePTZService;
import com.genersoft.iot.vmp.service.bean.ErrorCallback;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.sip.message.Response;
import java.util.List;
import java.util.Map;
@Service
@Slf4j
public class GbChannelControlServiceImpl implements IGbChannelControlService {
@Autowired
private Map<String, ISourcePTZService> sourcePTZServiceMap;
@Override
public void ptz(CommonGBChannel channel, FrontEndControlCodeForPTZ frontEndControlCode, ErrorCallback<String> callback) {
log.info("[通用通道] 云台控制, 通道: {}", channel.getGbId());
log.info("[通用通道] 云台控制, 类型: {} 编号:{}", channel.getDataType(), channel.getGbDeviceId());
Integer dataType = channel.getDataType();
ISourcePTZService sourcePTZService = sourcePTZServiceMap.get(ChannelDataType.PTZ_SERVICE + dataType);
if (sourcePTZService == null) {
// 通道数据异常
log.error("[点播通用通道] 类型: {} 不支持云台控制", dataType);
throw new PlayException(Response.BUSY_HERE, "channel not support");
}
sourcePTZService.ptz(channel, frontEndControlCode, callback);
}
@Override
public void preset(CommonGBChannel channel, FrontEndControlCodeForPTZ frontEndControlCode, ErrorCallback<String> callback) {
log.info("[通用通道] 预置位, 通道: {}", channel.getGbId());
public void preset(CommonGBChannel channel, FrontEndControlCodeForPreset frontEndControlCode, ErrorCallback<String> callback) {
log.info("[通用通道] 预置位控制, 类型: {} 编号:{}", channel.getDataType(), channel.getGbDeviceId());
Integer dataType = channel.getDataType();
ISourcePTZService sourcePTZService = sourcePTZServiceMap.get(ChannelDataType.PTZ_SERVICE + dataType);
if (sourcePTZService == null) {
// 通道数据异常
log.error("[点播通用通道] 类型: {} 不支持预置位控制", dataType);
throw new PlayException(Response.BUSY_HERE, "channel not support");
}
sourcePTZService.preset(channel, frontEndControlCode, callback);
}
@Override
public void fi(CommonGBChannel channel, FrontEndControlCodeForPTZ frontEndControlCode, ErrorCallback<String> callback) {
log.info("[通用通道] FI指令 通道: {}", channel.getGbId());
public void fi(CommonGBChannel channel, FrontEndControlCodeForFI frontEndControlCode, ErrorCallback<String> callback) {
log.info("[通用通道] FI指令 类型: {} 编号:{}", channel.getDataType(), channel.getGbDeviceId());
Integer dataType = channel.getDataType();
ISourcePTZService sourcePTZService = sourcePTZServiceMap.get(ChannelDataType.PTZ_SERVICE + dataType);
if (sourcePTZService == null) {
// 通道数据异常
log.error("[点播通用通道] 类型: {} 不支持FI指令", dataType);
throw new PlayException(Response.BUSY_HERE, "channel not support");
}
sourcePTZService.fi(channel, frontEndControlCode, callback);
}
@Override
public void tour(CommonGBChannel channel, FrontEndControlCodeForPTZ frontEndControlCode, ErrorCallback<String> callback) {
public void tour(CommonGBChannel channel, FrontEndControlCodeForTour frontEndControlCode, ErrorCallback<String> callback) {
log.info("[通用通道] 巡航指令, 类型: {} 编号:{}", channel.getDataType(), channel.getGbDeviceId());
Integer dataType = channel.getDataType();
ISourcePTZService sourcePTZService = sourcePTZServiceMap.get(ChannelDataType.PTZ_SERVICE + dataType);
if (sourcePTZService == null) {
// 通道数据异常
log.error("[点播通用通道] 类型: {} 不支持巡航指令", dataType);
throw new PlayException(Response.BUSY_HERE, "channel not support");
}
sourcePTZService.tour(channel, frontEndControlCode, callback);
}
@Override
public void scan(CommonGBChannel channel, FrontEndControlCodeForPTZ frontEndControlCode, ErrorCallback<String> callback) {
public void scan(CommonGBChannel channel, FrontEndControlCodeForScan frontEndControlCode, ErrorCallback<String> callback) {
log.info("[通用通道] 扫描指令, 类型: {} 编号:{}", channel.getDataType(), channel.getGbDeviceId());
Integer dataType = channel.getDataType();
ISourcePTZService sourcePTZService = sourcePTZServiceMap.get(ChannelDataType.PTZ_SERVICE + dataType);
if (sourcePTZService == null) {
// 通道数据异常
log.error("[点播通用通道] 类型: {} 不支持扫描指令", dataType);
throw new PlayException(Response.BUSY_HERE, "channel not support");
}
sourcePTZService.scan(channel, frontEndControlCode, callback);
}
@Override
public void auxiliary(CommonGBChannel channel, FrontEndControlCodeForPTZ frontEndControlCode, ErrorCallback<String> callback) {
public void auxiliary(CommonGBChannel channel, FrontEndControlCodeForAuxiliary frontEndControlCode, ErrorCallback<String> callback) {
log.info("[通用通道] 辅助开关控制指令, 类型: {} 编号:{}", channel.getDataType(), channel.getGbDeviceId());
Integer dataType = channel.getDataType();
ISourcePTZService sourcePTZService = sourcePTZServiceMap.get(ChannelDataType.PTZ_SERVICE + dataType);
if (sourcePTZService == null) {
// 通道数据异常
log.error("[点播通用通道] 类型: {} 不支持辅助开关控制指令", dataType);
throw new PlayException(Response.BUSY_HERE, "channel not support");
}
sourcePTZService.auxiliary(channel, frontEndControlCode, callback);
}
@Override
public void wiper(CommonGBChannel channel, FrontEndControlCodeForWiper frontEndControlCode, ErrorCallback<String> callback) {
log.info("[通用通道] 雨刷控制, 类型: {} 编号:{}", channel.getDataType(), channel.getGbDeviceId());
Integer dataType = channel.getDataType();
ISourcePTZService sourcePTZService = sourcePTZServiceMap.get(ChannelDataType.PTZ_SERVICE + dataType);
if (sourcePTZService == null) {
// 通道数据异常
log.error("[点播通用通道] 类型: {} 不支持雨刷控制", dataType);
throw new PlayException(Response.BUSY_HERE, "channel not support");
}
sourcePTZService.wiper(channel, frontEndControlCode, callback);
}
@Override
public void queryPreset(CommonGBChannel channel, ErrorCallback<List<Preset>> callback) {
log.info("[通用通道] 预置位查询, 类型: {} 编号:{}", channel.getDataType(), channel.getGbDeviceId());
Integer dataType = channel.getDataType();
ISourcePTZService sourcePTZService = sourcePTZServiceMap.get(ChannelDataType.PTZ_SERVICE + dataType);
if (sourcePTZService == null) {
// 通道数据异常
log.error("[点播通用通道] 类型: {} 不支持预置位查询", dataType);
throw new PlayException(Response.BUSY_HERE, "channel not support");
}
sourcePTZService.queryPreset(channel, callback);
}
}

View File

@ -2,95 +2,63 @@ package com.genersoft.iot.vmp.gb28181.service.impl;
import com.genersoft.iot.vmp.common.InviteSessionType;
import com.genersoft.iot.vmp.common.StreamInfo;
import com.genersoft.iot.vmp.conf.exception.ControllerException;
import com.genersoft.iot.vmp.conf.exception.ServiceException;
import com.genersoft.iot.vmp.gb28181.bean.*;
import com.genersoft.iot.vmp.common.enums.ChannelDataType;
import com.genersoft.iot.vmp.conf.UserSetting;
import com.genersoft.iot.vmp.gb28181.bean.CommonGBChannel;
import com.genersoft.iot.vmp.gb28181.bean.Platform;
import com.genersoft.iot.vmp.gb28181.bean.PlayException;
import com.genersoft.iot.vmp.gb28181.bean.*;
import com.genersoft.iot.vmp.gb28181.dao.CommonGBChannelMapper;
import com.genersoft.iot.vmp.gb28181.service.*;
import com.genersoft.iot.vmp.gb28181.service.IGbChannelPlayService;
import com.genersoft.iot.vmp.gb28181.service.IPlayService;
import com.genersoft.iot.vmp.jt1078.service.Ijt1078PlayService;
import com.genersoft.iot.vmp.service.bean.ErrorCallback;
import com.genersoft.iot.vmp.streamProxy.service.IStreamProxyPlayService;
import com.genersoft.iot.vmp.streamPush.service.IStreamPushPlayService;
import com.genersoft.iot.vmp.service.bean.InviteErrorCode;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.sip.InvalidArgumentException;
import javax.sip.SipException;
import javax.sip.message.Response;
import java.text.ParseException;
import java.util.List;
import java.util.Map;
@Slf4j
@Service
public class GbChannelPlayServiceImpl implements IGbChannelPlayService {
@Autowired
private IPlayService deviceChannelPlayService;
@Autowired
private IStreamProxyPlayService streamProxyPlayService;
@Autowired
private IStreamPushPlayService streamPushPlayService;
@Autowired
private UserSetting userSetting;
@Autowired
private CommonGBChannelMapper channelMapper;
@Autowired
private Map<String, ISourcePlayService> sourcePlayServiceMap;
@Autowired
private Ijt1078PlayService jt1078PlayService;
@Autowired
private Map<String, ISourcePlaybackService> sourcePlaybackServiceMap;
@Autowired
private Map<String, ISourceDownloadService> sourceDownloadServiceMap;
@Override
public void start(CommonGBChannel channel, InviteMessageInfo inviteInfo, Platform platform, ErrorCallback<StreamInfo> callback) {
public void startInvite(CommonGBChannel channel, InviteMessageInfo inviteInfo, Platform platform, ErrorCallback<StreamInfo> callback) {
if (channel == null || inviteInfo == null || callback == null || channel.getDataType() == null) {
log.warn("[通用通道点播] 参数异常, channel: {}, inviteInfo: {}, callback: {}", channel != null, inviteInfo != null, callback != null);
throw new PlayException(Response.SERVER_INTERNAL_ERROR, "server internal error");
}
log.info("[点播通用通道] 类型:{} 通道: {}({})", inviteInfo.getSessionName(), channel.getGbName(), channel.getGbDeviceId());
if ("Play".equalsIgnoreCase(inviteInfo.getSessionName())) {
play(channel, platform, userSetting.getRecordSip(), callback);
}else if ("Playback".equals(inviteInfo.getSessionName())) {
if (channel.getDataType() == ChannelDataType.GB28181.value) {
// 国标通道
playbackGbDeviceChannel(channel, inviteInfo.getStartTime(), inviteInfo.getStopTime(), callback);
} else if (channel.getDataType() == ChannelDataType.STREAM_PROXY.value) {
// 拉流代理
log.warn("[回放通用通道] 不支持回放拉流代理的录像: {}({})", channel.getGbName(), channel.getGbDeviceId());
throw new PlayException(Response.FORBIDDEN, "forbidden");
} else if (channel.getDataType() == ChannelDataType.STREAM_PUSH.value) {
// 推流
log.warn("[回放通用通道] 不支持回放推流的录像: {}({})", channel.getGbName(), channel.getGbDeviceId());
throw new PlayException(Response.FORBIDDEN, "forbidden");
} else {
// 通道数据异常
log.error("[回放通用通道] 通道数据异常,无法识别通道来源: {}({})", channel.getGbName(), channel.getGbDeviceId());
throw new PlayException(Response.SERVER_INTERNAL_ERROR, "server internal error");
}
playback(channel, inviteInfo.getStartTime(), inviteInfo.getStopTime(), callback);
}else if ("Download".equals(inviteInfo.getSessionName())) {
if (channel.getDataType() == ChannelDataType.GB28181.value) {
int downloadSpeed = 4;
try {
if (inviteInfo.getDownloadSpeed() != null){
downloadSpeed = Integer.parseInt(inviteInfo.getDownloadSpeed());
}
}catch (Exception ignored) {}
Integer downloadSpeed = Integer.parseInt(inviteInfo.getDownloadSpeed());
// 国标通道
downloadGbDeviceChannel(channel, inviteInfo.getStartTime(), inviteInfo.getStopTime(), downloadSpeed, callback);
} else if (channel.getDataType() == ChannelDataType.STREAM_PROXY.value) {
// 拉流代理
log.warn("[下载通用通道录像] 不支持下载拉流代理的录像: {}({})", channel.getGbName(), channel.getGbDeviceId());
throw new PlayException(Response.FORBIDDEN, "forbidden");
} else if (channel.getDataType() == ChannelDataType.STREAM_PUSH.value) {
// 推流
log.warn("[下载通用通道录像] 不支持下载推流的录像: {}({})", channel.getGbName(), channel.getGbDeviceId());
throw new PlayException(Response.FORBIDDEN, "forbidden");
} else {
// 通道数据异常
log.error("[回放通用通道] 通道数据异常,无法识别通道来源: {}({})", channel.getGbName(), channel.getGbDeviceId());
throw new PlayException(Response.SERVER_INTERNAL_ERROR, "server internal error");
}
download(channel, inviteInfo.getStartTime(), inviteInfo.getStopTime(), downloadSpeed, callback);
}else {
// 不支持的点播方式
log.error("[点播通用通道] 不支持的点播方式:{} {}({})", inviteInfo.getSessionName(), channel.getGbName(), channel.getGbDeviceId());
@ -99,149 +67,173 @@ public class GbChannelPlayServiceImpl implements IGbChannelPlayService {
}
@Override
public void stopPlay(InviteSessionType type, CommonGBChannel channel, String stream) {
if (channel.getDataType() == ChannelDataType.GB28181.value) {
// 国标通道
stopPlayDeviceChannel(type, channel, stream);
} else if (channel.getDataType() == ChannelDataType.STREAM_PROXY.value) {
// 拉流代理
stopPlayProxy(channel);
} else if (channel.getDataType() == ChannelDataType.STREAM_PUSH.value) {
// 推流
stopPlayPush(channel);
} else {
public void stopInvite(InviteSessionType type, CommonGBChannel channel, String stream) {
switch (type) {
case PLAY:
stopPlay(channel, stream);
break;
case PLAYBACK:
stopPlayback(channel, stream);
break;
case DOWNLOAD:
stopDownload(channel, stream);
break;
default:
// 通道数据异常
log.error("[点播通用通道] 通道数据异常,无法识别通道来源: {}({})", channel.getGbName(), channel.getGbDeviceId());
throw new PlayException(Response.SERVER_INTERNAL_ERROR, "server internal error");
log.error("[点播通用通道] 类型编号: {} 不支持此类型请求", type);
throw new PlayException(Response.BUSY_HERE, "channel not support");
}
}
@Override
public void play(CommonGBChannel channel, Platform platform, Boolean record, ErrorCallback<StreamInfo> callback) {
if (channel.getDataType() == ChannelDataType.GB28181.value) {
// 国标通道
playGbDeviceChannel(channel, record, callback);
} else if (channel.getDataType() == ChannelDataType.STREAM_PROXY.value) {
// 拉流代理
playProxy(channel, record, callback);
} else if (channel.getDataType() == ChannelDataType.STREAM_PUSH.value) {
if (platform != null) {
// 推流
playPush(channel, platform.getServerGBId(), platform.getName(), callback);
}else {
// 推流
playPush(channel, null, null, callback);
}
} else {
log.info("[通用通道] 播放, 类型: {} 编号:{}", channel.getDataType(), channel.getGbDeviceId());
Integer dataType = channel.getDataType();
ISourcePlayService sourceChannelPlayService = sourcePlayServiceMap.get(ChannelDataType.PLAY_SERVICE + dataType);
if (sourceChannelPlayService == null) {
// 通道数据异常
log.error("[点播通用通道] 通道数据异常,无法识别通道来源: {}({})", channel.getGbName(), channel.getGbDeviceId());
throw new PlayException(Response.SERVER_INTERNAL_ERROR, "server internal error");
log.error("[点播通用通道] 类型编号: {} 不支持实时流预览", dataType);
throw new PlayException(Response.BUSY_HERE, "channel not support");
}
sourceChannelPlayService.play(channel, platform, record, (code, msg, data) -> {
if (code == InviteErrorCode.SUCCESS.getCode()) {
// 将流ID记录到数据库
if (channel.getDataType() != ChannelDataType.GB28181) {
channelMapper.updateStream(channel.getGbId(), data.getStream());
}
}
callback.run(code, msg, data);
});
}
@Override
public void playback(CommonGBChannel channel, Long startTime, Long stopTime, ErrorCallback<StreamInfo> callback) {
log.info("[通用通道] 回放, 类型: {} 编号:{}", channel.getDataType(), channel.getGbDeviceId());
Integer dataType = channel.getDataType();
ISourcePlaybackService playbackService = sourcePlaybackServiceMap.get(ChannelDataType.PLAYBACK_SERVICE + dataType);
if (playbackService == null) {
// 通道数据异常
log.error("[点播通用通道] 类型编号: {} 不支持回放", dataType);
throw new PlayException(Response.BUSY_HERE, "channel not support");
}
playbackService.playback(channel, startTime, stopTime, callback);
}
@Override
public void playGbDeviceChannel(CommonGBChannel channel, Boolean record, ErrorCallback<StreamInfo> callback){
// 国标通道
try {
deviceChannelPlayService.play(channel, record, callback);
} catch (PlayException e) {
callback.run(e.getCode(), e.getMsg(), null);
} catch (ControllerException e) {
log.error("[点播失败] {}({}), {}", channel.getGbName(), channel.getGbDeviceId(), e.getMsg());
callback.run(Response.BUSY_HERE, "busy here", null);
} catch (Exception e) {
log.error("[点播失败] {}({})", channel.getGbName(), channel.getGbDeviceId(), e);
callback.run(Response.BUSY_HERE, "busy here", null);
}
}
@Override
public void stopPlayDeviceChannel(InviteSessionType type, CommonGBChannel channel, String stream) {
// 国标通道
try {
deviceChannelPlayService.stop(type, channel, stream);
} catch (Exception e) {
log.error("[停止点播失败] {}({})", channel.getGbName(), channel.getGbDeviceId(), e);
}
}
@Override
public void playProxy(CommonGBChannel channel, Boolean record, ErrorCallback<StreamInfo> callback){
// 拉流代理通道
try {
streamProxyPlayService.start(channel.getDataDeviceId(), record, callback);
}catch (Exception e) {
callback.run(Response.BUSY_HERE, "busy here", null);
}
}
@Override
public void stopPlayProxy(CommonGBChannel channel) {
// 拉流代理通道
try {
streamProxyPlayService.stop(channel.getDataDeviceId());
}catch (Exception e) {
log.error("[停止点播失败] {}({})", channel.getGbName(), channel.getGbDeviceId(), e);
}
}
@Override
public void playPush(CommonGBChannel channel, String platformDeviceId, String platformName, ErrorCallback<StreamInfo> callback){
// 推流
try {
streamPushPlayService.start(channel.getDataDeviceId(), callback, platformDeviceId, platformName);
}catch (PlayException e) {
callback.run(e.getCode(), e.getMsg(), null);
}catch (Exception e) {
log.error("[点播推流通道失败] 通道: {}({})", channel.getGbName(), channel.getGbDeviceId(), e);
callback.run(Response.BUSY_HERE, "busy here", null);
}
}
@Override
public void stopPlayPush(CommonGBChannel channel) {
// 推流
try {
streamPushPlayService.stop(channel.getDataDeviceId());
}catch (Exception e) {
log.error("[停止点播失败] {}({})", channel.getGbName(), channel.getGbDeviceId(), e);
}
}
private void playbackGbDeviceChannel(CommonGBChannel channel, Long startTime, Long stopTime, ErrorCallback<StreamInfo> callback){
try {
deviceChannelPlayService.playBack(channel, startTime, stopTime, callback);
} catch (PlayException e) {
callback.run(e.getCode(), e.getMsg(), null);
} catch (Exception e) {
callback.run(Response.BUSY_HERE, "busy here", null);
}
}
@Override
public void pauseRtp(String streamId) {
try {
deviceChannelPlayService.pauseRtp(streamId);
} catch (ServiceException | InvalidArgumentException | ParseException | SipException ignore) {}
}
@Override
public void resumeRtp(String streamId) {
try {
deviceChannelPlayService.resumeRtp(streamId);
} catch (ServiceException | InvalidArgumentException | ParseException | SipException ignore) {}
}
private void downloadGbDeviceChannel(CommonGBChannel channel, Long startTime, Long stopTime, Integer downloadSpeed,
public void download(CommonGBChannel channel, Long startTime, Long stopTime, Integer downloadSpeed,
ErrorCallback<StreamInfo> callback){
try {
deviceChannelPlayService.download(channel, startTime, stopTime, downloadSpeed, callback);
} catch (PlayException e) {
callback.run(e.getCode(), e.getMsg(), null);
} catch (Exception e) {
callback.run(Response.BUSY_HERE, "busy here", null);
log.info("[通用通道] 录像下载, 类型: {} 编号:{}", channel.getDataType(), channel.getGbDeviceId());
Integer dataType = channel.getDataType();
ISourceDownloadService downloadService = sourceDownloadServiceMap.get(ChannelDataType.DOWNLOAD_SERVICE + dataType);
if (downloadService == null) {
// 通道数据异常
log.error("[点播通用通道] 类型编号: {} 不支持录像下载", dataType);
throw new PlayException(Response.BUSY_HERE, "channel not support");
}
downloadService.download(channel, startTime, stopTime, downloadSpeed, callback);
}
@Override
public void stopPlay(CommonGBChannel channel, String stream) {
Integer dataType = channel.getDataType();
ISourcePlayService sourceChannelPlayService = sourcePlayServiceMap.get(ChannelDataType.PLAY_SERVICE + dataType);
if (sourceChannelPlayService == null) {
// 通道数据异常
log.error("[点播通用通道] 类型编号: {} 不支持停止实时流", dataType);
throw new PlayException(Response.BUSY_HERE, "channel not support");
}
sourceChannelPlayService.stopPlay(channel, stream);
}
@Override
public void stopPlayback(CommonGBChannel channel, String stream) {
log.info("[通用通道] 停止回放, 类型: {} 编号:{}", channel.getDataType(), channel.getGbDeviceId());
Integer dataType = channel.getDataType();
ISourcePlaybackService playbackService = sourcePlaybackServiceMap.get(ChannelDataType.PLAYBACK_SERVICE + dataType);
if (playbackService == null) {
// 通道数据异常
log.error("[点播通用通道] 类型编号: {} 不支持回放", dataType);
throw new PlayException(Response.BUSY_HERE, "channel not support");
}
playbackService.stopPlayback(channel, stream);
}
@Override
public void stopDownload(CommonGBChannel channel, String stream) {
log.info("[通用通道] 停止录像下载, 类型: {} 编号:{} stream: {}", channel.getDataType(), channel.getGbDeviceId(), stream);
Integer dataType = channel.getDataType();
ISourceDownloadService downloadService = sourceDownloadServiceMap.get(ChannelDataType.DOWNLOAD_SERVICE + dataType);
if (downloadService == null) {
// 通道数据异常
log.error("[点播通用通道] 类型编号: {} 不支持录像下载", dataType);
throw new PlayException(Response.BUSY_HERE, "channel not support");
}
downloadService.stopDownload(channel, stream);
}
@Override
public void playbackPause(CommonGBChannel channel, String stream) {
log.info("[通用通道] 回放暂停, 类型: {} 编号:{} stream{}", channel.getDataType(), channel.getGbDeviceId(), stream);
Integer dataType = channel.getDataType();
ISourcePlaybackService playbackService = sourcePlaybackServiceMap.get(ChannelDataType.PLAYBACK_SERVICE + dataType);
if (playbackService == null) {
// 通道数据异常
log.error("[点播通用通道] 类型编号: {} 不支持回放暂停", dataType);
throw new PlayException(Response.BUSY_HERE, "channel not support");
}
playbackService.playbackPause(channel, stream);
}
@Override
public void playbackResume(CommonGBChannel channel, String stream) {
log.info("[通用通道] 回放暂停恢复, 类型: {} 编号:{} stream{}", channel.getDataType(), channel.getGbDeviceId(), stream);
Integer dataType = channel.getDataType();
ISourcePlaybackService playbackService = sourcePlaybackServiceMap.get(ChannelDataType.PLAYBACK_SERVICE + dataType);
if (playbackService == null) {
// 通道数据异常
log.error("[点播通用通道] 类型编号: {} 不支持回放暂停恢复", dataType);
throw new PlayException(Response.BUSY_HERE, "channel not support");
}
playbackService.playbackResume(channel, stream);
}
@Override
public void playbackSeek(CommonGBChannel channel, String stream, long seekTime) {
log.info("[通用通道] 回放拖动播放, 类型: {} 编号:{} stream{}", channel.getDataType(), channel.getGbDeviceId(), stream);
Integer dataType = channel.getDataType();
ISourcePlaybackService playbackService = sourcePlaybackServiceMap.get(ChannelDataType.PLAYBACK_SERVICE + dataType);
if (playbackService == null) {
// 通道数据异常
log.error("[点播通用通道] 类型编号: {} 不支持回放暂停恢复", dataType);
throw new PlayException(Response.BUSY_HERE, "channel not support");
}
playbackService.playbackSeek(channel, stream, seekTime);
}
@Override
public void playbackSpeed(CommonGBChannel channel, String stream, Double speed) {
log.info("[通用通道] 回放倍速播放, 类型: {} 编号:{} stream{}", channel.getDataType(), channel.getGbDeviceId(), stream);
Integer dataType = channel.getDataType();
ISourcePlaybackService playbackService = sourcePlaybackServiceMap.get(ChannelDataType.PLAYBACK_SERVICE + dataType);
if (playbackService == null) {
// 通道数据异常
log.error("[点播通用通道] 类型编号: {} 不支持回放暂停恢复", dataType);
throw new PlayException(Response.BUSY_HERE, "channel not support");
}
playbackService.playbackSpeed(channel, stream, speed);
}
@Override
public void queryRecord(CommonGBChannel channel, String startTime, String endTime, ErrorCallback<List<CommonRecordInfo>> callback) {
log.info("[通用通道] 录像查询, 类型: {} 编号:{}", channel.getDataType(), channel.getGbDeviceId());
Integer dataType = channel.getDataType();
ISourcePlaybackService playbackService = sourcePlaybackServiceMap.get(ChannelDataType.PLAYBACK_SERVICE + dataType);
if (playbackService == null) {
// 通道数据异常
log.error("[点播通用通道] 类型编号: {} 不支持回放暂停恢复", dataType);
throw new PlayException(Response.BUSY_HERE, "channel not support");
}
playbackService.queryRecord(channel, startTime, endTime, callback);
}
}

View File

@ -12,7 +12,6 @@ import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent;
import com.genersoft.iot.vmp.gb28181.service.IDeviceChannelService;
import com.genersoft.iot.vmp.gb28181.service.IGbChannelService;
import com.genersoft.iot.vmp.gb28181.service.IPlatformChannelService;
import com.genersoft.iot.vmp.service.bean.ErrorCallback;
import com.genersoft.iot.vmp.service.bean.GPSMsgInfo;
import com.genersoft.iot.vmp.streamPush.bean.StreamPush;
import com.genersoft.iot.vmp.utils.DateUtil;
@ -26,7 +25,6 @@ import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import javax.sip.message.Response;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@ -366,12 +364,12 @@ public class GbChannelServiceImpl implements IGbChannelService {
log.warn("[重置国标通道] 未找到对应Id的通道: id: {}", id);
throw new ControllerException(ErrorCode.ERROR400);
}
if (channel.getDataType() != ChannelDataType.GB28181.value) {
if (channel.getDataType() != ChannelDataType.GB28181) {
log.warn("[重置国标通道] 非国标下级通道无法重置: id: {}", id);
throw new ControllerException(ErrorCode.ERROR100.getCode(), "非国标下级通道无法重置");
}
// 这个多加一个参数,为了防止将非国标的通道通过此方法清空内容,导致意外发生
commonGBChannelMapper.reset(id, ChannelDataType.GB28181.value, channel.getDataDeviceId(), DateUtil.getNow());
commonGBChannelMapper.reset(id, ChannelDataType.GB28181, channel.getDataDeviceId(), DateUtil.getNow());
CommonGBChannel channelNew = getOne(id);
// 发送通过更新通知
try {
@ -494,7 +492,7 @@ public class GbChannelServiceImpl implements IGbChannelService {
@Override
public void addChannelToRegionByGbDevice(String civilCode, List<Integer> deviceIds) {
List<CommonGBChannel> channelList = commonGBChannelMapper.queryByGbDeviceIds(ChannelDataType.GB28181.value, deviceIds);
List<CommonGBChannel> channelList = commonGBChannelMapper.queryByGbDeviceIds(ChannelDataType.GB28181, deviceIds);
if (channelList.isEmpty()) {
throw new ControllerException(ErrorCode.ERROR100.getCode(), "所有通道Id不存在");
}
@ -515,7 +513,7 @@ public class GbChannelServiceImpl implements IGbChannelService {
@Override
public void deleteChannelToRegionByGbDevice(List<Integer> deviceIds) {
List<CommonGBChannel> channelList = commonGBChannelMapper.queryByGbDeviceIds(ChannelDataType.GB28181.value, deviceIds);
List<CommonGBChannel> channelList = commonGBChannelMapper.queryByGbDeviceIds(ChannelDataType.GB28181, deviceIds);
if (channelList.isEmpty()) {
throw new ControllerException(ErrorCode.ERROR100.getCode(), "所有通道Id不存在");
}
@ -632,7 +630,7 @@ public class GbChannelServiceImpl implements IGbChannelService {
@Override
@Transactional
public void addChannelToGroupByGbDevice(String parentId, String businessGroup, List<Integer> deviceIds) {
List<CommonGBChannel> channelList = commonGBChannelMapper.queryByGbDeviceIds(ChannelDataType.GB28181.value, deviceIds);
List<CommonGBChannel> channelList = commonGBChannelMapper.queryByGbDeviceIds(ChannelDataType.GB28181, deviceIds);
if (channelList.isEmpty()) {
throw new ControllerException(ErrorCode.ERROR100.getCode(), "所有通道Id不存在");
}
@ -660,7 +658,7 @@ public class GbChannelServiceImpl implements IGbChannelService {
@Override
public void deleteChannelToGroupByGbDevice(List<Integer> deviceIds) {
List<CommonGBChannel> channelList = commonGBChannelMapper.queryByGbDeviceIds(ChannelDataType.GB28181.value, deviceIds);
List<CommonGBChannel> channelList = commonGBChannelMapper.queryByGbDeviceIds(ChannelDataType.GB28181, deviceIds);
if (channelList.isEmpty()) {
throw new ControllerException(ErrorCode.ERROR100.getCode(), "所有通道Id不存在");
}
@ -702,7 +700,7 @@ public class GbChannelServiceImpl implements IGbChannelService {
@Override
public List<CommonGBChannel> queryListByStreamPushList(List<StreamPush> streamPushList) {
return commonGBChannelMapper.queryListByStreamPushList(ChannelDataType.STREAM_PUSH.value, streamPushList);
return commonGBChannelMapper.queryListByStreamPushList(ChannelDataType.STREAM_PUSH, streamPushList);
}
@Override
@ -717,25 +715,6 @@ public class GbChannelServiceImpl implements IGbChannelService {
return new PageInfo<>(all);
}
@Override
public void queryRecordInfo(CommonGBChannel channel, String startTime, String endTime, ErrorCallback<RecordInfo> callback) {
if (channel.getDataType() == ChannelDataType.GB28181.value) {
deviceChannelService.queryRecordInfo(channel, startTime, endTime, callback);
} else if (channel.getDataType() == ChannelDataType.STREAM_PROXY.value) {
// 拉流代理
log.warn("[下载通用通道录像] 不支持下载拉流代理的录像: {}({})", channel.getGbName(), channel.getGbDeviceId());
throw new PlayException(Response.FORBIDDEN, "forbidden");
} else if (channel.getDataType() == ChannelDataType.STREAM_PUSH.value) {
// 推流
log.warn("[下载通用通道录像] 不支持下载推流的录像: {}({})", channel.getGbName(), channel.getGbDeviceId());
throw new PlayException(Response.FORBIDDEN, "forbidden");
} else {
// 通道数据异常
log.error("[回放通用通道] 通道数据异常,无法识别通道来源: {}({})", channel.getGbName(), channel.getGbDeviceId());
throw new PlayException(Response.SERVER_INTERNAL_ERROR, "server internal error");
}
}
@Override
public PageInfo<CommonGBChannel> queryListByCivilCodeForUnusual(int page, int count, String query, Boolean online, Integer channelType) {
PageHelper.startPage(page, count);
@ -790,4 +769,26 @@ public class GbChannelServiceImpl implements IGbChannelService {
}
commonGBChannelMapper.updateGpsByDeviceId(gpsMsgInfoList);
}
@Transactional
@Override
public void updateGPS(List<CommonGBChannel> commonGBChannels) {
int limitCount = 1000;
if (commonGBChannels.size() > limitCount) {
for (int i = 0; i < commonGBChannels.size(); i += limitCount) {
int toIndex = i + limitCount;
if (i + limitCount > commonGBChannels.size()) {
toIndex = commonGBChannels.size();
}
commonGBChannelMapper.updateGps(commonGBChannels.subList(i, toIndex));
}
} else {
commonGBChannelMapper.updateGps(commonGBChannels);
}
}
@Override
public List<CommonGBChannel> queryListForMap(String query, Boolean online, Boolean hasRecordPlan, Integer channelType) {
return commonGBChannelMapper.queryList(query, online, hasRecordPlan, channelType);
}
}

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