Commit 8b0ff3767b23f9479a0b3ebe8e343ed6470bd194
Merge branch 'wvp-28181-2.0'
# Conflicts: # sql/update.sql # src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java # src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java # src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRTPServerFactory.java # src/main/java/com/genersoft/iot/vmp/service/impl/MediaServerServiceImpl.java # src/main/java/com/genersoft/iot/vmp/service/impl/MediaServiceImpl.java # src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java
Showing
204 changed files
with
4644 additions
and
1894 deletions
README.md
| 1 | 1 |  |
| 2 | -# 寮绠卞嵆鐢ㄧ殑鐨8181鍗忚瑙嗛骞冲彴 | |
| 2 | +# 寮绠卞嵆鐢ㄧ殑28181鍗忚瑙嗛骞冲彴 | |
| 3 | 3 | |
| 4 | 4 | [](https://travis-ci.org/xia-chu/ZLMediaKit) |
| 5 | 5 | [](https://github.com/xia-chu/ZLMediaKit/blob/master/LICENSE) |
| ... | ... | @@ -25,7 +25,7 @@ WEB VIDEO PLATFORM鏄竴涓熀浜嶨B28181-2016鏍囧噯瀹炵幇鐨勫紑绠卞嵆鐢ㄧ殑缃戠 |
| 25 | 25 | 鏃ㄥ湪鎵撻犱竴涓槗閰嶇疆,鏄撲娇鐢,渚夸簬缁存姢鐨8181鍥芥爣淇′护绯荤粺, 渚濇墭浼樼鐨勫紑婧愭祦濯掍綋鏈嶅姟妗嗘灦ZLMediaKit, 瀹炵幇涓涓畬鏁存槗鐢℅B28181骞冲彴. |
| 26 | 26 | |
| 27 | 27 | # 閮ㄧ讲鏂囨。 |
| 28 | -[https://github.com/648540858/wvp-GB28181-pro/wiki](https://github.com/648540858/wvp-GB28181-pro/wiki) | |
| 28 | +[doc.wvp-pro.cn](https://doc.wvp-pro.cn) | |
| 29 | 29 | |
| 30 | 30 | # gitee鍚屾浠撳簱 |
| 31 | 31 | https://gitee.com/pan648540858/wvp-GB28181-pro.git | ... | ... |
bootstrap.sh
100755 → 100644
doc/README.md
0 → 100644
| 1 | +# 介绍 | |
| 2 | + | |
| 3 | +> 开箱即用的28181协议视频平台 | |
| 4 | + | |
| 5 | +# 概述 | |
| 6 | +- WVP-PRO基于GB/T 28181-2016标准实现的流媒体平台,依托优秀的开源流媒体服务[ZLMediaKit](https://github.com/ZLMediaKit/ZLMediaKit),提供完善丰富的功能。 | |
| 7 | +- GB/T 28181-2016 中文标准名称是《公共安全视频监控联网系统信息传输、交换、控制技术要求》是监控领域的国家标准。大量应用于政府视频平台。 | |
| 8 | +- 通过28181协议你可以将IPC摄像头接入平台,可以观看也可以使用28181/rtsp/rtmp/flv等协议将视频流分发到其他平台。 | |
| 9 | + | |
| 10 | +# 特性 | |
| 11 | +- 实现标准的28181信令,兼容常见的品牌设备,比如海康、大华、宇视等品牌的IPC、NVR以及平台。 | |
| 12 | +- 支持将国标设备级联到其他国标平台,也支持将不支持国标的设备的图像或者直播推送到其他国标平台 | |
| 13 | +- 前端完善,自带完整前端页面,无需二次开发可直接部署使用。 | |
| 14 | +- 完全开源,且使用MIT许可协议。保留版权的情况下可以用于商业项目。 | |
| 15 | +- 支持多流媒体节点负载均衡。 | |
| 16 | + | |
| 17 | +# 我们实现了哪些国标功能 | |
| 18 | +**作为上级平台** | |
| 19 | +- [X] 注册 | |
| 20 | +- [X] 注销 | |
| 21 | +- [X] 实时视音频点播 | |
| 22 | +- [X] 设备控制 | |
| 23 | + - [X] 云台控制 | |
| 24 | + - [ ] 远程启动 | |
| 25 | + - [ ] 录像控制 | |
| 26 | + - [ ] 报警布防/撤防 | |
| 27 | + - [ ] 报警复位 | |
| 28 | + - [X] 强制关键帧 | |
| 29 | + - [ ] 拉框放大 | |
| 30 | + - [ ] 拉框缩小 | |
| 31 | + - [ ] 看守位控制 | |
| 32 | + - [ ] 设备配置 | |
| 33 | +- [X] 报警事件通知和分发 | |
| 34 | +- [X] 设备目录订阅 | |
| 35 | +- [X] 网络设备信息查询 | |
| 36 | + - [X] 设备目录查询 | |
| 37 | + - [X] 设备状态查询 | |
| 38 | + - [ ] 设备配置查询 | |
| 39 | + - [ ] 设备预置位查询 | |
| 40 | +- [X] 状态信息报送 | |
| 41 | +- [X] 设备视音频文件检索 | |
| 42 | +- [X] 历史视音频的回放 | |
| 43 | + - [X] 播放 | |
| 44 | + - [X] 暂停 | |
| 45 | + - [X] 进/退 | |
| 46 | + - [X] 停止 | |
| 47 | +- [X] 视音频文件下载 | |
| 48 | +- [X] 校时 | |
| 49 | +- [X] 订阅和通知 | |
| 50 | + - [X] 事件订阅 | |
| 51 | + - [X] 移动设备位置订阅 | |
| 52 | + - [X] 报警订阅 | |
| 53 | + - [X] 目录订阅 | |
| 54 | +- [ ] 语音广播 | |
| 55 | +- [ ] 语音对讲 | |
| 56 | + | |
| 57 | +**作为下级平台** | |
| 58 | +- [X] 注册 | |
| 59 | +- [X] 注销 | |
| 60 | +- [X] 实时视音频点播 | |
| 61 | +- [ ] 设备控制 | |
| 62 | + - [ ] 云台控制 | |
| 63 | + - [ ] 远程启动 | |
| 64 | + - [ ] 录像控制 | |
| 65 | + - [ ] 报警布防/撤防 | |
| 66 | + - [ ] 报警复位 | |
| 67 | + - [ ] 强制关键帧 | |
| 68 | + - [ ] 拉框放大 | |
| 69 | + - [ ] 拉框缩小 | |
| 70 | + - [ ] 看守位控制 | |
| 71 | + - [ ] 设备配置 | |
| 72 | +- [ ] 报警事件通知和分发 | |
| 73 | +- [X] 设备目录订阅 | |
| 74 | +- [X] 网络设备信息查询 | |
| 75 | + - [X] 设备目录查询 | |
| 76 | + - [X] 设备状态查询 | |
| 77 | + - [ ] 设备配置查询 | |
| 78 | + - [ ] 设备预置位查询 | |
| 79 | +- [X] 状态信息报送 | |
| 80 | +- [X] 设备视音频文件检索 | |
| 81 | +- [X] 历史视音频的回放 | |
| 82 | + - [X] 播放 | |
| 83 | + - [x] 暂停 | |
| 84 | + - [x] 进/退 | |
| 85 | + - [x] 停止 | |
| 86 | +- [ ] 视音频文件下载 | |
| 87 | +- [ ] ~~校时~~ | |
| 88 | +- [X] 订阅和通知 | |
| 89 | + - [X] 事件订阅 | |
| 90 | + - [X] 移动设备位置订阅 | |
| 91 | + - [ ] 报警订阅 | |
| 92 | + - [X] 目录订阅 | |
| 93 | +- [ ] 语音广播 | |
| 94 | +- [ ] 语音对讲 | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | +# 社区 | |
| 100 | +代码目前托管在GitHub和Gitee,Gitee目前作为加速仓库使用,不接受issue。 | |
| 101 | +GitHub: [https://github.com/648540858/wvp-GB28181-pro](https://github.com/648540858/wvp-GB28181-pro) | |
| 102 | +Gitee: [https://gitee.com/pan648540858/wvp-GB28181-pro](https://gitee.com/pan648540858/wvp-GB28181-pro) | |
| 0 | 103 | \ No newline at end of file | ... | ... |
doc/_content/ability/_media/cascade1.png
0 → 100644
37.4 KB
doc/_content/ability/_media/cascade2.png
0 → 100644
162 KB
doc/_content/ability/_media/cascade3.png
0 → 100644
129 KB
doc/_content/ability/_media/cascade4.png
0 → 100644
119 KB
doc/_content/ability/_media/img.png
0 → 100644
13.1 KB
doc/_content/ability/_media/img_1.png
0 → 100644
17.1 KB
doc/_content/ability/_media/img_10.png
0 → 100644
65.1 KB
doc/_content/ability/_media/img_11.png
0 → 100644
80.5 KB
doc/_content/ability/_media/img_12.png
0 → 100644
66.2 KB
doc/_content/ability/_media/img_13.png
0 → 100644
58.1 KB
doc/_content/ability/_media/img_14.png
0 → 100644
692 Bytes
doc/_content/ability/_media/img_15.png
0 → 100644
98.9 KB
doc/_content/ability/_media/img_16.png
0 → 100644
41.5 KB
doc/_content/ability/_media/img_17.png
0 → 100644
56.3 KB
doc/_content/ability/_media/img_18.png
0 → 100644
64.6 KB
doc/_content/ability/_media/img_2.png
0 → 100644
41.1 KB
doc/_content/ability/_media/img_3.png
0 → 100644
16.2 KB
doc/_content/ability/_media/img_4.png
0 → 100644
136 KB
doc/_content/ability/_media/img_5.png
0 → 100644
152 KB
doc/_content/ability/_media/img_6.png
0 → 100644
62.2 KB
doc/_content/ability/_media/img_7.png
0 → 100644
46.3 KB
doc/_content/ability/_media/img_8.png
0 → 100644
43.8 KB
doc/_content/ability/_media/img_9.png
0 → 100644
80.1 KB
doc/_content/ability/auto_play.md
0 → 100644
doc/_content/ability/cascade.md
0 → 100644
| 1 | +<!-- 国标级联的使用 --> | |
| 2 | +# 国标级联的使用 | |
| 3 | +国标28181不同平台之间支持两种连接方式,平级和上下级,WVP目前支持向上级级联。 | |
| 4 | +## 1 接入平台 | |
| 5 | +### 1.1 wvp-pro | |
| 6 | +#### 1.1.1 wvp-pro管理页面点击添加 | |
| 7 | +  | |
| 8 | +#### 1.1.2 填入wvp-pro上级平台信息 | |
| 9 | +  | |
| 10 | +  | |
| 11 | +#### 1.1.3 编辑wvp-pro上级设备信息,开启订阅 | |
| 12 | +  | |
| 13 | +### 1.2 大华平台 | |
| 14 | +### 1.3 海康平台 | |
| 15 | +### 1.4 liveGBS | |
| 16 | +#### 1.4.1. wvp-pro管理页面点击添加 | |
| 17 | +  | |
| 18 | +#### 1.4.2. 填入liveGBS平台信息 | |
| 19 | +  | |
| 20 | +  | |
| 21 | +#### 1.4.3. 编辑liveGBS设备信息,开启目录订阅 | |
| 22 | +  | |
| 23 | +#### 1.4.4. 编辑liveGBS设备信息,开启GPS订阅 | |
| 24 | +  | |
| 25 | + | |
| 26 | +## 2 添加目录与通道 | |
| 27 | +1. 级联平台添加目录信息 | |
| 28 | +  | |
| 29 | +2. 为目录添加通道 | |
| 30 | +  | |
| 31 | +3. 设置默认流目录 | |
| 32 | +如果需要后续自动生成的流信息都在某一个节点下,可以在对应节点右键设置为默认 | |
| 33 | +  | |
| 34 | + | ... | ... |
doc/_content/ability/cascade2.md
0 → 100644
| 1 | +<!-- 国标级联的使用 --> | |
| 2 | +# 国标级联的使用 | |
| 3 | +国标28181不同平台之间支持两种连接方式,平级和上下级,WVP目前支持向上级级联。 | |
| 4 | +## 添加上级平台 | |
| 5 | +在国标级联页面点击“添加”按钮,以推送到上级WVP为例子,参看[接入设备](./_content/ability/device.md) | |
| 6 | + | |
| 7 | +点击保存可以在上级的国标通道列表看到新增加的设备; | |
| 8 | +国标级联列表出现了级联的这个平台;同时状态显示为在线,如果状态为离线那么可能是你的服务信息配置有误或者网络不通。 | |
| 9 | +订阅信息列有三个图标,表示上级开启订阅,从左到右依次是:报警订阅,目录订阅,移动位置订阅。 | |
| 10 | +## 推送通道 | |
| 11 | +点击你要推送的平台的“选择通道”按钮。 | |
| 12 | + | |
| 13 | +- **页面结构** | |
| 14 | + - 左侧为目录结构 | |
| 15 | + 选择未分配,则右侧显示待分配的通道,可以点击“添加按钮”,在弹窗中选择要放置的位置,保存后即可添加通道成功 | |
| 16 | + 选择其他的目录可以看到已经分配在这个目录下的通道,可以对其进行删除后重新在未分配中去分配。 | |
| 17 | + - 右侧为数据展示以及操作 | |
| 18 | + 国标通道栏内为来自其他国标设备/平台的通道;直播流通道为来自推流/拉流代理的通道。 | |
| 0 | 19 | \ No newline at end of file | ... | ... |
doc/_content/ability/cloud_record.md
0 → 100644
| 1 | +<!-- 云端录像 --> | |
| 2 | +# 云端录像 | |
| 3 | +云端录像是对录制在zlm服务下的录像文件的管理,录像的文件路径默认在ZLM/www/record下,使用云端录像功能必须部署wvp-pro-assist,主要通过调用wvp-pro-assist的接口完成各种功能。 | |
| 4 | +如果你需要24小时的录像,目前有一个这种方案,可以参考[7*24不间断录像](./_content/ability/continuous_recording.md)。 | |
| 5 | +1. 云段录像支持录像文件的查看,播放(可能因为编码的原因导致无法播放); | |
| 6 | +2. 支持录像的下载; | |
| 7 | +3. 支持录像的合并下载; | |
| 8 | +功能没有太多特殊的地方就不一一介绍了,大家自行体验吧。 | ... | ... |
doc/_content/ability/continuous_recording.md
0 → 100644
| 1 | +<!-- 7*24不间断录像 --> | |
| 2 | +# 7*24不间断录像 | |
| 3 | + | |
| 4 | +目前如果要实现不间断录像如果只是关闭无人观看停止推流是不够的,设备可能经历断网,重启,都会导致录像的中断,目前给大家提供一种可用的临时方案。 | |
| 5 | + | |
| 6 | +**原理:** wvp支持使用流地址自动点播,即你拿到一个流地址直接去播放,即使设备处于未点播状态,wvp会自动帮你点播;ZLM | |
| 7 | +的拉流代理成功后会无限重试,只要流一恢复就可以拉起来,基于这两个原理。 | |
| 8 | +**方案如下:** | |
| 9 | +1. wvp的配置中user-settings->auto-apply-play设置为团true,开启自动点播; | |
| 10 | +2. 点击你要录像的通道,点击播放页面左下角的“更多地址”,点击rtsp,此时复制了rtsp地址到剪贴板; | |
| 11 | +3. 在拉流代理中添加一路流,地址填写你复制的地址,启用成功即可。 | |
| 12 | +**前提:** | |
| 13 | +1. wvp使用多端口收流,不然你无法得到一个固定的流地址,也就无法实现自动点播。 | |
| 14 | + | ... | ... |
doc/_content/ability/device.md
0 → 100644
| 1 | +<!-- 接入设备 --> | |
| 2 | +# 接入设备 | |
| 3 | +设备接入主要是需要在设备上配置28181上级也就是WVP-PRO的信息,只有信息一致的情况才可以注册成功。设备注册成功后打开WVP->国标设备,可以看到新增加的设备;[设备使用](./_content/ability/device_use.md), | |
| 4 | +主要有以下字段需要配置: | |
| 5 | + | |
| 6 | +- sip->ip | |
| 7 | +本机IP,不要使用127.0.0.1/0.0.0.0, 除非你对项目及其熟悉 | |
| 8 | + | |
| 9 | +- sip->port | |
| 10 | +28181服务监听的端口 | |
| 11 | + | |
| 12 | +- sip->domain | |
| 13 | +domain宜采用ID统一编码的前十位编码。 | |
| 14 | + | |
| 15 | +- sip->id | |
| 16 | +28181服务ID | |
| 17 | + | |
| 18 | +- sip->password | |
| 19 | +28181服务密码 | |
| 20 | + | |
| 21 | +- 配置信息在如下位置 | |
| 22 | + | |
| 23 | + | |
| 24 | +*** | |
| 25 | +## 大华摄像头 | |
| 26 | + | |
| 27 | +## 大华NVR | |
| 28 | + | |
| 29 | +## 艾科威视摄像头 | |
| 30 | + | |
| 31 | +## 水星摄像头 | |
| 32 | + | |
| 33 | +## 海康摄像头 | |
| 34 | + | |
| 35 | + | |
| 36 | +[设备使用](_content/ability/device_use.md) | ... | ... |
doc/_content/ability/device_use.md
0 → 100644
| 1 | +<!-- 设备使用 --> | |
| 2 | +# 设备使用 | |
| 3 | +### 更新设备通道 | |
| 4 | + 点击列表末尾的“刷新”按钮,可以看到一个圆形进度条,等进度结束提示成功后即可更新完成,如果通道数量有变化你可以看点击左上角的即可看到通道数量的变化;如果通道数量仍未0,那么可能时对方尚未推送通道给你。 | |
| 5 | +### 查看设备通道 | |
| 6 | + 点击列表末尾的“通道”按钮, | |
| 7 | +### 查看设备定位 | |
| 8 | + 点击列表末尾的“定位”按钮,即可跳转到地图页面看到设备的位置 | |
| 9 | +### 编辑设备在WVP中一些功能 | |
| 10 | +点击列表末尾的“编辑”按钮,即可在打开的弹窗中对设备功能进行修改 | |
| 11 | +- 设备名称 | |
| 12 | + 如何未能从设备里读取到设备名称或者需要自己重命名,那么可以修改此选项。 | |
| 13 | +- 字符集 | |
| 14 | + 修改读取设备数据时使用的字符集,默认为GB2312,但是GB2312收录的汉字不全,所以有时候回遇到乱码,可以修改为UTF-8来解决。 | |
| 15 | +- 地理坐标系 | |
| 16 | + 展示此设备定位信息时使用的设用什么坐标系来解析经纬度,一般不用修改,如果遇到定位不准,可以修改尝试修改此选项解决。 | |
| 17 | +- 目录结构 | |
| 18 | + 展示设备的通道信息时,使用设备作为树形结构的依据,国标28181定义了两种树形结构,详情查看[国标28181的树形结构](./_content/theory/channel_tree.md); | |
| 19 | +- 目录订阅 | |
| 20 | + 填写订阅周期即可对设备开启目录订阅,设备如果支持目录订阅那么设备在通道信息发生变化时就会通知WVP哪些通道发生了那些变化,包括通道增加/删除/更新/上线/下线/视频丢失/故障。0为取消订阅。 | |
| 21 | + 一般NVR和平台对接可以开启此选项,直接接摄像机开启此选项意义不大。 | |
| 22 | +- 移动位置订阅 | |
| 23 | + 对设备开启移动位置订阅,设备如果支持目录订阅那么设备位置发生变化时会通知到WVP,一般执法记录仪可以开启此选项,对固定位置的设备意义不大。 | |
| 24 | +- SSRC校验 | |
| 25 | + 为了解决部分设备出现的串流问题,可以打开此选项。ZLM会严格按照给定的ssrc处理视频流。部分设备流信息不标准,开启可能导致无法点播。 | |
| 26 | +### 删除设备 | |
| 27 | + 可以删除WVP中的设备信息,如果设备28181配置未更改,那么设备在下一次注册后仍然会注册上来。 | |
| 28 | +### 点播视频 | |
| 29 | + 进入通道列表后,点击列表末尾的“播放”按钮,稍等即可弹出播放页面 | |
| 30 | +### 设备录像 | |
| 31 | + 进入通道列表后,点击列表末尾的“设备录像”按钮,也可以在播放页面点击录像查询进入录像查看页面,选择要查看的日期即可对录像进行播放和下载。 | |
| 32 | +### 云台控制 | |
| 33 | + 可以对支持云台功能的设备进行上下左右的转动以及拉近拉远的操作。 | |
| 34 | +### 获取视频的播放器地址 | |
| 35 | + 视频点播成功后在实时视频页面,点击“更多地址”可以看到所有的播放地址,地址是否可以播放与你是否完整编译启用zlm功能有关,更与网络有关。 | |
| 0 | 36 | \ No newline at end of file | ... | ... |
doc/_content/ability/gis.md
0 → 100644
| 1 | +<!-- 电子地图 --> | |
| 2 | +# 电子地图 | |
| 3 | +WVP提供了简单的电子地图用于设备的定位以及移动设备的轨迹信息,电子地图基于开源的地图引擎openlayers开发。 | |
| 4 | +### 查看设备定位 | |
| 5 | +1. 可以在设备列表点击“定位”按钮,自动跳转到电子地图页面; | |
| 6 | +2. 在电子地图页面在设备上右键点击“定位”获取设备/平台下的所有通道位置。 | |
| 7 | +3. 单击通道信息可以定位到具体的通道 | |
| 8 | + | |
| 9 | + | |
| 10 | +### 查询设备轨迹 | |
| 11 | +查询轨迹需要提前配置save-position-history选项开启轨迹信息的保存,目前WVP此处未支持分库分表,对于大数据量的轨迹信息无法胜任,有需求请自行二次开发或者定制开发。 | |
| 12 | +在电子地图页面在设备上右键点击“查询轨迹”获取设备轨迹信息。 | |
| 13 | + | |
| 14 | +PS: 目前的底图仅用用作演示和学习,商用情况请自行购买授权使用。 | |
| 15 | + | |
| 16 | +### 更换底图以及底图配置 | |
| 17 | +目前WVP支持使用了更换底图,配置文件在web_src/static/js/mapConfig.js,请修改后重新编译前端文件。 | |
| 18 | +```javascript | |
| 19 | +window.mapParam = { | |
| 20 | + // 开启/关闭地图功能 | |
| 21 | + enable: true, | |
| 22 | + // 坐标系 GCJ-02 WGS-84, | |
| 23 | + coordinateSystem: "GCJ-02", | |
| 24 | + // 地图瓦片地址 | |
| 25 | + tilesUrl: "http://webrd0{1-4}.is.autonavi.com/appmaptile?x={x}&y={y}&z={z}&lang=zh_cn&size=1&scale=1&style=8", | |
| 26 | + // 瓦片大小 | |
| 27 | + tileSize: 256, | |
| 28 | + // 默认层级 | |
| 29 | + zoom:10, | |
| 30 | + // 默认地图中心点 | |
| 31 | + center:[116.41020, 39.915119], | |
| 32 | + // 地图最大层级 | |
| 33 | + maxZoom:18, | |
| 34 | + // 地图最小层级 | |
| 35 | + minZoom: 3 | |
| 36 | +} | |
| 37 | +``` | ... | ... |
doc/_content/ability/node_manger.md
0 → 100644
| 1 | +<!-- 节点管理 --> | |
| 2 | +# 节点管理 | |
| 3 | +WVP支持单个WVP多个ZLM的方案来扩展WVP的视频并发能力,并发点播是因为带宽和性能的原因,单个ZLM节点能支持的路数有限,所以WVP增加了ZLM集群来扩展并发并且保证ZLM的高可用。 | |
| 4 | +## 默认节点 | |
| 5 | +WVP中为了保证功能的完整性,ZLM节点至少要有一个默认节点,这个节点不是在管理页面添加的,而是在WVP的配置文件中配置的,这个节点不可在页面删除。每次启动会自动从配置文件中读取配置写入数据库备用。 | |
| 6 | +## 新增节点 | |
| 7 | +启动你要添加的zlm节点,然后点击“添加节点”按钮输入zlm的ip, http端口,SECRET。点击测试测试完成则开始对节点进行详细的设置,如果你的zlm是使用docker启动的,可能存在zlm使用的端口与宿主机端口不一致的情况,需要在这里一一配置。 | |
| 8 | +## wvp使用多个节点的原理 | |
| 9 | +wvp会把连接的节点统一记录在redis中,并记录zlm的负载情况,当新的请求到来时,会取出负载最低的那个zlm进行使用。以此保证节点负载均衡。 | ... | ... |
doc/_content/ability/online_doc.md
0 → 100644
doc/_content/ability/proxy.md
0 → 100644
| 1 | +<!-- 拉流代理 --> | |
| 2 | +# 拉流代理 | |
| 3 | +不是所有的摄像机都支持国标或者推流的,但是这些设备可以得到一个视频播放地址,通常为rtsp协议, | |
| 4 | +以大华为例: | |
| 5 | +```text | |
| 6 | +rtsp://{user}:{passwd}@{ipc_ip}:{rtsp_port}/cam/realmonitor?channel=1&subtype=0 | |
| 7 | +``` | |
| 8 | +可以得到这样一个流地址,可以直接用vlc进行播放,此时我们可以通过拉流代理功能将这个设备推送给其他国标平台了。 | |
| 9 | +流程如下: | |
| 10 | +```plantuml | |
| 11 | +@startuml | |
| 12 | +"摄像机" <- "ZLMediaKit": 1. 流去流信息到ZLM | |
| 13 | +"ZLMediaKit" -> "WVP-PRO": 2. 收到hook通知得到流信息 | |
| 14 | +"上级国标平台" -> "WVP-PRO": 3. 点播这路视频 | |
| 15 | +"WVP-PRO" -> "ZLMediaKit": 4. 通知推流到上级国标平台 | |
| 16 | +@enduml | |
| 17 | +``` | |
| 18 | +## 添加代理 | |
| 19 | +拉流代理支持两种方式: | |
| 20 | +1. ZLM中直接代理流,支持RTSP/RTMP,不支持转码; | |
| 21 | +2. 借助ffmpeg完成拉转,可以通过修改ffmpeg拉转参数完成转码。 | |
| 22 | +点击页面的“添加代理”,安装提示操作即可,保存并启用成功后,可以在国标级联中[添加通道推送给上级平台](./_content/ability/cascade?id=_2-%e6%b7%bb%e5%8a%a0%e7%9b%ae%e5%bd%95%e4%b8%8e%e9%80%9a%e9%81%93) | |
| 23 | + | |
| 24 | +PS: ffmpeg默认模板不需修改,需要修改参数自行去ZLM配置文件中添加一个即可。 | ... | ... |
doc/_content/ability/push.md
0 → 100644
| 1 | +<!-- 推流列表 --> | |
| 2 | +# 推流列表 | |
| 3 | +## 功能说明 | |
| 4 | + | |
| 5 | +WVP支持三种图像输入方式,直播,[拉流代理](_content/ability/proxy.md),[国标](_content/ability/device.md),直播设备接入流程如下 | |
| 6 | +```plantuml | |
| 7 | +@startuml | |
| 8 | +"直播设备" -> "ZLMediaKit": 1. 发起推流 | |
| 9 | +"ZLMediaKit" -> "WVP-PRO": 2. 收到hook通知得到流信息 | |
| 10 | +"上级国标平台" -> "WVP-PRO": 3. 点播这路视频 | |
| 11 | +"WVP-PRO" -> "ZLMediaKit": 4. 通知推流到上级国标平台 | |
| 12 | +@enduml | |
| 13 | +``` | |
| 14 | +1. 默认情况下WVP收到推流信息后,列表中出现这条推流信息,此时你可以点击“加入国标”按钮为此路推流配置名称以及国标编号,只有有国标编号的推流才可以添加到级联平台,保存成功后可以在国标级联中[添加通道推送给上级平台](_content/ability/cascade?id=_2-%e6%b7%bb%e5%8a%a0%e7%9b%ae%e5%bd%95%e4%b8%8e%e9%80%9a%e9%81%93) | |
| 15 | +2. WVP也支持推流前导入大量通道直接推送给上级,点击“下载模板”按钮,根据示例修改模板后,点击“通道导入”按钮导入通道数据,保存成功后可以在国标级联中[添加通道推送给上级平台](_content/ability/cascade?id=_2-%e6%b7%bb%e5%8a%a0%e7%9b%ae%e5%bd%95%e4%b8%8e%e9%80%9a%e9%81%93) | |
| 16 | + | |
| 17 | +## 推拉流鉴权规则 | |
| 18 | +为了保护服务器的WVP默认开启推流鉴权(目前不支持关闭此功能) | |
| 19 | + | |
| 20 | +### 推流规则 | |
| 21 | +推流时需要携带推流鉴权的签名sign,sign=md5(pushKey),pushKey来自用户表,每个用户会有一个不同的pushKey. | |
| 22 | +例如app=test,stream=live,pushKey=1000,ip=192.168.1.4, port=10554 那么推流地址为: | |
| 23 | +``` | |
| 24 | +rtsp://192.168.1.4:10554/test/live?sign=a9b7ba70783b617e9998dc4dd82eb3c5 | |
| 25 | +``` | |
| 26 | +支持推流时自定义播放鉴权Id,参数名为callId,此时sign=md5(callId_pushKey) | |
| 27 | +例如app=test,stream=live,pushKey=1000,callId=12345678, ip=192.168.1.4, port=10554 那么推流地址为: | |
| 28 | +``` | |
| 29 | +rtsp://192.168.1.4:10554/test/live?callId=12345678&sign=c8e6e01dde2d60c66dcea8d2498ffef1 | |
| 30 | +``` | |
| 31 | +### 播放规则 | |
| 32 | +默认情况播放不需要鉴权,但是如果推流时携带了callId,那么播放时必须携带callId | |
| 33 | +例如app=test,stream=live,无callId, ip=192.168.1.4, port=10554 那么播放地址为: | |
| 34 | +``` | |
| 35 | +rtsp://192.168.1.4:10554/test/live | |
| 36 | +``` | |
| 37 | +例如app=test,stream=live,callId=12345678, ip=192.168.1.4, port=10554 那么播放地址为: | |
| 38 | +``` | |
| 39 | +rtsp://192.168.1.4:10554/test/live?callId=12345678 | |
| 40 | +``` | |
| 41 | + | ... | ... |
doc/_content/ability/user.md
0 → 100644
doc/_content/about_doc.md
0 → 100644
doc/_content/disclaimers.md
0 → 100644
doc/_content/donation.md
0 → 100644
| 1 | +# 捐赠 | |
| 2 | +项目目前仍在积极开发。大家的捐赠以及start可以让我看到大家的支持于关注。更加有动力把项目维护下去。 | |
| 3 | + | |
| 4 | +<div align="left"> | |
| 5 | +<img src=_media/weixin.jpg style="height: 500px; border: 1px solid #e2e2e2"/> | |
| 6 | +<img src=_media/zhifubao.jpg style="height: 500px; border: 1px solid #e2e2e2; margin-left: 20px"/> | |
| 7 | +</div> | |
| 0 | 8 | \ No newline at end of file | ... | ... |
doc/_content/introduction/_media/img.png
0 → 100644
112 KB
doc/_content/introduction/_media/img_1.png
0 → 100644
150 KB
doc/_content/introduction/_media/img_2.png
0 → 100644
206 KB
doc/_content/introduction/compile.md
0 → 100644
| 1 | +<!-- 编译 --> | |
| 2 | +# 编译 | |
| 3 | +WVP-PRO不只是实现了国标28181的协议,本身也是一个完整的视频平台。所以对于新手来说,你可能需要一些耐心来完成。遇到问题不要焦躁,你可以 | |
| 4 | +1. 百度 | |
| 5 | +2. 如果身边有熟悉java的朋友,可以咨询下朋友; | |
| 6 | +3. 来群里(901799015)咨询群友; | |
| 7 | +4. 向作者发送邮件648540858@qq.com; | |
| 8 | +5. 作者远程支持(有偿)。 | |
| 9 | + 如果这些仍不能解决你的问题,那么你可能需要与作者我一起合作完成这个项目,解决你遇到的问题。 | |
| 10 | + | |
| 11 | + | |
| 12 | +WVP-PRO使用Spring boot开发,maven管理依赖。对于熟悉spring开发的朋友是很容易进行编译部署以及运行的。 | |
| 13 | +下面将提供一种通用方法方便大家运行项目。 | |
| 14 | +## 1 服务介绍 | |
| 15 | +| 服务 | 作用 | 是否必须 | | |
| 16 | +|----------------|------------------------------------------|-------------------------| | |
| 17 | +| WVP-PRO | 实现国标28181的信令以及视频平台相关的功能 | 是 | | |
| 18 | +| ZLMediaKit | 为WVP-PRO提供国标28181的媒体部分的实现,以及各种视频流格式的分发支持 | 是 | | |
| 19 | +| wvp-pro-assist | wvp的辅助录像程序,也可单独跟zlm一起使用,提供录像控制,录像合并下载接口 | 否(不安装只是影响云端录像功能和国标录像下载) | | |
| 20 | + | |
| 21 | +## 2 安装依赖 | |
| 22 | +| 依赖 | 版本 | 用途 | 开发环境需要 | 生产环境需要 | | |
| 23 | +|--------|------------|-------------|--------|--------| | |
| 24 | +| jdk | >=1.8 | 运行与编译java代码 | 是 | 是 | | |
| 25 | +| maven | >=3.3 | 管理java代码依赖 | 否 | 否 | | |
| 26 | +| git || 下载/更新/提交代码 | 否 | 否 | | |
| 27 | +| nodejs || 编译于运行前端文件 | 否 | 否 | | |
| 28 | +| npm || 管理前端文件依赖 | 否 | 否 | | |
| 29 | + | |
| 30 | +如果你是一个新手,建议你使用linux或者macOS平台。windows不推荐。 | |
| 31 | + | |
| 32 | +ubuntu环境,以ubuntu 18为例: | |
| 33 | +``` bash | |
| 34 | +apt-get install -y openjdk-11-jre git maven nodejs npm | |
| 35 | +``` | |
| 36 | +centos环境,以centos 8为例: | |
| 37 | +```bash | |
| 38 | +yum install -y java-1.8.0-openjdk.x86_64 git maven nodejs npm | |
| 39 | +``` | |
| 40 | +window环境,以windows10为例: | |
| 41 | +```bash | |
| 42 | +这里不细说了,百度或者谷歌一搜一大把,基本都是下一步下一步,然后配置环境变量。 | |
| 43 | +``` | |
| 44 | +## 3 安装mysql以及redis | |
| 45 | +这里依然是参考网上教程,自行安装吧。 | |
| 46 | + | |
| 47 | +## 4 编译ZLMediaKit | |
| 48 | +参考ZLMediaKit[WIKI](https://github.com/ZLMediaKit/ZLMediaKit/wiki),截取一下关键步骤: | |
| 49 | +```bash | |
| 50 | +# 国内用户推荐从同步镜像网站gitee下载 | |
| 51 | +git clone --depth 1 https://gitee.com/xia-chu/ZLMediaKit | |
| 52 | +cd ZLMediaKit | |
| 53 | +# 千万不要忘记执行这句命令 | |
| 54 | +git submodule update --init | |
| 55 | +``` | |
| 56 | +## 5 编译WVP-PRO | |
| 57 | +### 5.1 可以通过git克隆,也可以在项目下载点击下载 | |
| 58 | + | |
| 59 | + | |
| 60 | +从gitee克隆 | |
| 61 | +```bash | |
| 62 | +git clone https://gitee.com/pan648540858/wvp-GB28181-pro.git | |
| 63 | +``` | |
| 64 | +从github克隆 | |
| 65 | +```bash | |
| 66 | +git clone https://github.com/648540858/wvp-GB28181-pro.git | |
| 67 | +``` | |
| 68 | + | |
| 69 | +### 5.2 编译前端页面 | |
| 70 | +```shell script | |
| 71 | +cd wvp-GB28181-pro/web_src/ | |
| 72 | +npm --registry=https://registry.npm.taobao.org install | |
| 73 | +npm run build | |
| 74 | +``` | |
| 75 | +编译如果报错, 一般都是网络问题, 导致的依赖包下载失败 | |
| 76 | +编译完成后在src/main/resources下出现static目录 | |
| 77 | +**编译完成一般是这个样子,中间没有报红的错误信息** | |
| 78 | + | |
| 79 | + | |
| 80 | +### 5.3 打包项目, 生成可执行jar | |
| 81 | +```bash | |
| 82 | +cd wvp-GB28181-pro | |
| 83 | +mvn package | |
| 84 | +``` | |
| 85 | +编译如果报错, 一般都是网络问题, 导致的依赖包下载失败 | |
| 86 | +编译完成后在target目录下出现wvp-pro-***.jar。 | |
| 87 | +接下来[配置服务](./_content/introduction/config.md) | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | ... | ... |
doc/_content/introduction/config.md
0 → 100644
| 1 | +<!-- 配置 --> | |
| 2 | +# 配置 | |
| 3 | +对于首次测试或者新手同学,我建议在局域网测试,并且关闭服务器与客户机的防火墙测试。建议部署在linux进行测试。 | |
| 4 | + | |
| 5 | +```plantuml | |
| 6 | +@startuml | |
| 7 | +"WVP-PRO" -> "ZLMediaKit": RESTful 接口 | |
| 8 | +"WVP-PRO" <-- "ZLMediaKit": Web Hook 接口 | |
| 9 | +@enduml | |
| 10 | +``` | |
| 11 | +WVP-PRO通过调用ZLMediaKit的RESTful接口实现对ZLMediaKit行为的控制; ZLMediaKit通过Web Hook 接口把消息通知WVP-PRO。通过这种方式,实现了两者的互通。 | |
| 12 | +对于最简单的配置,你不需要修改ZLMediaKit的任何默认配置。你只需要在WVP-PRO中配置的ZLMediaKit信息即可 | |
| 13 | +## 1 WVP配置文件位置 | |
| 14 | +基于spring boot的开发方式,配置文件的加载是很灵活的。默认在src/main/resources/application.yml,部分配置项是可选,你不需要全部配置在配置文件中, | |
| 15 | +完全的配置说明可以参看all-application.yml。 | |
| 16 | +### 1.1 默认加载配置文件方式 | |
| 17 | +使用maven打包后的jar包里,已经存在了配置文件,但是每次打开jar包修改配置文件或者修改后再打包都是比较麻烦的,所以大家可通过指定配置文件路径来加载指定位置的配置文件。 | |
| 18 | +```shell | |
| 19 | +cd wvp-GB28181-pro/target | |
| 20 | +java -jar wvp-pro-*.jar --spring.config.location=../src/main/resources/application.yml | |
| 21 | +``` | |
| 22 | +### 1.2 迁移配置文件以方便启动 | |
| 23 | +由于配置文件的命令比较长,所以为了启动方便通常我会把配置文件放到jar包的同级目录,类似这样, | |
| 24 | +移除jar包内/BOOT-INF/classes/下所有以application开头的文件,使用解压缩工具打开jar即可,不需要解压出来。 | |
| 25 | +```shell | |
| 26 | +cd wvp-GB28181-pro/target | |
| 27 | +mv ../src/main/resources/application-dev.yml application.yml | |
| 28 | +java -jar wvp-pro-*.jar | |
| 29 | +``` | |
| 30 | +这也是我自己最常用的方式。 | |
| 31 | +## 2 配置WVP-PRO | |
| 32 | +### 2.1 Mysql数据库配置 | |
| 33 | +首先你需要创建一个名为wvp(也可使用其他名字)的数据库,并使用sql/mysql.sql导入数据库,初始化数据库结构。 | |
| 34 | +在application-dev.yml中配置(使用1.2方式的是在jar包的同级目录的application.yml)配置数据库连接,包括数据库连接信息,密码。 | |
| 35 | +### 2.2 Redis数据库配置 | |
| 36 | +配置wvp中的redis连接信息,建议wvp自己单独使用一个db。 | |
| 37 | +### 2.3 配置服务启动端口(可直接使用默认配置) | |
| 38 | +```yaml | |
| 39 | +# [可选] WVP监听的HTTP端口, 网页和接口调用都是这个端口 | |
| 40 | +server: | |
| 41 | + port: 18080 | |
| 42 | +``` | |
| 43 | +### 2.4 配置28181相关信息(可直接使用默认配置) | |
| 44 | +```yaml | |
| 45 | +# 作为28181服务器的配置 | |
| 46 | +sip: | |
| 47 | + # [必须修改] 本机的IP | |
| 48 | + ip: 192.168.1.3 | |
| 49 | + # [可选] 28181服务监听的端口 | |
| 50 | + port: 5060 | |
| 51 | + # 根据国标6.1.2中规定,domain宜采用ID统一编码的前十位编码。国标附录D中定义前8位为中心编码(由省级、市级、区级、基层编号组成,参照GB/T 2260-2007) | |
| 52 | + # 后两位为行业编码,定义参照附录D.3 | |
| 53 | + # 3701020049标识山东济南历下区 信息行业接入 | |
| 54 | + # [可选] | |
| 55 | + domain: 3402000000 | |
| 56 | + # [可选] | |
| 57 | + id: 34020000002000000001 | |
| 58 | + # [可选] 默认设备认证密码,后续扩展使用设备单独密码, 移除密码将不进行校验 | |
| 59 | + password: 12345678 | |
| 60 | +``` | |
| 61 | +### 2.5 配置ZLMediaKit连接信息 | |
| 62 | +```yaml | |
| 63 | +#zlm 默认服务器配置 | |
| 64 | +media: | |
| 65 | + # ZLMediaKit的服务ID,必须配置 | |
| 66 | + id: FQ3TF8yT83wh5Wvz | |
| 67 | + # [必须修改] zlm服务器的内网IP,sdp-ip与stream-ip使用默认值的情况下,这里不要使用127.0.0.1/0.0.0.0 | |
| 68 | + ip: 192.168.1.3 | |
| 69 | + # [必须修改] zlm服务器的http.port | |
| 70 | + http-port: 6080 | |
| 71 | + # [可选] zlm服务器的hook.admin_params=secret | |
| 72 | + secret: 035c73f7-bb6b-4889-a715-d9eb2d1925cc | |
| 73 | + # 启用多端口模式, 多端口模式使用端口区分每路流,兼容性更好。 单端口使用流的ssrc区分, 点播超时建议使用多端口测试 | |
| 74 | + rtp: | |
| 75 | + # [可选] 是否启用多端口模式, 开启后会在portRange范围内选择端口用于媒体流传输 | |
| 76 | + enable: true | |
| 77 | + # [可选] 在此范围内选择端口用于媒体流传输, | |
| 78 | + port-range: 30000,30500 # 端口范围 | |
| 79 | + # [可选] 国标级联在此范围内选择端口发送媒体流, | |
| 80 | + send-port-range: 30000,30500 # 端口范围 | |
| 81 | + # 录像辅助服务, 部署此服务可以实现zlm录像的管理与下载, 0 表示不使用 | |
| 82 | + record-assist-port: 18081 | |
| 83 | +``` | |
| 84 | +### 2.4 个性化定制信息配置 | |
| 85 | +```yaml | |
| 86 | +# [根据业务需求配置] | |
| 87 | +user-settings: | |
| 88 | + # [可选] 服务ID,不写则为000000 | |
| 89 | + server-id: | |
| 90 | + # [可选] 自动点播, 使用固定流地址进行播放时,如果未点播则自动进行点播, 需要rtp.enable=true | |
| 91 | + auto-apply-play: false | |
| 92 | + # [可选] 部分设备需要扩展SDP,需要打开此设置 | |
| 93 | + senior-sdp: false | |
| 94 | + # 保存移动位置历史轨迹:true:保留历史数据,false:仅保留最后的位置(默认) | |
| 95 | + save-position-history: false | |
| 96 | + # 点播等待超时时间,单位:毫秒 | |
| 97 | + play-timeout: 3000 | |
| 98 | + # 等待音视频编码信息再返回, true: 可以根据编码选择合适的播放器,false: 可以更快点播 | |
| 99 | + wait-track: false | |
| 100 | + # 是否开启接口鉴权 | |
| 101 | + interface-authentication: true | |
| 102 | + # 自动配置redis 可以过期事件 | |
| 103 | + redis-config: true | |
| 104 | + # 接口鉴权例外的接口, 即不进行接口鉴权的接口,尽量详细书写,尽量不用/**,至少两级目录 | |
| 105 | + interface-authentication-excludes: | |
| 106 | + - /api/v1/** | |
| 107 | + # 推流直播是否录制 | |
| 108 | + record-push-live: true | |
| 109 | + # 国标是否录制 | |
| 110 | + record-sip: true | |
| 111 | + # 是否将日志存储进数据库 | |
| 112 | + logInDatebase: true | |
| 113 | + # 第三方匹配,用于从stream钟获取有效信息 | |
| 114 | + thirdPartyGBIdReg: [\s\S]* | |
| 115 | +``` | |
| 116 | + | |
| 117 | + | |
| 118 | +如果配置信息无误,你可以启动zlm,再启动wvp来测试了,启动成功的话,你可以在wvp的日志下看到zlm已连接的提示。 | |
| 119 | +接下来[部署到服务器](./_content/introduction/deployment.md), 如何你只是本地运行直接再本地运行即可。 | |
| 0 | 120 | \ No newline at end of file | ... | ... |
doc/_content/introduction/deployment.md
0 → 100644
| 1 | +<!-- 部署 --> | |
| 2 | + | |
| 3 | +# 部署 | |
| 4 | +**请仔细阅读以下内容** | |
| 5 | +1. WVP-PRO与ZLM支持分开部署,但是wvp-pro-assist必须与zlm部署在同一台主机; | |
| 6 | +2. 需要开放的端口 | |
| 7 | +| 服务 | 端口 | 类型 | 必选 | | |
| 8 | +|-----|:-------------------------|-------------|-------| | |
| 9 | +| wvp | server.port | tcp | 是 | | |
| 10 | +| wvp | sip.port | udp and tcp | 是 | | |
| 11 | +| zlm | http.port | tcp | 是 | | |
| 12 | +| zlm | http.sslport | tcp | 否 | | |
| 13 | +| zlm | rtmp.port | tcp | 否 | | |
| 14 | +| zlm | rtmp.sslport | tcp | 否 | | |
| 15 | +| zlm | rtsp.port | udp and tcp | 否 | | |
| 16 | +| zlm | rtsp.sslport | udp and tcp | 否 | | |
| 17 | +| zlm | rtp_proxy.port | udp and tcp | 单端口开放 | | |
| 18 | +| zlm | rtp.port-range(在wvp中配置) | udp and tcp | 多端口开放 | | |
| 19 | + | |
| 20 | +3. 测试环境部署建议所有服务部署在一台主机,关闭防火墙,减少因网络出现问题的可能; | |
| 21 | +4. WVP-PRO与ZLM支持分开部署,但是wvp-pro-assist必须与zlm部署在同一台主机; | |
| 22 | +5. 生产环境按需开放端口,但是建议修改默认端口,尤其是5060端口,易受到攻击; | |
| 23 | +6. zlm使用docker部署的情况,要求端口映射一致,比如映射5060,应将外部端口也映射为5060端口; | |
| 24 | +7. 启动服务,以linux为例 | |
| 25 | +**启动WVP-PRO** | |
| 26 | +```shell | |
| 27 | +nohup java -jar java -jar wvp-pro-*.jar & | |
| 28 | +``` | |
| 29 | + | |
| 30 | +**启动ZLM** | |
| 31 | +```shell | |
| 32 | +nohup ./MediaServer -d -m 3 & | |
| 33 | +``` | |
| 34 | + | |
| 35 | +[接入设备](./_content/ability/device.md) | |
| 36 | + | ... | ... |
doc/_content/qa/_media/img.png
0 → 100644
139 KB
doc/_content/qa/_media/img_1.png
0 → 100644
117 KB
doc/_content/qa/_media/img_2.png
0 → 100644
72.3 KB
doc/_content/qa/_media/img_3.png
0 → 100644
90.2 KB
doc/_content/qa/_media/img_4.png
0 → 100644
48 KB
doc/_content/qa/_media/img_5.png
0 → 100644
149 KB
doc/_content/qa/bug.md
0 → 100644
| 1 | +<!-- 反馈bug --> | |
| 2 | +# 反馈bug | |
| 3 | +代码是在不断的完善的,不断修改会修复旧的问题也有可能引入新的问题,所以遇到BUG是很正常的一件事。所以遇到问题不要烦燥,咱们就事论事就好了。 | |
| 4 | +## 如何反馈 | |
| 5 | +1. 更新代码,很可能你遇到问题别人已经更早的遇到了,或者是作者自己发现了,已经解决了,所以你可以更新代码再次进行测试; | |
| 6 | +2. 可以在github提ISSUE,我几乎每天都会去看issue,你的问题我会尽快给予答复; | |
| 7 | +3. 你可以来我的QQ群里,询问群友看看是否遇到了同样的问题; | |
| 8 | +4. 你可以私聊我的QQ,如果我有时间我会给你答复,但是除非你有明确的复现步骤或者修复方案,否则你可能等不到我的答复。 | |
| 9 | + | |
| 10 | +## 如何快速解决BUG | |
| 11 | +目前解决BUG有三种方式: | |
| 12 | +1. 作者验证以及修复; | |
| 13 | +2. 热心开发者提来的PR; | |
| 14 | +3. 使用运维手段屏蔽BUG的影响。 | |
| 15 | + | |
| 16 | +- 对于第一种:详细的复现步骤,完整的抓包文件,有条理的错误分析都可以帮助作者复现问题,进而解决问题。解决问题往往不是最难的,复现才是。 | |
| 17 | +- 对于第二种:如果你是开发者,你已经发现了造成BUG的原因以及知道如何正确的修复,那么我很希望你PR,SRS的大佬经常说的,开源不是一个人的事。所以你的参与就是最大的鼓励。 | |
| 18 | +- 对于第三种:如果你有一个有经验的运维伙伴,那么部分问题是可以通过运维的手段暂时屏蔽的,在等待修复的这段时间了以保证项目的运行。 | |
| 19 | + | ... | ... |
doc/_content/qa/development.md
0 → 100644
| 1 | +<!-- 参与开发 --> | |
| 2 | +# 参与到开发中来 | |
| 3 | +非常欢迎有兴趣的小伙伴一起来维护这个项目 | |
| 4 | +## 与开发有关的信息 | |
| 5 | +- 开发语言:后端java + 前端vue; | |
| 6 | +- jdk版本: 1.8; | |
| 7 | +- 作者自用开发ide: jetbrains intellij idea; | |
| 8 | +- nodejs/npm版本:v10.19.0/6.14.4; | |
| 9 | +- 后端使用Spring boot框架开发; | |
| 10 | +- 项目大量使用了异步操作; | |
| 11 | +- 跟代码学流程需要参考28181文档,只看代码你会很懵的; | |
| 12 | +- 必须学会[抓包](_content/skill/tcpdump.md),这是必须的 | |
| 13 | + | |
| 14 | +## 提交代码 | |
| 15 | +大家可以通过fork项目的方式提交自己的代码,然后提交PR,我来合并到主线。提交代码的过程中我们需要遵循“**阿里编码规约**”,现有代码也有很多代码没有做到,但是我们在朝这个方向努力。 | |
| 0 | 16 | \ No newline at end of file | ... | ... |
doc/_content/qa/img.png
0 → 100644
139 KB
doc/_content/qa/play_error.md
0 → 100644
| 1 | +<!-- 点播错误 --> | |
| 2 | +# 点播错误 | |
| 3 | +排查点播错误你首先要清除[点播的基本流程](_content/theory/play.md),一般的流程如下: | |
| 4 | +```plantuml | |
| 5 | +@startuml | |
| 6 | +"WEB用户" -> "WVP-PRO": 1. 发起点播请求 | |
| 7 | +"设备" <- "WVP-PRO": 2. Invite(携带SDP消息体) | |
| 8 | +"设备" --> "WVP-PRO": 3. 200OK(携带SDP消息体) | |
| 9 | +"设备" <-- "WVP-PRO": 4. Ack | |
| 10 | +"设备" -> "ZLMediaKit": 5. 发送实时流 | |
| 11 | +"WVP-PRO" <- "ZLMediaKit": 6. 流改变事件 | |
| 12 | +"WEB用户" <-- "WVP-PRO": 7. 回复流播放地址(携带流地址) | |
| 13 | +"WVP-PRO" <- "ZLMediaKit": 8. 无人观看事件 | |
| 14 | +"设备" <- "WVP-PRO": 9 Bye消息 | |
| 15 | +"设备" --> "WVP-PRO": 10 200OK | |
| 16 | +@enduml | |
| 17 | +``` | |
| 18 | +针对几种常见的错误,我们来分析一下,也方便大家对号入座解决常见的问题 | |
| 19 | +## 点播收到错误码 | |
| 20 | +这个错误一般表现为点击"播放"按钮后很快得到一个错误。 | |
| 21 | +1. **400错误码** | |
| 22 | +出现400错误玛时一般是这样的流程是这样的 | |
| 23 | +```plantuml | |
| 24 | +@startuml | |
| 25 | +"WEB用户" -> "WVP-PRO": 1. 发起点播请求 | |
| 26 | +"设备" <- "WVP-PRO": 2. Invite(携带SDP消息体) | |
| 27 | +"设备" --> "WVP-PRO": 3. 400错误 | |
| 28 | +@enduml | |
| 29 | +``` | |
| 30 | +此时通常是设备认为WVP发送了错误的消息给它,它认为消息不全或者错误所以直接返回400错误,此时我们需要[抓包](_content/skill/tcpdump.md)来分析是否缺失了内容,也可以直接联系对方询问为什么返回了400。 | |
| 31 | +WVP不能保证兼容所有的设备,有些实现不规范的设备可能在对接时就会出现上述问题,你可以联系作者帮忙对接。 | |
| 32 | +2. **500错误码** | |
| 33 | +500或者大于500小于600的错误码一般多是设备内部出了问题,解决方式有两个,第一种直接联系设备/平台客服寻求解决;第二种,如果你有确定可以对接这个设备的平台那么可以把对接这个平台的抓包和对接wvp的抓包同时发送给我,我来尝试解决。 | |
| 34 | + | |
| 35 | + | |
| 36 | +## 点播超时 | |
| 37 | +点播超时的情况大致分为两种:点播超时和收流超时 | |
| 38 | +1. **点播超时** | |
| 39 | +点播超时错误一般为信令的超时,比如长时间为收到对方的回复,可能出现在流程中 “3. 200OK(携带SDP消息体)”这个位置,即我们发送点播消息,但是设备没有回复,可能的原因: | |
| 40 | +> 1. 设备内部错误,未能回复消息 | |
| 41 | +> 2. 网络原因消息未到到达设备 | |
| 42 | + | |
| 43 | +大部分时候是原因2,所以遇到这个错误我们首先要排查我们我的网路,如果你是公网部署,那么也可能时心跳周期太长,导致的路由NAT失效,WVP的消息无法通道原来的IP端口号发送给设备。 | |
| 44 | + | |
| 45 | +2. **收流超时** | |
| 46 | +收流超时可能发生在流程中的5和6,可能的原因有: | |
| 47 | +> 1. 设备发送了流但是发送到了错误的ip和端口上,而这个信息是在invite消息的sdp中指定的,就是流程2Invite(携带SDP消息体)中,而这个错误很可能来自你的配置错误,比如你设置了127.0.0.1导致设备网127.0.0.1上发流,或者是你WVP在公网,但是你给设备了一个内网ip,导致设备无法把流发送过来; | |
| 48 | +> 2. 设备内部错误未发送流; | |
| 49 | +> 2. 设备发送了流,但是流无法识别,可能存在于流不规范和网络很差的情况下; | |
| 50 | +> 3. 设备发送了流,zlm也收到了,但是zlm无法通过hook通知到wvp,此时原因是你可以检查zlm的配置文件中的hook配置,看看是否无法从zlm连接到wvp; | |
| 51 | +> 4. 设备发送了流,但是开启SSRC校验,设备的流不够规范采用错误的ssrc,导致zlm选择丢弃; | |
| 52 | + | |
| 53 | +针对这些可能的错误原因我建议的排查顺序: | |
| 54 | +- 关闭ssrc校验; | |
| 55 | +- 查看zlm配置的hook是否可以连接到zlm; | |
| 56 | +- 查看zlm日志是否有流注册; | |
| 57 | +- 抓包查看流的信息,看看流是否正常发送,甚至可以导出发送原始流,用vlc播放,看看是否可以播放。 | ... | ... |
doc/_content/qa/regiser_error.md
0 → 100644
doc/_content/qa/start_error.md
0 → 100644
| 1 | +<!-- 启动时报错 --> | |
| 2 | +# 启动时报错 | |
| 3 | +启动时的报错大部分时候是因为你的配置有问题,比如mysql没连接上,redis没连接上,18080/15060端口占用了,这些都会导致启动是报错,修改配置配置之后都可以解决; | |
| 4 | +下面我整理的一些常见的错误,大家可以先对号入座的简单排查下。 | |
| 5 | +> **常见错误** | |
| 6 | + | |
| 7 | + | |
| 8 | +**错误原因:** redis配置错误,可能原因: redis未启动/ip错误/端口错误/网络不通 | |
| 9 | +--- | |
| 10 | + | |
| 11 | +**错误原因:** redis配置错误,可能原因: 密码错误 | |
| 12 | +--- | |
| 13 | + | |
| 14 | +**错误原因:** mysql配置错误,可能原因: mysql未启动/ip错误/端口错误/网络不通 | |
| 15 | +--- | |
| 16 | + | |
| 17 | +**错误原因:** mysql配置错误,可能原因: 用户名/密码错误 | |
| 18 | +--- | |
| 19 | + | |
| 20 | +**错误原因:** SIP配置错误,可能原因: SIP端口被占用 | |
| 21 | +--- | |
| 22 | + | |
| 23 | +**错误原因:** WVP Tomcat端口配置错误,可能原因: server.port端口被占用 | |
| 24 | +--- | |
| 0 | 25 | \ No newline at end of file | ... | ... |
doc/_content/skill/_media/img.png
0 → 100644
43.8 KB
doc/_content/skill/_media/img_1.png
0 → 100644
105 KB
doc/_content/skill/_media/img_2.png
0 → 100644
15.9 KB
doc/_content/skill/tcpdump.md
0 → 100644
| 1 | +<!-- 抓包 --> | |
| 2 | +# 抓包 | |
| 3 | +如果说对于网络编程,有什么工具是必会的,我觉得抓包肯定是其中之一了。作为GB/T 28181调试过程中最重要的手段,我觉得如果你真对他有兴趣,或者系统遇到问题可以最快的得到解决,那么抓包你就一定要学会了。 | |
| 4 | + | |
| 5 | +## 抓包工具的选择 | |
| 6 | +### 1. Wireshark | |
| 7 | +在具备图形界面的系统上,比如windows,linux发行版ubuntu,opensuse等,我一般直接使用Wireshark直接进行抓包,也方便进行内容的查看。 | |
| 8 | +### 2. Tcpdump | |
| 9 | +在使用命令行的系统,比如linux服务器,我一般使用Tcpdump进行抓包,无需额外安装,系统一般自带,抓包的到的文件,可以使用Wireshark打开,在图形界面下方便查看内容。 | |
| 10 | + | |
| 11 | +## 工具安装 | |
| 12 | +Wireshark的安装很简单,根据提示一步步点击就好了,在linux需要解决权限的问题,如果和我一样使用图形界面的linux发行版的话,可以参看如下步骤; windows的小伙伴直接略过即可 | |
| 13 | +```shell | |
| 14 | +# 1. 添加wireshark用户组 | |
| 15 | +sudo groupadd wireshark | |
| 16 | +# 2. 将dumpcap更改为wireshark用户组 | |
| 17 | +sudo chgrp wireshark /usr/bin/dumpcap | |
| 18 | +# 3. 让wireshark用户组有root权限使用dumpcap | |
| 19 | +sudo chmod 4755 /usr/bin/dumpcap | |
| 20 | +# 4. 将需要使用的用户名加入wireshark用户组 | |
| 21 | +sudo gpasswd -a $USER wireshark | |
| 22 | +``` | |
| 23 | +tcpdump一般linux都是自带,无需安装,可以这样验证;显示版本信息即是已安装 | |
| 24 | +```shell | |
| 25 | +tcpdump --version | |
| 26 | +``` | |
| 27 | +## 开始抓包 | |
| 28 | +### 使用Wireshark | |
| 29 | +在28181中我一般只关注sip包和rtp包,所以我一般是直接过滤sip和rtp,可以输入框输入 `sip or rtp`这样即可,如果设备来源比较多还可以加上ip和端口号的过滤`(sip or rtp )and ip.addr==192.168.1.3 and udp.port==5060` | |
| 30 | +详细的过滤规则可以自行百度,我可以提供一些常用的给大家参考 | |
| 31 | + | |
| 32 | +**只过滤SIP:** | |
| 33 | +```shell | |
| 34 | +sip | |
| 35 | +``` | |
| 36 | +**只获取rtp数据:** | |
| 37 | +```shell | |
| 38 | +rtp | |
| 39 | +``` | |
| 40 | +**默认方式:** | |
| 41 | +```shell | |
| 42 | +sip or rtp | |
| 43 | +``` | |
| 44 | +**过滤IP:** | |
| 45 | +```shell | |
| 46 | + sip and ip.addr==192.168.1.3 | |
| 47 | +``` | |
| 48 | +**过滤端口:** | |
| 49 | +```shell | |
| 50 | + sip and udp.port==5060 | |
| 51 | +``` | |
| 52 | +输入命令开启抓包后,此时可以进行操作,比如点播,录像回访等,操作完成回到Wireshark点击红色的停止即可,需要保存文件可以点击`文件->导出特定分组`导出过滤后的数据,也可以直接`文件->另存为`保存未过滤的数据。 | |
| 53 | +### 使用tcpdump | |
| 54 | +对于服务器抓包,为了得到足够完整的数据,我一般会要求直接抓取网卡数据而不过滤,如下: | |
| 55 | +抓取网卡首先需要获取网卡名,在linux我一般使用`ip addr`获取网卡信息,如下所示: | |
| 56 | + | |
| 57 | +```shell | |
| 58 | +sudo tcpdump -i wlp3s0 -w demo.pcap | |
| 59 | +``` | |
| 60 | + | |
| 61 | +命令行会停留在这个位置,此时可以进行操作,比如点播,录像回放等,操作完成回到命令行使用`Ctrl+C`结束命令行,在当前目录下得到demo.pcap,将这个文件下载到图形界面操作系统里,即可使用Wireshark查看了 | |
| 62 | +更多的操作可以参考: [https://www.cnblogs.com/jiujuan/p/9017495.html](https://www.cnblogs.com/jiujuan/p/9017495.html) | ... | ... |
doc/_content/theory/_media/img.png
0 → 100644
96.4 KB
doc/_content/theory/_media/img_1.png
0 → 100644
105 KB
doc/_content/theory/_media/img_2.png
0 → 100644
16.8 KB
doc/_content/theory/_media/img_3.png
0 → 100644
82.8 KB
doc/_content/theory/_media/img_4.png
0 → 100644
45.6 KB
doc/_content/theory/_media/img_5.png
0 → 100644
59.5 KB
doc/_content/theory/_media/img_6.png
0 → 100644
51.7 KB
doc/_content/theory/_media/img_7.png
0 → 100644
80 KB
doc/_content/theory/_media/img_8.png
0 → 100644
23.7 KB
doc/_content/theory/_media/img_9.png
0 → 100644
28 KB
doc/_content/theory/channel_tree.md
0 → 100644
| 1 | +<!-- 通道的树形结构 --> | |
| 2 | + | |
| 3 | +# 通道的树形结构 | |
| 4 | + | |
| 5 | +国标28181规定了两种组织设备树的方式 | |
| 6 | +1. **行政区划** | |
| 7 | + 行政区划模式下主要是以行政区划作为目录节点例如:河北省->邯郸市->广平县 | |
| 8 | +  | |
| 9 | +2. **业务分组** | |
| 10 | + 业务分组主要自定义的目录树的一种组织形式,但是对定义的目录的国标编号有一定的要求。 | |
| 11 | + 第一级别需要是业务分组类型,即国标编码中的11、12、13是215,例如:65010200002150000001; | |
| 12 | + 业务分组下是虚拟组织,即国标编码中的11、12、13是216,例如:65010200002160000002。 | |
| 13 | + 虚拟组织下不可是业务分组,虚拟组织下可以继续添加虚拟组织。 | |
| 14 | +  | ... | ... |
doc/_content/theory/code.md
0 → 100644
| 1 | +<!-- 统一编码规则 --> | |
| 2 | + | |
| 3 | +# 统一编码规则 | |
| 4 | +## D.1 编码规则 A | |
| 5 | +>  编码规则 A 由中心编码(8位)、行业编码(2位)、类型编码(3位)和序号(7位)四个码段共20位十 | |
| 6 | +>进制数字字符构成,即系统编码 =中心编码 + 行业编码 + 类型编码 + 序号。 | |
| 7 | +>  编码规则 A 的详细说明见表 D.1。其中,中心编码指用户或设备所归属的监控中心的编码,按照监控中心所在地的行政区划代码确定, | |
| 8 | +> 当不是基层单位时空余位为0。行政区划代码采用 GB/T2260— 2007规定的行政区划代码表示。行业编码是指用户或设备所归属的行业,行业编码对照表见 D.3。 | |
| 9 | +> 类型编码指定了设备或用户的具体类型,其中的前端设备包含公安系统和非公安系统的前端设备,终端用 户包含公安系统和非公安系统的终端用户。 | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | +## D.2 编码规则 B | |
| 16 | +>  编码规则 B由中心编码(8位)、行业编码(2位)、序号(4位)和类型编码(2位)四个码段构成,即系 | |
| 17 | +>统编码 =中心编码 + 行业编码 +序号+类型编码。编码规则 B的详细说明见表 D.2。 | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | +## D.3 行业编码对照表 | |
| 23 | +>  行业编码对照表见表 D.3。 | |
| 24 | + | |
| 25 | + | |
| 0 | 26 | \ No newline at end of file | ... | ... |
doc/_content/theory/img.png
0 → 100644
23.7 KB
doc/_content/theory/play.md
0 → 100644
| 1 | +<!-- 点播流程 --> | |
| 2 | + | |
| 3 | +# 点播流程 | |
| 4 | +> 以下为WVP-PRO点播流程。点播成功前的任何一个环节出现问题都可能出现点播超时,这也是排查点播超时的依据。 | |
| 5 | + | |
| 6 | +```plantuml | |
| 7 | +@startuml | |
| 8 | +"WEB用户" -> "WVP-PRO": 1. 发起点播请求 | |
| 9 | +"设备" <- "WVP-PRO": 2. Invite(携带SDP消息体) | |
| 10 | +"设备" --> "WVP-PRO": 3. 200OK(携带SDP消息体) | |
| 11 | +"设备" <-- "WVP-PRO": 4. Ack | |
| 12 | +"设备" -> "ZLMediaKit": 5. 发送实时流 | |
| 13 | +"WVP-PRO" <- "ZLMediaKit": 6. 流改变事件 | |
| 14 | +"WEB用户" <-- "WVP-PRO": 7. 回复流播放地址(携带流地址) | |
| 15 | +"WVP-PRO" <- "ZLMediaKit": 8. 无人观看事件 | |
| 16 | +"设备" <- "WVP-PRO": 9 Bye消息 | |
| 17 | +"设备" --> "WVP-PRO": 10 200OK | |
| 18 | +@enduml | |
| 19 | +``` | |
| 20 | + | |
| 21 | + | |
| 22 | +## 注册流程描述如下: | |
| 23 | +1. 用户从网页或调用接口发起点播请求; | |
| 24 | +2. WVP-PRO向摄像机发送Invite消息,消息头域中携带 Subject字段,表明点播的视频源ID、发送方媒体流序列号、ZLMediaKit接收流使用的IP、端口号、 | |
| 25 | + 接收端媒体流序列号等参数,SDP消息体中 s字段为“Play”代表实时点播,y字段描述SSRC值,f字段描述媒体参数。 | |
| 26 | +3. 摄像机向WVP-PRO回复200OK,消息体中描述了媒体流发送者发送媒体流的IP、端口、媒体格式、SSRC字段等内容。 | |
| 27 | +4. WVP-PRO向设备回复Ack, 会话建立成功。 | |
| 28 | +5. 设备向ZLMediaKit发送实时流。 | |
| 29 | +6. ZLMediaKit向WVP-PRO发送流改变事件。 | |
| 30 | +7. WVP-PRO向WEB用户回复播放地址。 | |
| 31 | +8. ZLMediaKit向WVP发送流无人观看事件。 | |
| 32 | +9. WVP-PRO向设备回复Bye, 结束会话。 | |
| 33 | +10. 设备回复200OK,会话结束成功。 | ... | ... |
doc/_content/theory/register.md
0 → 100644
| 1 | +<!-- 注册流程 --> | |
| 2 | + | |
| 3 | +# 注册流程 | |
| 4 | +WVP-PRO目前仅支持国标中描述的基本注册流程,也是最常用的, | |
| 5 | +> 基本注册即采用IETFRFC3261规定的基于数字摘要的挑战应答式安全技术进行注册. | |
| 6 | + | |
| 7 | +```plantuml | |
| 8 | +@startuml | |
| 9 | +"设备" -> "WVP-PRO": 1. Register | |
| 10 | +"设备" <-- "WVP-PRO": 2. 401 Unauthorized | |
| 11 | +"设备" -> "WVP-PRO": 3. Register | |
| 12 | +"设备" <-- "WVP-PRO": 4. 200 OK | |
| 13 | +@enduml | |
| 14 | +``` | |
| 15 | + | |
| 16 | + | |
| 17 | +> 注册流程描述如下: | |
| 18 | +> 1. 摄像机向WVP-PRO服务器发送 Register请求; | |
| 19 | +> 2. WVP-PRO向摄像机发送响应401,并在响应的消息头 WWW_Authenticate字段中给出适合摄像机的认证体制和参数; | |
| 20 | +> 3. 摄像机重新向WVP-PRO发送 Register请求,在请求的 Authorization字段给出信任书, 包含认证信息; | |
| 21 | +> 4. WVP-PRO对请求进行验证,如果检查出 摄像机身份合法,向摄像机发送成功响应 200OK,如果身份不合法则发送拒绝服务应答。 | ... | ... |
doc/_coverpage.md
0 → 100644
| 1 | +<!-- 封面 --> | |
| 2 | + | |
| 3 | + | |
| 4 | +# WVP-PRO <small>2.0</small> | |
| 5 | + | |
| 6 | +> 开箱即用的28181协议视频平台。 | |
| 7 | + | |
| 8 | +- 基于GB/T28181-2016标准信令实现,兼容GB/T28181-2011。 | |
| 9 | +- 自带完整前端页面,开箱即用。 | |
| 10 | +- 完全开源,且使用MIT许可协议。可以在保留版权信息的基础上商用。 | |
| 11 | + | |
| 12 | +[GitHub](https://github.com/648540858/wvp-GB28181-pro) | |
| 13 | +[Gitee](https://gitee.com/pan648540858/wvp-GB28181-pro) | |
| 14 | + | |
| 15 | +<!-- 背景色 --> | |
| 16 | + | |
| 17 | +[//]: # ([comment]: <> ()) | ... | ... |
doc/_media/favicon.ico
0 → 100644
No preview for this file type
doc/_media/logo-mini.png
0 → 100644
22.4 KB
doc/_media/logo.png
0 → 100644
65.5 KB
doc/_media/weixin.jpg
0 → 100644
87.1 KB
doc/_media/zhifubao.jpg
0 → 100644
421 KB
doc/_navbar.md
0 → 100644
| 1 | +<!-- 导航栏 --> | ... | ... |
doc/_sidebar.md
0 → 100644
| 1 | +<!-- 侧边栏 --> | |
| 2 | + | |
| 3 | +* **编译与部署** | |
| 4 | + * [编译](_content/introduction/compile.md) | |
| 5 | + * [配置](_content/introduction/config.md) | |
| 6 | + * [部署](_content/introduction/deployment.md) | |
| 7 | +* **功能与使用** | |
| 8 | + * [接入设备](_content/ability/device.md) | |
| 9 | + * [设备使用](_content/ability/device_use.md) | |
| 10 | + * [国标级联](_content/ability/cascade2.md) | |
| 11 | + * [推流列表](_content/ability/push.md) | |
| 12 | + * [拉流代理](_content/ability/proxy.md) | |
| 13 | + * [电子地图](_content/ability/gis.md) | |
| 14 | + * [节点管理](_content/ability/node_manger.md) | |
| 15 | + * [云端录像](_content/ability/cloud_record.md) | |
| 16 | + * [不间断录像](_content/ability/continuous_recording.md) | |
| 17 | +* **流程与原理** | |
| 18 | + * [统一编码规则](_content/theory/code.md) | |
| 19 | + * [树形结构](_content/theory/channel_tree.md) | |
| 20 | + * [注册流程](_content/theory/register.md) | |
| 21 | + * [点播流程](_content/theory/play.md) | |
| 22 | +* **必备技巧** | |
| 23 | + * [抓包](_content/skill/tcpdump.md) | |
| 24 | + | |
| 25 | +* **常见问答** | |
| 26 | + - [如何反馈BUG](_content/qa/bug.md) | |
| 27 | + - [如何参与开发](_content/qa/development.md) | |
| 28 | + - [启动报错的解决办法](_content/qa/start_error.md) | |
| 29 | + - [设备注册不上来的解决办法](_content/qa/regiser_error.md) | |
| 30 | + - [点播超时/报错的解决办法](_content/qa/play_error.md) | |
| 31 | +* [**免责声明**](_content/disclaimers.md) | |
| 32 | +* [**捐赠**](_content/donation.md) | |
| 33 | +* [**关于本文档**](_content/about_doc.md) | ... | ... |
doc/index.html
0 → 100644
| 1 | +<!DOCTYPE html> | |
| 2 | +<html lang="en"> | |
| 3 | +<head> | |
| 4 | + <meta charset="UTF-8"> | |
| 5 | + <title>WVP-PRO文档</title> | |
| 6 | + <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" /> | |
| 7 | + <meta name="description" content="Description"> | |
| 8 | + <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0"> | |
| 9 | + <link rel="icon" href="_media/favicon.ico" type="image/x-icon" /> | |
| 10 | + <link rel="stylesheet" href="//cdn.jsdelivr.net/npm/docsify@4/lib/themes/vue.css"> | |
| 11 | +<!-- <link rel="stylesheet" href="//cdn.jsdelivr.net/npm/docsify/lib/themes/dark.css">--> | |
| 12 | + <style> | |
| 13 | + .cover{ | |
| 14 | + background: linear-gradient(to left bottom, hsl(82, 100%, 85%) 0%,hsl(199, 100%, 85%) 100%) !important; | |
| 15 | + } | |
| 16 | + </style> | |
| 17 | +</head> | |
| 18 | +<body> | |
| 19 | + <div id="app">加载中</div> | |
| 20 | + <script> | |
| 21 | + window.$docsify = { | |
| 22 | + name: 'WVP-RPO使用文档', | |
| 23 | + repo: 'https://github.com/648540858/wvp-GB28181-pro', | |
| 24 | + loadSidebar: true, // 开启侧边栏 | |
| 25 | + loadNavbar: true, // 开启导航栏 | |
| 26 | + coverpage: true, // 开启封面 | |
| 27 | + | |
| 28 | + subMaxLevel: 3, | |
| 29 | + plantuml: { | |
| 30 | + skin: 'default', | |
| 31 | + }, | |
| 32 | + search: { | |
| 33 | + maxAge: 86400000, // 过期时间,单位毫秒,默认一天 | |
| 34 | + paths: 'auto', // or 'auto' | |
| 35 | + placeholder: '搜索', | |
| 36 | + noData: '找不到结果', | |
| 37 | + // 搜索标题的最大层级, 1 - 6 | |
| 38 | + depth: 4, | |
| 39 | + hideOtherSidebarContent: false, // 是否隐藏其他侧边栏内容 | |
| 40 | + }, | |
| 41 | + copyCode: { | |
| 42 | + buttonText : '复制', | |
| 43 | + errorText : '错误', | |
| 44 | + successText: '已复制' | |
| 45 | + }, | |
| 46 | + // disqus: 'shortname' | |
| 47 | + } | |
| 48 | + </script> | |
| 49 | + <!-- Docsify v4 --> | |
| 50 | + <script src="//cdn.jsdelivr.net/npm/docsify@4"></script> | |
| 51 | + <script src="//unpkg.com/docsify-plantuml/dist/docsify-plantuml.min.js"></script> | |
| 52 | + <script src="//cdn.jsdelivr.net/npm/docsify/lib/plugins/search.min.js"></script> | |
| 53 | + <script src="//cdn.jsdelivr.net/npm/docsify/lib/plugins/zoom-image.min.js"></script> | |
| 54 | + <script src="//cdn.jsdelivr.net/npm/docsify-copy-code/dist/docsify-copy-code.min.js"></script> | |
| 55 | + | |
| 56 | + </script> | |
| 57 | +<!-- <script src="//cdn.jsdelivr.net/npm/docsify/lib/plugins/disqus.min.js"></script>--> | |
| 58 | +</body> | |
| 59 | +</html> | ... | ... |
pom.xml
| ... | ... | @@ -61,6 +61,13 @@ |
| 61 | 61 | <dependency> |
| 62 | 62 | <groupId>org.springframework.boot</groupId> |
| 63 | 63 | <artifactId>spring-boot-starter-data-redis</artifactId> |
| 64 | + <exclusions> | |
| 65 | + <!-- 去掉 Lettuce 的依赖, Spring Boot 优先使用 Lettuce 作为 Redis 客户端 --> | |
| 66 | + <exclusion> | |
| 67 | + <groupId>io.lettuce</groupId> | |
| 68 | + <artifactId>lettuce-core</artifactId> | |
| 69 | + </exclusion> | |
| 70 | + </exclusions> | |
| 64 | 71 | </dependency> |
| 65 | 72 | <dependency> |
| 66 | 73 | <groupId>org.springframework.boot</groupId> |
| ... | ... | @@ -75,6 +82,12 @@ |
| 75 | 82 | <groupId>org.mybatis.spring.boot</groupId> |
| 76 | 83 | <artifactId>mybatis-spring-boot-starter</artifactId> |
| 77 | 84 | <version>2.1.4</version> |
| 85 | + <exclusions> | |
| 86 | + <exclusion> | |
| 87 | + <groupId>com.zaxxer</groupId> | |
| 88 | + <artifactId>HikariCP</artifactId> | |
| 89 | + </exclusion> | |
| 90 | + </exclusions> | |
| 78 | 91 | </dependency> |
| 79 | 92 | <dependency> |
| 80 | 93 | <groupId>org.springframework.boot</groupId> |
| ... | ... | @@ -84,7 +97,6 @@ |
| 84 | 97 | <dependency> |
| 85 | 98 | <groupId>redis.clients</groupId> |
| 86 | 99 | <artifactId>jedis</artifactId> |
| 87 | - <version>${jedis-version}</version> | |
| 88 | 100 | </dependency> |
| 89 | 101 | |
| 90 | 102 | <!-- druid数据库连接池 --> |
| ... | ... | @@ -265,14 +277,14 @@ |
| 265 | 277 | </configuration> |
| 266 | 278 | </plugin> |
| 267 | 279 | |
| 268 | - <plugin> | |
| 280 | + <!-- <plugin> | |
| 269 | 281 | <groupId>pl.project13.maven</groupId> |
| 270 | 282 | <artifactId>git-commit-id-plugin</artifactId> |
| 271 | 283 | <version>3.0.1</version> |
| 272 | 284 | <configuration> |
| 273 | 285 | <offline>true</offline> |
| 274 | 286 | </configuration> |
| 275 | - </plugin> | |
| 287 | + </plugin>--> | |
| 276 | 288 | |
| 277 | 289 | <plugin> |
| 278 | 290 | <groupId>org.apache.maven.plugins</groupId> | ... | ... |
sql/mysql.sql
| ... | ... | @@ -2,55 +2,60 @@ |
| 2 | 2 | -- |
| 3 | 3 | -- Host: 127.0.0.1 Database: wvp2 |
| 4 | 4 | -- ------------------------------------------------------ |
| 5 | --- Server version 8.0.29-0ubuntu0.22.04.2 | |
| 5 | +-- Server version 8.0.29-0ubuntu0.22.04.3 | |
| 6 | 6 | |
| 7 | -/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; | |
| 8 | -/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; | |
| 9 | -/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; | |
| 7 | +/*!40101 SET @OLD_CHARACTER_SET_CLIENT = @@CHARACTER_SET_CLIENT */; | |
| 8 | +/*!40101 SET @OLD_CHARACTER_SET_RESULTS = @@CHARACTER_SET_RESULTS */; | |
| 9 | +/*!40101 SET @OLD_COLLATION_CONNECTION = @@COLLATION_CONNECTION */; | |
| 10 | 10 | /*!50503 SET NAMES utf8mb4 */; |
| 11 | -/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; | |
| 12 | -/*!40103 SET TIME_ZONE='+00:00' */; | |
| 13 | -/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; | |
| 14 | -/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; | |
| 15 | -/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; | |
| 16 | -/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; | |
| 11 | +/*!40103 SET @OLD_TIME_ZONE = @@TIME_ZONE */; | |
| 12 | +/*!40103 SET TIME_ZONE = ' + 00:00' */; | |
| 13 | +/*!40014 SET @OLD_UNIQUE_CHECKS = @@UNIQUE_CHECKS, UNIQUE_CHECKS = 0 */; | |
| 14 | +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS = @@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS = 0 */; | |
| 15 | +/*!40101 SET @OLD_SQL_MODE = @@SQL_MODE, SQL_MODE = 'NO_AUTO_VALUE_ON_ZERO' */; | |
| 16 | +/*!40111 SET @OLD_SQL_NOTES = @@SQL_NOTES, SQL_NOTES = 0 */; | |
| 17 | 17 | |
| 18 | 18 | -- |
| 19 | 19 | -- Table structure for table `device` |
| 20 | 20 | -- |
| 21 | 21 | |
| 22 | 22 | DROP TABLE IF EXISTS `device`; |
| 23 | -/*!40101 SET @saved_cs_client = @@character_set_client */; | |
| 23 | +/*!40101 SET @saved_cs_client = @@character_set_client */; | |
| 24 | 24 | /*!50503 SET character_set_client = utf8mb4 */; |
| 25 | -CREATE TABLE `device` ( | |
| 26 | - `id` int NOT NULL AUTO_INCREMENT, | |
| 27 | - `deviceId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 28 | - `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 29 | - `manufacturer` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 30 | - `model` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 31 | - `firmware` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 32 | - `transport` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 33 | - `streamMode` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 34 | - `online` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 35 | - `registerTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 36 | - `keepaliveTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 37 | - `ip` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 38 | - `createTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 39 | - `updateTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 40 | - `port` int NOT NULL, | |
| 41 | - `expires` int NOT NULL, | |
| 42 | - `subscribeCycleForCatalog` int NOT NULL, | |
| 43 | - `hostAddress` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 44 | - `charset` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 45 | - `subscribeCycleForMobilePosition` int DEFAULT NULL, | |
| 46 | - `mobilePositionSubmissionInterval` int DEFAULT '5', | |
| 47 | - `subscribeCycleForAlarm` int DEFAULT NULL, | |
| 48 | - `ssrcCheck` int DEFAULT '0', | |
| 49 | - `geoCoordSys` varchar(50) COLLATE utf8mb4_general_ci NOT NULL, | |
| 50 | - `treeType` varchar(50) COLLATE utf8mb4_general_ci NOT NULL, | |
| 51 | - PRIMARY KEY (`id`) USING BTREE, | |
| 52 | - UNIQUE KEY `device_deviceId_uindex` (`deviceId`) USING BTREE | |
| 53 | -) ENGINE=InnoDB AUTO_INCREMENT=42 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC; | |
| 25 | +CREATE TABLE `device` | |
| 26 | +( | |
| 27 | + `id` int NOT NULL AUTO_INCREMENT, | |
| 28 | + `deviceId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 29 | + `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 30 | + `manufacturer` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 31 | + `model` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 32 | + `firmware` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 33 | + `transport` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 34 | + `streamMode` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 35 | + `online` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 36 | + `registerTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 37 | + `keepaliveTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 38 | + `ip` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 39 | + `createTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 40 | + `updateTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 41 | + `port` int NOT NULL, | |
| 42 | + `expires` int NOT NULL, | |
| 43 | + `subscribeCycleForCatalog` int NOT NULL, | |
| 44 | + `hostAddress` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 45 | + `charset` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 46 | + `subscribeCycleForMobilePosition` int DEFAULT NULL, | |
| 47 | + `mobilePositionSubmissionInterval` int DEFAULT '5 ', | |
| 48 | + `subscribeCycleForAlarm` int DEFAULT NULL, | |
| 49 | + `ssrcCheck` int DEFAULT '0 ', | |
| 50 | + `geoCoordSys` varchar(50) COLLATE utf8mb4_general_ci NOT NULL, | |
| 51 | + `treeType` varchar(50) COLLATE utf8mb4_general_ci NOT NULL, | |
| 52 | + PRIMARY KEY (`id`) USING BTREE, | |
| 53 | + UNIQUE KEY `device_deviceId_uindex` (`deviceId`) USING BTREE | |
| 54 | +) ENGINE = InnoDB | |
| 55 | + AUTO_INCREMENT = 53 | |
| 56 | + DEFAULT CHARSET = utf8mb4 | |
| 57 | + COLLATE = utf8mb4_general_ci | |
| 58 | + ROW_FORMAT = DYNAMIC; | |
| 54 | 59 | /*!40101 SET character_set_client = @saved_cs_client */; |
| 55 | 60 | |
| 56 | 61 | -- |
| ... | ... | @@ -58,8 +63,10 @@ CREATE TABLE `device` ( |
| 58 | 63 | -- |
| 59 | 64 | |
| 60 | 65 | LOCK TABLES `device` WRITE; |
| 61 | -/*!40000 ALTER TABLE `device` DISABLE KEYS */; | |
| 62 | -/*!40000 ALTER TABLE `device` ENABLE KEYS */; | |
| 66 | +/*!40000 ALTER TABLE `device` | |
| 67 | + DISABLE KEYS */; | |
| 68 | +/*!40000 ALTER TABLE `device` | |
| 69 | + ENABLE KEYS */; | |
| 63 | 70 | UNLOCK TABLES; |
| 64 | 71 | |
| 65 | 72 | -- |
| ... | ... | @@ -67,22 +74,26 @@ UNLOCK TABLES; |
| 67 | 74 | -- |
| 68 | 75 | |
| 69 | 76 | DROP TABLE IF EXISTS `device_alarm`; |
| 70 | -/*!40101 SET @saved_cs_client = @@character_set_client */; | |
| 77 | +/*!40101 SET @saved_cs_client = @@character_set_client */; | |
| 71 | 78 | /*!50503 SET character_set_client = utf8mb4 */; |
| 72 | -CREATE TABLE `device_alarm` ( | |
| 73 | - `id` int NOT NULL AUTO_INCREMENT, | |
| 74 | - `deviceId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 75 | - `channelId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 76 | - `alarmPriority` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 77 | - `alarmMethod` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 78 | - `alarmTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 79 | - `alarmDescription` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 80 | - `longitude` double DEFAULT NULL, | |
| 81 | - `latitude` double DEFAULT NULL, | |
| 82 | - `alarmType` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 83 | - `createTime` varchar(50) COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 84 | - PRIMARY KEY (`id`) USING BTREE | |
| 85 | -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC; | |
| 79 | +CREATE TABLE `device_alarm` | |
| 80 | +( | |
| 81 | + `id` int NOT NULL AUTO_INCREMENT, | |
| 82 | + `deviceId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 83 | + `channelId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 84 | + `alarmPriority` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 85 | + `alarmMethod` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 86 | + `alarmTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 87 | + `alarmDescription` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 88 | + `longitude` double DEFAULT NULL, | |
| 89 | + `latitude` double DEFAULT NULL, | |
| 90 | + `alarmType` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 91 | + `createTime` varchar(50) COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 92 | + PRIMARY KEY (`id`) USING BTREE | |
| 93 | +) ENGINE = InnoDB | |
| 94 | + DEFAULT CHARSET = utf8mb4 | |
| 95 | + COLLATE = utf8mb4_general_ci | |
| 96 | + ROW_FORMAT = DYNAMIC; | |
| 86 | 97 | /*!40101 SET character_set_client = @saved_cs_client */; |
| 87 | 98 | |
| 88 | 99 | -- |
| ... | ... | @@ -90,8 +101,10 @@ CREATE TABLE `device_alarm` ( |
| 90 | 101 | -- |
| 91 | 102 | |
| 92 | 103 | LOCK TABLES `device_alarm` WRITE; |
| 93 | -/*!40000 ALTER TABLE `device_alarm` DISABLE KEYS */; | |
| 94 | -/*!40000 ALTER TABLE `device_alarm` ENABLE KEYS */; | |
| 104 | +/*!40000 ALTER TABLE `device_alarm` | |
| 105 | + DISABLE KEYS */; | |
| 106 | +/*!40000 ALTER TABLE `device_alarm` | |
| 107 | + ENABLE KEYS */; | |
| 95 | 108 | UNLOCK TABLES; |
| 96 | 109 | |
| 97 | 110 | -- |
| ... | ... | @@ -99,50 +112,55 @@ UNLOCK TABLES; |
| 99 | 112 | -- |
| 100 | 113 | |
| 101 | 114 | DROP TABLE IF EXISTS `device_channel`; |
| 102 | -/*!40101 SET @saved_cs_client = @@character_set_client */; | |
| 115 | +/*!40101 SET @saved_cs_client = @@character_set_client */; | |
| 103 | 116 | /*!50503 SET character_set_client = utf8mb4 */; |
| 104 | -CREATE TABLE `device_channel` ( | |
| 105 | - `id` int NOT NULL AUTO_INCREMENT, | |
| 106 | - `channelId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 107 | - `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 108 | - `manufacture` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 109 | - `model` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 110 | - `owner` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 111 | - `civilCode` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 112 | - `block` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 113 | - `address` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 114 | - `parentId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 115 | - `safetyWay` int DEFAULT NULL, | |
| 116 | - `registerWay` int DEFAULT NULL, | |
| 117 | - `certNum` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 118 | - `certifiable` int DEFAULT NULL, | |
| 119 | - `errCode` int DEFAULT NULL, | |
| 120 | - `endTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 121 | - `secrecy` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 122 | - `ipAddress` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 123 | - `port` int DEFAULT NULL, | |
| 124 | - `password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 125 | - `PTZType` int DEFAULT NULL, | |
| 126 | - `status` int DEFAULT NULL, | |
| 127 | - `longitude` double DEFAULT NULL, | |
| 128 | - `latitude` double DEFAULT NULL, | |
| 129 | - `streamId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 130 | - `deviceId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 131 | - `parental` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 132 | - `hasAudio` bit(1) DEFAULT NULL, | |
| 133 | - `createTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 134 | - `updateTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 135 | - `subCount` int DEFAULT '0', | |
| 136 | - `longitudeGcj02` double DEFAULT NULL, | |
| 137 | - `latitudeGcj02` double DEFAULT NULL, | |
| 138 | - `longitudeWgs84` double DEFAULT NULL, | |
| 139 | - `latitudeWgs84` double DEFAULT NULL, | |
| 140 | - `businessGroupId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 141 | - `gpsTime` varchar(50) COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 142 | - PRIMARY KEY (`id`) USING BTREE, | |
| 143 | - UNIQUE KEY `device_channel_id_uindex` (`id`) USING BTREE, | |
| 144 | - UNIQUE KEY `device_channel_pk` (`channelId`,`deviceId`) USING BTREE | |
| 145 | -) ENGINE=InnoDB AUTO_INCREMENT=19331 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC; | |
| 117 | +CREATE TABLE `device_channel` | |
| 118 | +( | |
| 119 | + `id` int NOT NULL AUTO_INCREMENT, | |
| 120 | + `channelId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 121 | + `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 122 | + `manufacture` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 123 | + `model` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 124 | + `owner` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 125 | + `civilCode` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 126 | + `block` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 127 | + `address` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 128 | + `parentId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 129 | + `safetyWay` int DEFAULT NULL, | |
| 130 | + `registerWay` int DEFAULT NULL, | |
| 131 | + `certNum` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 132 | + `certifiable` int DEFAULT NULL, | |
| 133 | + `errCode` int DEFAULT NULL, | |
| 134 | + `endTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 135 | + `secrecy` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 136 | + `ipAddress` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 137 | + `port` int DEFAULT NULL, | |
| 138 | + `password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 139 | + `PTZType` int DEFAULT NULL, | |
| 140 | + `status` int DEFAULT NULL, | |
| 141 | + `longitude` double DEFAULT NULL, | |
| 142 | + `latitude` double DEFAULT NULL, | |
| 143 | + `streamId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 144 | + `deviceId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 145 | + `parental` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 146 | + `hasAudio` bit(1) DEFAULT NULL, | |
| 147 | + `createTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 148 | + `updateTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 149 | + `subCount` int DEFAULT '0 ', | |
| 150 | + `longitudeGcj02` double DEFAULT NULL, | |
| 151 | + `latitudeGcj02` double DEFAULT NULL, | |
| 152 | + `longitudeWgs84` double DEFAULT NULL, | |
| 153 | + `latitudeWgs84` double DEFAULT NULL, | |
| 154 | + `businessGroupId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 155 | + `gpsTime` varchar(50) COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 156 | + PRIMARY KEY (`id`) USING BTREE, | |
| 157 | + UNIQUE KEY `device_channel_id_uindex` (`id`) USING BTREE, | |
| 158 | + UNIQUE KEY `device_channel_pk` (`channelId`, `deviceId`) USING BTREE | |
| 159 | +) ENGINE = InnoDB | |
| 160 | + AUTO_INCREMENT = 19496 | |
| 161 | + DEFAULT CHARSET = utf8mb4 | |
| 162 | + COLLATE = utf8mb4_general_ci | |
| 163 | + ROW_FORMAT = DYNAMIC; | |
| 146 | 164 | /*!40101 SET character_set_client = @saved_cs_client */; |
| 147 | 165 | |
| 148 | 166 | -- |
| ... | ... | @@ -150,8 +168,10 @@ CREATE TABLE `device_channel` ( |
| 150 | 168 | -- |
| 151 | 169 | |
| 152 | 170 | LOCK TABLES `device_channel` WRITE; |
| 153 | -/*!40000 ALTER TABLE `device_channel` DISABLE KEYS */; | |
| 154 | -/*!40000 ALTER TABLE `device_channel` ENABLE KEYS */; | |
| 171 | +/*!40000 ALTER TABLE `device_channel` | |
| 172 | + DISABLE KEYS */; | |
| 173 | +/*!40000 ALTER TABLE `device_channel` | |
| 174 | + ENABLE KEYS */; | |
| 155 | 175 | UNLOCK TABLES; |
| 156 | 176 | |
| 157 | 177 | -- |
| ... | ... | @@ -159,27 +179,32 @@ UNLOCK TABLES; |
| 159 | 179 | -- |
| 160 | 180 | |
| 161 | 181 | DROP TABLE IF EXISTS `device_mobile_position`; |
| 162 | -/*!40101 SET @saved_cs_client = @@character_set_client */; | |
| 182 | +/*!40101 SET @saved_cs_client = @@character_set_client */; | |
| 163 | 183 | /*!50503 SET character_set_client = utf8mb4 */; |
| 164 | -CREATE TABLE `device_mobile_position` ( | |
| 165 | - `id` int NOT NULL AUTO_INCREMENT, | |
| 166 | - `deviceId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 167 | - `channelId` varchar(50) COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 168 | - `deviceName` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 169 | - `time` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 170 | - `longitude` double NOT NULL, | |
| 171 | - `latitude` double NOT NULL, | |
| 172 | - `altitude` double DEFAULT NULL, | |
| 173 | - `speed` double DEFAULT NULL, | |
| 174 | - `direction` double DEFAULT NULL, | |
| 175 | - `reportSource` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 176 | - `longitudeGcj02` double DEFAULT NULL, | |
| 177 | - `latitudeGcj02` double DEFAULT NULL, | |
| 178 | - `longitudeWgs84` double DEFAULT NULL, | |
| 179 | - `latitudeWgs84` double DEFAULT NULL, | |
| 180 | - `createTime` varchar(50) COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 181 | - PRIMARY KEY (`id`) USING BTREE | |
| 182 | -) ENGINE=InnoDB AUTO_INCREMENT=6751 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC; | |
| 184 | +CREATE TABLE `device_mobile_position` | |
| 185 | +( | |
| 186 | + `id` int NOT NULL AUTO_INCREMENT, | |
| 187 | + `deviceId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 188 | + `channelId` varchar(50) COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 189 | + `deviceName` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 190 | + `time` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 191 | + `longitude` double NOT NULL, | |
| 192 | + `latitude` double NOT NULL, | |
| 193 | + `altitude` double DEFAULT NULL, | |
| 194 | + `speed` double DEFAULT NULL, | |
| 195 | + `direction` double DEFAULT NULL, | |
| 196 | + `reportSource` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 197 | + `longitudeGcj02` double DEFAULT NULL, | |
| 198 | + `latitudeGcj02` double DEFAULT NULL, | |
| 199 | + `longitudeWgs84` double DEFAULT NULL, | |
| 200 | + `latitudeWgs84` double DEFAULT NULL, | |
| 201 | + `createTime` varchar(50) COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 202 | + PRIMARY KEY (`id`) USING BTREE | |
| 203 | +) ENGINE = InnoDB | |
| 204 | + AUTO_INCREMENT = 6956 | |
| 205 | + DEFAULT CHARSET = utf8mb4 | |
| 206 | + COLLATE = utf8mb4_general_ci | |
| 207 | + ROW_FORMAT = DYNAMIC; | |
| 183 | 208 | /*!40101 SET character_set_client = @saved_cs_client */; |
| 184 | 209 | |
| 185 | 210 | -- |
| ... | ... | @@ -187,8 +212,10 @@ CREATE TABLE `device_mobile_position` ( |
| 187 | 212 | -- |
| 188 | 213 | |
| 189 | 214 | LOCK TABLES `device_mobile_position` WRITE; |
| 190 | -/*!40000 ALTER TABLE `device_mobile_position` DISABLE KEYS */; | |
| 191 | -/*!40000 ALTER TABLE `device_mobile_position` ENABLE KEYS */; | |
| 215 | +/*!40000 ALTER TABLE `device_mobile_position` | |
| 216 | + DISABLE KEYS */; | |
| 217 | +/*!40000 ALTER TABLE `device_mobile_position` | |
| 218 | + ENABLE KEYS */; | |
| 192 | 219 | UNLOCK TABLES; |
| 193 | 220 | |
| 194 | 221 | -- |
| ... | ... | @@ -196,24 +223,29 @@ UNLOCK TABLES; |
| 196 | 223 | -- |
| 197 | 224 | |
| 198 | 225 | DROP TABLE IF EXISTS `gb_stream`; |
| 199 | -/*!40101 SET @saved_cs_client = @@character_set_client */; | |
| 226 | +/*!40101 SET @saved_cs_client = @@character_set_client */; | |
| 200 | 227 | /*!50503 SET character_set_client = utf8mb4 */; |
| 201 | -CREATE TABLE `gb_stream` ( | |
| 202 | - `gbStreamId` int NOT NULL AUTO_INCREMENT, | |
| 203 | - `app` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 204 | - `stream` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 205 | - `gbId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 206 | - `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 207 | - `longitude` double DEFAULT NULL, | |
| 208 | - `latitude` double DEFAULT NULL, | |
| 209 | - `streamType` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 210 | - `mediaServerId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 211 | - `createTime` varchar(50) COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 212 | - `gpsTime` varchar(50) COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 213 | - PRIMARY KEY (`gbStreamId`) USING BTREE, | |
| 214 | - UNIQUE KEY `app` (`app`,`stream`) USING BTREE, | |
| 215 | - UNIQUE KEY `gbId` (`gbId`) USING BTREE | |
| 216 | -) ENGINE=InnoDB AUTO_INCREMENT=301681 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC; | |
| 228 | +CREATE TABLE `gb_stream` | |
| 229 | +( | |
| 230 | + `gbStreamId` int NOT NULL AUTO_INCREMENT, | |
| 231 | + `app` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 232 | + `stream` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 233 | + `gbId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 234 | + `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 235 | + `longitude` double DEFAULT NULL, | |
| 236 | + `latitude` double DEFAULT NULL, | |
| 237 | + `streamType` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 238 | + `mediaServerId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 239 | + `createTime` varchar(50) COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 240 | + `gpsTime` varchar(50) COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 241 | + PRIMARY KEY (`gbStreamId`) USING BTREE, | |
| 242 | + UNIQUE KEY `app` (`app`, `stream`) USING BTREE, | |
| 243 | + UNIQUE KEY `gbId` (`gbId`) USING BTREE | |
| 244 | +) ENGINE = InnoDB | |
| 245 | + AUTO_INCREMENT = 301754 | |
| 246 | + DEFAULT CHARSET = utf8mb4 | |
| 247 | + COLLATE = utf8mb4_general_ci | |
| 248 | + ROW_FORMAT = DYNAMIC; | |
| 217 | 249 | /*!40101 SET character_set_client = @saved_cs_client */; |
| 218 | 250 | |
| 219 | 251 | -- |
| ... | ... | @@ -221,8 +253,10 @@ CREATE TABLE `gb_stream` ( |
| 221 | 253 | -- |
| 222 | 254 | |
| 223 | 255 | LOCK TABLES `gb_stream` WRITE; |
| 224 | -/*!40000 ALTER TABLE `gb_stream` DISABLE KEYS */; | |
| 225 | -/*!40000 ALTER TABLE `gb_stream` ENABLE KEYS */; | |
| 256 | +/*!40000 ALTER TABLE `gb_stream` | |
| 257 | + DISABLE KEYS */; | |
| 258 | +/*!40000 ALTER TABLE `gb_stream` | |
| 259 | + ENABLE KEYS */; | |
| 226 | 260 | UNLOCK TABLES; |
| 227 | 261 | |
| 228 | 262 | -- |
| ... | ... | @@ -230,20 +264,25 @@ UNLOCK TABLES; |
| 230 | 264 | -- |
| 231 | 265 | |
| 232 | 266 | DROP TABLE IF EXISTS `log`; |
| 233 | -/*!40101 SET @saved_cs_client = @@character_set_client */; | |
| 267 | +/*!40101 SET @saved_cs_client = @@character_set_client */; | |
| 234 | 268 | /*!50503 SET character_set_client = utf8mb4 */; |
| 235 | -CREATE TABLE `log` ( | |
| 236 | - `id` int NOT NULL AUTO_INCREMENT, | |
| 237 | - `name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 238 | - `type` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 239 | - `uri` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 240 | - `address` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 241 | - `result` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 242 | - `timing` bigint NOT NULL, | |
| 243 | - `username` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 244 | - `createTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 245 | - PRIMARY KEY (`id`) USING BTREE | |
| 246 | -) ENGINE=InnoDB AUTO_INCREMENT=34997 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC; | |
| 269 | +CREATE TABLE `log` | |
| 270 | +( | |
| 271 | + `id` int NOT NULL AUTO_INCREMENT, | |
| 272 | + `name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 273 | + `type` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 274 | + `uri` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 275 | + `address` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 276 | + `result` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 277 | + `timing` bigint NOT NULL, | |
| 278 | + `username` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 279 | + `createTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 280 | + PRIMARY KEY (`id`) USING BTREE | |
| 281 | +) ENGINE = InnoDB | |
| 282 | + AUTO_INCREMENT = 42703 | |
| 283 | + DEFAULT CHARSET = utf8mb4 | |
| 284 | + COLLATE = utf8mb4_general_ci | |
| 285 | + ROW_FORMAT = DYNAMIC; | |
| 247 | 286 | /*!40101 SET character_set_client = @saved_cs_client */; |
| 248 | 287 | |
| 249 | 288 | -- |
| ... | ... | @@ -251,8 +290,10 @@ CREATE TABLE `log` ( |
| 251 | 290 | -- |
| 252 | 291 | |
| 253 | 292 | LOCK TABLES `log` WRITE; |
| 254 | -/*!40000 ALTER TABLE `log` DISABLE KEYS */; | |
| 255 | -/*!40000 ALTER TABLE `log` ENABLE KEYS */; | |
| 293 | +/*!40000 ALTER TABLE `log` | |
| 294 | + DISABLE KEYS */; | |
| 295 | +/*!40000 ALTER TABLE `log` | |
| 296 | + ENABLE KEYS */; | |
| 256 | 297 | UNLOCK TABLES; |
| 257 | 298 | |
| 258 | 299 | -- |
| ... | ... | @@ -260,35 +301,39 @@ UNLOCK TABLES; |
| 260 | 301 | -- |
| 261 | 302 | |
| 262 | 303 | DROP TABLE IF EXISTS `media_server`; |
| 263 | -/*!40101 SET @saved_cs_client = @@character_set_client */; | |
| 304 | +/*!40101 SET @saved_cs_client = @@character_set_client */; | |
| 264 | 305 | /*!50503 SET character_set_client = utf8mb4 */; |
| 265 | -CREATE TABLE `media_server` ( | |
| 266 | - `id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 267 | - `ip` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 268 | - `hookIp` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 269 | - `sdpIp` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 270 | - `streamIp` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 271 | - `httpPort` int NOT NULL, | |
| 272 | - `httpSSlPort` int NOT NULL, | |
| 273 | - `rtmpPort` int NOT NULL, | |
| 274 | - `rtmpSSlPort` int NOT NULL, | |
| 275 | - `rtpProxyPort` int NOT NULL, | |
| 276 | - `rtspPort` int NOT NULL, | |
| 277 | - `rtspSSLPort` int NOT NULL, | |
| 278 | - `autoConfig` int NOT NULL, | |
| 279 | - `secret` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 280 | - `streamNoneReaderDelayMS` int NOT NULL, | |
| 281 | - `rtpEnable` int NOT NULL, | |
| 282 | - `rtpPortRange` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 283 | - `sendRtpPortRange` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 284 | - `recordAssistPort` int NOT NULL, | |
| 285 | - `defaultServer` int NOT NULL, | |
| 286 | - `createTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 287 | - `updateTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 288 | - `hookAliveInterval` int NOT NULL, | |
| 289 | - PRIMARY KEY (`id`) USING BTREE, | |
| 290 | - UNIQUE KEY `media_server_i` (`ip`,`httpPort`) USING BTREE | |
| 291 | -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC; | |
| 306 | +CREATE TABLE `media_server` | |
| 307 | +( | |
| 308 | + `id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 309 | + `ip` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 310 | + `hookIp` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 311 | + `sdpIp` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 312 | + `streamIp` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 313 | + `httpPort` int NOT NULL, | |
| 314 | + `httpSSlPort` int NOT NULL, | |
| 315 | + `rtmpPort` int NOT NULL, | |
| 316 | + `rtmpSSlPort` int NOT NULL, | |
| 317 | + `rtpProxyPort` int NOT NULL, | |
| 318 | + `rtspPort` int NOT NULL, | |
| 319 | + `rtspSSLPort` int NOT NULL, | |
| 320 | + `autoConfig` int NOT NULL, | |
| 321 | + `secret` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 322 | + `streamNoneReaderDelayMS` int NOT NULL, | |
| 323 | + `rtpEnable` int NOT NULL, | |
| 324 | + `rtpPortRange` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 325 | + `sendRtpPortRange` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 326 | + `recordAssistPort` int NOT NULL, | |
| 327 | + `defaultServer` int NOT NULL, | |
| 328 | + `createTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 329 | + `updateTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 330 | + `hookAliveInterval` int NOT NULL, | |
| 331 | + PRIMARY KEY (`id`) USING BTREE, | |
| 332 | + UNIQUE KEY `media_server_i` (`ip`, `httpPort`) USING BTREE | |
| 333 | +) ENGINE = InnoDB | |
| 334 | + DEFAULT CHARSET = utf8mb4 | |
| 335 | + COLLATE = utf8mb4_general_ci | |
| 336 | + ROW_FORMAT = DYNAMIC; | |
| 292 | 337 | /*!40101 SET character_set_client = @saved_cs_client */; |
| 293 | 338 | |
| 294 | 339 | -- |
| ... | ... | @@ -296,8 +341,10 @@ CREATE TABLE `media_server` ( |
| 296 | 341 | -- |
| 297 | 342 | |
| 298 | 343 | LOCK TABLES `media_server` WRITE; |
| 299 | -/*!40000 ALTER TABLE `media_server` DISABLE KEYS */; | |
| 300 | -/*!40000 ALTER TABLE `media_server` ENABLE KEYS */; | |
| 344 | +/*!40000 ALTER TABLE `media_server` | |
| 345 | + DISABLE KEYS */; | |
| 346 | +/*!40000 ALTER TABLE `media_server` | |
| 347 | + ENABLE KEYS */; | |
| 301 | 348 | UNLOCK TABLES; |
| 302 | 349 | |
| 303 | 350 | -- |
| ... | ... | @@ -305,39 +352,44 @@ UNLOCK TABLES; |
| 305 | 352 | -- |
| 306 | 353 | |
| 307 | 354 | DROP TABLE IF EXISTS `parent_platform`; |
| 308 | -/*!40101 SET @saved_cs_client = @@character_set_client */; | |
| 355 | +/*!40101 SET @saved_cs_client = @@character_set_client */; | |
| 309 | 356 | /*!50503 SET character_set_client = utf8mb4 */; |
| 310 | -CREATE TABLE `parent_platform` ( | |
| 311 | - `id` int NOT NULL AUTO_INCREMENT, | |
| 312 | - `enable` int DEFAULT NULL, | |
| 313 | - `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 314 | - `serverGBId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 315 | - `serverGBDomain` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 316 | - `serverIP` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 317 | - `serverPort` int DEFAULT NULL, | |
| 318 | - `deviceGBId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 319 | - `deviceIp` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 320 | - `devicePort` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 321 | - `username` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 322 | - `password` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 323 | - `expires` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 324 | - `keepTimeout` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 325 | - `transport` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 326 | - `characterSet` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 327 | - `catalogId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 328 | - `ptz` int DEFAULT NULL, | |
| 329 | - `rtcp` int DEFAULT NULL, | |
| 330 | - `status` bit(1) DEFAULT NULL, | |
| 331 | - `shareAllLiveStream` int DEFAULT NULL, | |
| 332 | - `startOfflinePush` int DEFAULT '0', | |
| 333 | - `administrativeDivision` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 334 | - `catalogGroup` int DEFAULT '1', | |
| 335 | - `createTime` varchar(50) COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 336 | - `updateTime` varchar(50) COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 337 | - PRIMARY KEY (`id`) USING BTREE, | |
| 338 | - UNIQUE KEY `parent_platform_id_uindex` (`id`) USING BTREE, | |
| 339 | - UNIQUE KEY `parent_platform_pk` (`serverGBId`) USING BTREE | |
| 340 | -) ENGINE=InnoDB AUTO_INCREMENT=33 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC; | |
| 357 | +CREATE TABLE `parent_platform` | |
| 358 | +( | |
| 359 | + `id` int NOT NULL AUTO_INCREMENT, | |
| 360 | + `enable` int DEFAULT NULL, | |
| 361 | + `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 362 | + `serverGBId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 363 | + `serverGBDomain` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 364 | + `serverIP` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 365 | + `serverPort` int DEFAULT NULL, | |
| 366 | + `deviceGBId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 367 | + `deviceIp` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 368 | + `devicePort` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 369 | + `username` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 370 | + `password` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 371 | + `expires` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 372 | + `keepTimeout` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 373 | + `transport` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 374 | + `characterSet` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 375 | + `catalogId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 376 | + `ptz` int DEFAULT NULL, | |
| 377 | + `rtcp` int DEFAULT NULL, | |
| 378 | + `status` bit(1) DEFAULT NULL, | |
| 379 | + `startOfflinePush` int DEFAULT '0 ', | |
| 380 | + `administrativeDivision` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 381 | + `catalogGroup` int DEFAULT '1 ', | |
| 382 | + `createTime` varchar(50) COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 383 | + `updateTime` varchar(50) COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 384 | + `treeType` varchar(50) COLLATE utf8mb4_general_ci NOT NULL, | |
| 385 | + PRIMARY KEY (`id`) USING BTREE, | |
| 386 | + UNIQUE KEY `parent_platform_id_uindex` (`id`) USING BTREE, | |
| 387 | + UNIQUE KEY `parent_platform_pk` (`serverGBId`) USING BTREE | |
| 388 | +) ENGINE = InnoDB | |
| 389 | + AUTO_INCREMENT = 40 | |
| 390 | + DEFAULT CHARSET = utf8mb4 | |
| 391 | + COLLATE = utf8mb4_general_ci | |
| 392 | + ROW_FORMAT = DYNAMIC; | |
| 341 | 393 | /*!40101 SET character_set_client = @saved_cs_client */; |
| 342 | 394 | |
| 343 | 395 | -- |
| ... | ... | @@ -345,8 +397,10 @@ CREATE TABLE `parent_platform` ( |
| 345 | 397 | -- |
| 346 | 398 | |
| 347 | 399 | LOCK TABLES `parent_platform` WRITE; |
| 348 | -/*!40000 ALTER TABLE `parent_platform` DISABLE KEYS */; | |
| 349 | -/*!40000 ALTER TABLE `parent_platform` ENABLE KEYS */; | |
| 400 | +/*!40000 ALTER TABLE `parent_platform` | |
| 401 | + DISABLE KEYS */; | |
| 402 | +/*!40000 ALTER TABLE `parent_platform` | |
| 403 | + ENABLE KEYS */; | |
| 350 | 404 | UNLOCK TABLES; |
| 351 | 405 | |
| 352 | 406 | -- |
| ... | ... | @@ -354,15 +408,21 @@ UNLOCK TABLES; |
| 354 | 408 | -- |
| 355 | 409 | |
| 356 | 410 | DROP TABLE IF EXISTS `platform_catalog`; |
| 357 | -/*!40101 SET @saved_cs_client = @@character_set_client */; | |
| 411 | +/*!40101 SET @saved_cs_client = @@character_set_client */; | |
| 358 | 412 | /*!50503 SET character_set_client = utf8mb4 */; |
| 359 | -CREATE TABLE `platform_catalog` ( | |
| 360 | - `id` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 361 | - `platformId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 362 | - `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 363 | - `parentId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 364 | - PRIMARY KEY (`id`) USING BTREE | |
| 365 | -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC; | |
| 413 | +CREATE TABLE `platform_catalog` | |
| 414 | +( | |
| 415 | + `id` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 416 | + `platformId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 417 | + `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 418 | + `parentId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 419 | + `civilCode` varchar(50) COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 420 | + `businessGroupId` varchar(50) COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 421 | + PRIMARY KEY (`id`) USING BTREE | |
| 422 | +) ENGINE = InnoDB | |
| 423 | + DEFAULT CHARSET = utf8mb4 | |
| 424 | + COLLATE = utf8mb4_general_ci | |
| 425 | + ROW_FORMAT = DYNAMIC; | |
| 366 | 426 | /*!40101 SET character_set_client = @saved_cs_client */; |
| 367 | 427 | |
| 368 | 428 | -- |
| ... | ... | @@ -370,8 +430,10 @@ CREATE TABLE `platform_catalog` ( |
| 370 | 430 | -- |
| 371 | 431 | |
| 372 | 432 | LOCK TABLES `platform_catalog` WRITE; |
| 373 | -/*!40000 ALTER TABLE `platform_catalog` DISABLE KEYS */; | |
| 374 | -/*!40000 ALTER TABLE `platform_catalog` ENABLE KEYS */; | |
| 433 | +/*!40000 ALTER TABLE `platform_catalog` | |
| 434 | + DISABLE KEYS */; | |
| 435 | +/*!40000 ALTER TABLE `platform_catalog` | |
| 436 | + ENABLE KEYS */; | |
| 375 | 437 | UNLOCK TABLES; |
| 376 | 438 | |
| 377 | 439 | -- |
| ... | ... | @@ -379,15 +441,20 @@ UNLOCK TABLES; |
| 379 | 441 | -- |
| 380 | 442 | |
| 381 | 443 | DROP TABLE IF EXISTS `platform_gb_channel`; |
| 382 | -/*!40101 SET @saved_cs_client = @@character_set_client */; | |
| 444 | +/*!40101 SET @saved_cs_client = @@character_set_client */; | |
| 383 | 445 | /*!50503 SET character_set_client = utf8mb4 */; |
| 384 | -CREATE TABLE `platform_gb_channel` ( | |
| 385 | - `id` int NOT NULL AUTO_INCREMENT, | |
| 386 | - `platformId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 387 | - `catalogId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 388 | - `deviceChannelId` int NOT NULL, | |
| 389 | - PRIMARY KEY (`id`) USING BTREE | |
| 390 | -) ENGINE=InnoDB AUTO_INCREMENT=4889 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC; | |
| 446 | +CREATE TABLE `platform_gb_channel` | |
| 447 | +( | |
| 448 | + `id` int NOT NULL AUTO_INCREMENT, | |
| 449 | + `platformId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 450 | + `catalogId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 451 | + `deviceChannelId` int NOT NULL, | |
| 452 | + PRIMARY KEY (`id`) USING BTREE | |
| 453 | +) ENGINE = InnoDB | |
| 454 | + AUTO_INCREMENT = 4915 | |
| 455 | + DEFAULT CHARSET = utf8mb4 | |
| 456 | + COLLATE = utf8mb4_general_ci | |
| 457 | + ROW_FORMAT = DYNAMIC; | |
| 391 | 458 | /*!40101 SET character_set_client = @saved_cs_client */; |
| 392 | 459 | |
| 393 | 460 | -- |
| ... | ... | @@ -395,8 +462,10 @@ CREATE TABLE `platform_gb_channel` ( |
| 395 | 462 | -- |
| 396 | 463 | |
| 397 | 464 | LOCK TABLES `platform_gb_channel` WRITE; |
| 398 | -/*!40000 ALTER TABLE `platform_gb_channel` DISABLE KEYS */; | |
| 399 | -/*!40000 ALTER TABLE `platform_gb_channel` ENABLE KEYS */; | |
| 465 | +/*!40000 ALTER TABLE `platform_gb_channel` | |
| 466 | + DISABLE KEYS */; | |
| 467 | +/*!40000 ALTER TABLE `platform_gb_channel` | |
| 468 | + ENABLE KEYS */; | |
| 400 | 469 | UNLOCK TABLES; |
| 401 | 470 | |
| 402 | 471 | -- |
| ... | ... | @@ -404,16 +473,21 @@ UNLOCK TABLES; |
| 404 | 473 | -- |
| 405 | 474 | |
| 406 | 475 | DROP TABLE IF EXISTS `platform_gb_stream`; |
| 407 | -/*!40101 SET @saved_cs_client = @@character_set_client */; | |
| 476 | +/*!40101 SET @saved_cs_client = @@character_set_client */; | |
| 408 | 477 | /*!50503 SET character_set_client = utf8mb4 */; |
| 409 | -CREATE TABLE `platform_gb_stream` ( | |
| 410 | - `platformId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 411 | - `catalogId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 412 | - `gbStreamId` int NOT NULL, | |
| 413 | - `id` int NOT NULL AUTO_INCREMENT, | |
| 414 | - PRIMARY KEY (`id`) USING BTREE, | |
| 415 | - UNIQUE KEY `platform_gb_stream_pk` (`platformId`,`catalogId`,`gbStreamId`) USING BTREE | |
| 416 | -) ENGINE=InnoDB AUTO_INCREMENT=302077 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC; | |
| 478 | +CREATE TABLE `platform_gb_stream` | |
| 479 | +( | |
| 480 | + `platformId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 481 | + `catalogId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 482 | + `gbStreamId` int NOT NULL, | |
| 483 | + `id` int NOT NULL AUTO_INCREMENT, | |
| 484 | + PRIMARY KEY (`id`) USING BTREE, | |
| 485 | + UNIQUE KEY `platform_gb_stream_pk` (`platformId`, `catalogId`, `gbStreamId`) USING BTREE | |
| 486 | +) ENGINE = InnoDB | |
| 487 | + AUTO_INCREMENT = 302149 | |
| 488 | + DEFAULT CHARSET = utf8mb4 | |
| 489 | + COLLATE = utf8mb4_general_ci | |
| 490 | + ROW_FORMAT = DYNAMIC; | |
| 417 | 491 | /*!40101 SET character_set_client = @saved_cs_client */; |
| 418 | 492 | |
| 419 | 493 | -- |
| ... | ... | @@ -421,8 +495,10 @@ CREATE TABLE `platform_gb_stream` ( |
| 421 | 495 | -- |
| 422 | 496 | |
| 423 | 497 | LOCK TABLES `platform_gb_stream` WRITE; |
| 424 | -/*!40000 ALTER TABLE `platform_gb_stream` DISABLE KEYS */; | |
| 425 | -/*!40000 ALTER TABLE `platform_gb_stream` ENABLE KEYS */; | |
| 498 | +/*!40000 ALTER TABLE `platform_gb_stream` | |
| 499 | + DISABLE KEYS */; | |
| 500 | +/*!40000 ALTER TABLE `platform_gb_stream` | |
| 501 | + ENABLE KEYS */; | |
| 426 | 502 | UNLOCK TABLES; |
| 427 | 503 | |
| 428 | 504 | -- |
| ... | ... | @@ -430,31 +506,36 @@ UNLOCK TABLES; |
| 430 | 506 | -- |
| 431 | 507 | |
| 432 | 508 | DROP TABLE IF EXISTS `stream_proxy`; |
| 433 | -/*!40101 SET @saved_cs_client = @@character_set_client */; | |
| 509 | +/*!40101 SET @saved_cs_client = @@character_set_client */; | |
| 434 | 510 | /*!50503 SET character_set_client = utf8mb4 */; |
| 435 | -CREATE TABLE `stream_proxy` ( | |
| 436 | - `id` int NOT NULL AUTO_INCREMENT, | |
| 437 | - `type` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 438 | - `app` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 439 | - `stream` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 440 | - `url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 441 | - `src_url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 442 | - `dst_url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 443 | - `timeout_ms` int DEFAULT NULL, | |
| 444 | - `ffmpeg_cmd_key` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 445 | - `rtp_type` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 446 | - `mediaServerId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 447 | - `enable_hls` bit(1) DEFAULT NULL, | |
| 448 | - `enable_mp4` bit(1) DEFAULT NULL, | |
| 449 | - `enable` bit(1) NOT NULL, | |
| 450 | - `status` bit(1) NOT NULL, | |
| 451 | - `enable_remove_none_reader` bit(1) NOT NULL, | |
| 452 | - `createTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 453 | - `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 454 | - `updateTime` varchar(50) COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 455 | - PRIMARY KEY (`id`) USING BTREE, | |
| 456 | - UNIQUE KEY `stream_proxy_pk` (`app`,`stream`) USING BTREE | |
| 457 | -) ENGINE=InnoDB AUTO_INCREMENT=66 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC; | |
| 511 | +CREATE TABLE `stream_proxy` | |
| 512 | +( | |
| 513 | + `id` int NOT NULL AUTO_INCREMENT, | |
| 514 | + `type` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 515 | + `app` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 516 | + `stream` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 517 | + `url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 518 | + `src_url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 519 | + `dst_url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 520 | + `timeout_ms` int DEFAULT NULL, | |
| 521 | + `ffmpeg_cmd_key` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 522 | + `rtp_type` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 523 | + `mediaServerId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 524 | + `enable_hls` bit(1) DEFAULT NULL, | |
| 525 | + `enable_mp4` bit(1) DEFAULT NULL, | |
| 526 | + `enable` bit(1) NOT NULL, | |
| 527 | + `status` bit(1) NOT NULL, | |
| 528 | + `enable_remove_none_reader` bit(1) NOT NULL, | |
| 529 | + `createTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 530 | + `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 531 | + `updateTime` varchar(50) COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 532 | + PRIMARY KEY (`id`) USING BTREE, | |
| 533 | + UNIQUE KEY `stream_proxy_pk` (`app`, `stream`) USING BTREE | |
| 534 | +) ENGINE = InnoDB | |
| 535 | + AUTO_INCREMENT = 66 | |
| 536 | + DEFAULT CHARSET = utf8mb4 | |
| 537 | + COLLATE = utf8mb4_general_ci | |
| 538 | + ROW_FORMAT = DYNAMIC; | |
| 458 | 539 | /*!40101 SET character_set_client = @saved_cs_client */; |
| 459 | 540 | |
| 460 | 541 | -- |
| ... | ... | @@ -462,8 +543,10 @@ CREATE TABLE `stream_proxy` ( |
| 462 | 543 | -- |
| 463 | 544 | |
| 464 | 545 | LOCK TABLES `stream_proxy` WRITE; |
| 465 | -/*!40000 ALTER TABLE `stream_proxy` DISABLE KEYS */; | |
| 466 | -/*!40000 ALTER TABLE `stream_proxy` ENABLE KEYS */; | |
| 546 | +/*!40000 ALTER TABLE `stream_proxy` | |
| 547 | + DISABLE KEYS */; | |
| 548 | +/*!40000 ALTER TABLE `stream_proxy` | |
| 549 | + ENABLE KEYS */; | |
| 467 | 550 | UNLOCK TABLES; |
| 468 | 551 | |
| 469 | 552 | -- |
| ... | ... | @@ -471,25 +554,32 @@ UNLOCK TABLES; |
| 471 | 554 | -- |
| 472 | 555 | |
| 473 | 556 | DROP TABLE IF EXISTS `stream_push`; |
| 474 | -/*!40101 SET @saved_cs_client = @@character_set_client */; | |
| 557 | +/*!40101 SET @saved_cs_client = @@character_set_client */; | |
| 475 | 558 | /*!50503 SET character_set_client = utf8mb4 */; |
| 476 | -CREATE TABLE `stream_push` ( | |
| 477 | - `id` int NOT NULL AUTO_INCREMENT, | |
| 478 | - `app` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 479 | - `stream` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 480 | - `totalReaderCount` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 481 | - `originType` int DEFAULT NULL, | |
| 482 | - `originTypeStr` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 483 | - `createTime` varchar(50) COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 484 | - `aliveSecond` int DEFAULT NULL, | |
| 485 | - `mediaServerId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 486 | - `serverId` varchar(50) COLLATE utf8mb4_general_ci NOT NULL, | |
| 487 | - `pushTime` varchar(50) COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 488 | - `updateTime` varchar(50) COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 489 | - `status` int DEFAULT NULL, | |
| 490 | - PRIMARY KEY (`id`) USING BTREE, | |
| 491 | - UNIQUE KEY `stream_push_pk` (`app`,`stream`) USING BTREE | |
| 492 | -) ENGINE=InnoDB AUTO_INCREMENT=305315 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC; | |
| 559 | +CREATE TABLE `stream_push` | |
| 560 | +( | |
| 561 | + `id` int NOT NULL AUTO_INCREMENT, | |
| 562 | + `app` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 563 | + `stream` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 564 | + `totalReaderCount` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 565 | + `originType` int DEFAULT NULL, | |
| 566 | + `originTypeStr` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 567 | + `createTime` varchar(50) COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 568 | + `aliveSecond` int DEFAULT NULL, | |
| 569 | + `mediaServerId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 570 | + `serverId` varchar(50) COLLATE utf8mb4_general_ci NOT NULL, | |
| 571 | + `pushTime` varchar(50) COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 572 | + `updateTime` varchar(50) COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 573 | + `status` int DEFAULT NULL, | |
| 574 | + `pushIng` int DEFAULT NULL, | |
| 575 | + `self` int DEFAULT NULL, | |
| 576 | + PRIMARY KEY (`id`) USING BTREE, | |
| 577 | + UNIQUE KEY `stream_push_pk` (`app`, `stream`) USING BTREE | |
| 578 | +) ENGINE = InnoDB | |
| 579 | + AUTO_INCREMENT = 305415 | |
| 580 | + DEFAULT CHARSET = utf8mb4 | |
| 581 | + COLLATE = utf8mb4_general_ci | |
| 582 | + ROW_FORMAT = DYNAMIC; | |
| 493 | 583 | /*!40101 SET character_set_client = @saved_cs_client */; |
| 494 | 584 | |
| 495 | 585 | -- |
| ... | ... | @@ -497,8 +587,10 @@ CREATE TABLE `stream_push` ( |
| 497 | 587 | -- |
| 498 | 588 | |
| 499 | 589 | LOCK TABLES `stream_push` WRITE; |
| 500 | -/*!40000 ALTER TABLE `stream_push` DISABLE KEYS */; | |
| 501 | -/*!40000 ALTER TABLE `stream_push` ENABLE KEYS */; | |
| 590 | +/*!40000 ALTER TABLE `stream_push` | |
| 591 | + DISABLE KEYS */; | |
| 592 | +/*!40000 ALTER TABLE `stream_push` | |
| 593 | + ENABLE KEYS */; | |
| 502 | 594 | UNLOCK TABLES; |
| 503 | 595 | |
| 504 | 596 | -- |
| ... | ... | @@ -506,19 +598,24 @@ UNLOCK TABLES; |
| 506 | 598 | -- |
| 507 | 599 | |
| 508 | 600 | DROP TABLE IF EXISTS `user`; |
| 509 | -/*!40101 SET @saved_cs_client = @@character_set_client */; | |
| 601 | +/*!40101 SET @saved_cs_client = @@character_set_client */; | |
| 510 | 602 | /*!50503 SET character_set_client = utf8mb4 */; |
| 511 | -CREATE TABLE `user` ( | |
| 512 | - `id` int NOT NULL AUTO_INCREMENT, | |
| 513 | - `username` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 514 | - `password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 515 | - `roleId` int NOT NULL, | |
| 516 | - `createTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 517 | - `updateTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 518 | - `pushKey` varchar(50) COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 519 | - PRIMARY KEY (`id`) USING BTREE, | |
| 520 | - UNIQUE KEY `user_username_uindex` (`username`) USING BTREE | |
| 521 | -) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC; | |
| 603 | +CREATE TABLE `user` | |
| 604 | +( | |
| 605 | + `id` int NOT NULL AUTO_INCREMENT, | |
| 606 | + `username` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 607 | + `password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 608 | + `roleId` int NOT NULL, | |
| 609 | + `createTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 610 | + `updateTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 611 | + `pushKey` varchar(50) COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 612 | + PRIMARY KEY (`id`) USING BTREE, | |
| 613 | + UNIQUE KEY `user_username_uindex` (`username`) USING BTREE | |
| 614 | +) ENGINE = InnoDB | |
| 615 | + AUTO_INCREMENT = 2 | |
| 616 | + DEFAULT CHARSET = utf8mb4 | |
| 617 | + COLLATE = utf8mb4_general_ci | |
| 618 | + ROW_FORMAT = DYNAMIC; | |
| 522 | 619 | /*!40101 SET character_set_client = @saved_cs_client */; |
| 523 | 620 | |
| 524 | 621 | -- |
| ... | ... | @@ -526,9 +623,13 @@ CREATE TABLE `user` ( |
| 526 | 623 | -- |
| 527 | 624 | |
| 528 | 625 | LOCK TABLES `user` WRITE; |
| 529 | -/*!40000 ALTER TABLE `user` DISABLE KEYS */; | |
| 530 | -INSERT INTO `user` VALUES (1,'admin','21232f297a57a5a743894a0e4a801fc3',1,'2021 - 04 - 13 14:14:57','2021 - 04 - 13 14:14:57','453df297a57a5a7438934sda801fc3'); | |
| 531 | -/*!40000 ALTER TABLE `user` ENABLE KEYS */; | |
| 626 | +/*!40000 ALTER TABLE `user` | |
| 627 | + DISABLE KEYS */; | |
| 628 | +INSERT INTO `user` | |
| 629 | +VALUES (1, 'admin', '21232f297a57a5a743894a0e4a801fc3', 1, '2021 - 04 - 13 14:14:57', '2021 - 04 - 13 14:14:57', | |
| 630 | + '01685cb9573ae25ec6c52142402da7c5'); | |
| 631 | +/*!40000 ALTER TABLE `user` | |
| 632 | + ENABLE KEYS */; | |
| 532 | 633 | UNLOCK TABLES; |
| 533 | 634 | |
| 534 | 635 | -- |
| ... | ... | @@ -536,16 +637,21 @@ UNLOCK TABLES; |
| 536 | 637 | -- |
| 537 | 638 | |
| 538 | 639 | DROP TABLE IF EXISTS `user_role`; |
| 539 | -/*!40101 SET @saved_cs_client = @@character_set_client */; | |
| 640 | +/*!40101 SET @saved_cs_client = @@character_set_client */; | |
| 540 | 641 | /*!50503 SET character_set_client = utf8mb4 */; |
| 541 | -CREATE TABLE `user_role` ( | |
| 542 | - `id` int NOT NULL AUTO_INCREMENT, | |
| 543 | - `name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 544 | - `authority` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 545 | - `createTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 546 | - `updateTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 547 | - PRIMARY KEY (`id`) USING BTREE | |
| 548 | -) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC; | |
| 642 | +CREATE TABLE `user_role` | |
| 643 | +( | |
| 644 | + `id` int NOT NULL AUTO_INCREMENT, | |
| 645 | + `name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 646 | + `authority` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 647 | + `createTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 648 | + `updateTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 649 | + PRIMARY KEY (`id`) USING BTREE | |
| 650 | +) ENGINE = InnoDB | |
| 651 | + AUTO_INCREMENT = 2 | |
| 652 | + DEFAULT CHARSET = utf8mb4 | |
| 653 | + COLLATE = utf8mb4_general_ci | |
| 654 | + ROW_FORMAT = DYNAMIC; | |
| 549 | 655 | /*!40101 SET character_set_client = @saved_cs_client */; |
| 550 | 656 | |
| 551 | 657 | -- |
| ... | ... | @@ -553,18 +659,21 @@ CREATE TABLE `user_role` ( |
| 553 | 659 | -- |
| 554 | 660 | |
| 555 | 661 | LOCK TABLES `user_role` WRITE; |
| 556 | -/*!40000 ALTER TABLE `user_role` DISABLE KEYS */; | |
| 557 | -INSERT INTO `user_role` VALUES (1,'admin','0','2021-04-13 14:14:57','2021-04-13 14:14:57'); | |
| 558 | -/*!40000 ALTER TABLE `user_role` ENABLE KEYS */; | |
| 662 | +/*!40000 ALTER TABLE `user_role` | |
| 663 | + DISABLE KEYS */; | |
| 664 | +INSERT INTO `user_role` | |
| 665 | +VALUES (1, 'admin', '0 ', '2021 - 04 - 13 14:14:57', '2021 - 04 - 13 14:14:57'); | |
| 666 | +/*!40000 ALTER TABLE `user_role` | |
| 667 | + ENABLE KEYS */; | |
| 559 | 668 | UNLOCK TABLES; |
| 560 | -/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; | |
| 669 | +/*!40103 SET TIME_ZONE = @OLD_TIME_ZONE */; | |
| 561 | 670 | |
| 562 | -/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; | |
| 563 | -/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; | |
| 564 | -/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; | |
| 565 | -/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; | |
| 566 | -/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; | |
| 567 | -/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; | |
| 568 | -/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; | |
| 671 | +/*!40101 SET SQL_MODE = @OLD_SQL_MODE */; | |
| 672 | +/*!40014 SET FOREIGN_KEY_CHECKS = @OLD_FOREIGN_KEY_CHECKS */; | |
| 673 | +/*!40014 SET UNIQUE_CHECKS = @OLD_UNIQUE_CHECKS */; | |
| 674 | +/*!40101 SET CHARACTER_SET_CLIENT = @OLD_CHARACTER_SET_CLIENT */; | |
| 675 | +/*!40101 SET CHARACTER_SET_RESULTS = @OLD_CHARACTER_SET_RESULTS */; | |
| 676 | +/*!40101 SET COLLATION_CONNECTION = @OLD_COLLATION_CONNECTION */; | |
| 677 | +/*!40111 SET SQL_NOTES = @OLD_SQL_NOTES */; | |
| 569 | 678 | |
| 570 | --- Dump completed on 2022-07-11 17:32:51 | |
| 679 | +-- Dump completed on 2022-07-27 14:51:08 | ... | ... |
sql/update.sql
| ... | ... | @@ -71,6 +71,8 @@ alter table stream_push |
| 71 | 71 | alter table stream_push |
| 72 | 72 | add updateTime varchar(50) default null; |
| 73 | 73 | alter table stream_push |
| 74 | + add pushIng int DEFAULT NULL; | |
| 75 | +alter table stream_push | |
| 74 | 76 | change createStamp createTime varchar(50) default null; |
| 75 | 77 | |
| 76 | 78 | alter table gb_stream |
| ... | ... | @@ -78,4 +80,20 @@ alter table gb_stream |
| 78 | 80 | |
| 79 | 81 | alter table user |
| 80 | 82 | add pushKey varchar(50) default null; |
| 83 | +update user set pushKey='453df297a57a5a7438934sda801fc3' where id=1; | |
| 84 | + | |
| 85 | +alter table parent_platform | |
| 86 | + add treeType varchar(50) not null; | |
| 87 | +update parent_platform set parent_platform.treeType='BusinessGroup'; | |
| 88 | +alter table parent_platform drop shareAllLiveStream; | |
| 89 | + | |
| 90 | +alter table platform_catalog | |
| 91 | + add civilCode varchar(50) default null; | |
| 92 | +alter table platform_catalog | |
| 93 | + add businessGroupId varchar(50) default null; | |
| 94 | + | |
| 95 | +/********************* ADD ***************************/ | |
| 96 | +alter table stream_push | |
| 97 | + add self int DEFAULT NULL; | |
| 98 | + | |
| 81 | 99 | ... | ... |
src/main/java/com/genersoft/iot/vmp/VManageBootstrap.java
src/main/java/com/genersoft/iot/vmp/common/VideoManagerConstants.java
| ... | ... | @@ -104,6 +104,10 @@ public class VideoManagerConstants { |
| 104 | 104 | // 设备状态订阅的通知 |
| 105 | 105 | public static final String VM_MSG_SUBSCRIBE_DEVICE_STATUS = "device"; |
| 106 | 106 | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 107 | 111 | //************************** 第三方 **************************************** |
| 108 | 112 | public static final String WVP_STREAM_GB_ID_PREFIX = "memberNo_"; |
| 109 | 113 | public static final String WVP_STREAM_GPS_MSG_PREFIX = "WVP_STREAM_GPS_MSG_"; | ... | ... |
src/main/java/com/genersoft/iot/vmp/conf/RedisConfig.java
| 1 | 1 | package com.genersoft.iot.vmp.conf; |
| 2 | 2 | |
| 3 | 3 | import com.genersoft.iot.vmp.common.VideoManagerConstants; |
| 4 | -import com.genersoft.iot.vmp.service.impl.RedisAlarmMsgListener; | |
| 5 | -import com.genersoft.iot.vmp.service.impl.RedisGpsMsgListener; | |
| 6 | -import com.genersoft.iot.vmp.service.impl.RedisGbPlayMsgListener; | |
| 7 | -import com.genersoft.iot.vmp.service.impl.RedisStreamMsgListener; | |
| 4 | +import com.genersoft.iot.vmp.service.impl.*; | |
| 8 | 5 | import org.apache.commons.lang3.StringUtils; |
| 9 | 6 | import org.springframework.beans.factory.annotation.Autowired; |
| 10 | 7 | import org.springframework.beans.factory.annotation.Value; |
| ... | ... | @@ -60,6 +57,9 @@ public class RedisConfig extends CachingConfigurerSupport { |
| 60 | 57 | @Autowired |
| 61 | 58 | private RedisGbPlayMsgListener redisGbPlayMsgListener; |
| 62 | 59 | |
| 60 | + @Autowired | |
| 61 | + private RedisPushStreamStatusMsgListener redisPushStreamStatusMsgListener; | |
| 62 | + | |
| 63 | 63 | @Bean |
| 64 | 64 | public JedisPool jedisPool() { |
| 65 | 65 | if (StringUtils.isBlank(password)) { |
| ... | ... | @@ -108,6 +108,7 @@ public class RedisConfig extends CachingConfigurerSupport { |
| 108 | 108 | container.addMessageListener(redisAlarmMsgListener, new PatternTopic(VideoManagerConstants.VM_MSG_SUBSCRIBE_ALARM_RECEIVE)); |
| 109 | 109 | container.addMessageListener(redisStreamMsgListener, new PatternTopic(VideoManagerConstants.WVP_MSG_STREAM_CHANGE_PREFIX + "PUSH")); |
| 110 | 110 | container.addMessageListener(redisGbPlayMsgListener, new PatternTopic(RedisGbPlayMsgListener.WVP_PUSH_STREAM_KEY)); |
| 111 | + container.addMessageListener(redisPushStreamStatusMsgListener, new PatternTopic(VideoManagerConstants.VM_MSG_PUSH_STREAM_STATUS_CHANGE)); | |
| 111 | 112 | return container; |
| 112 | 113 | } |
| 113 | 114 | ... | ... |
src/main/java/com/genersoft/iot/vmp/conf/UserSetting.java
src/main/java/com/genersoft/iot/vmp/conf/security/DefaultUserDetailsServiceImpl.java
| 1 | 1 | package com.genersoft.iot.vmp.conf.security; |
| 2 | 2 | |
| 3 | -import com.genersoft.iot.vmp.conf.security.dto.LoginUser; | |
| 4 | -import com.genersoft.iot.vmp.service.IUserService; | |
| 5 | -import com.genersoft.iot.vmp.storager.dao.dto.User; | |
| 6 | -import com.github.xiaoymin.knife4j.core.util.StrUtil; | |
| 3 | +import java.time.LocalDateTime; | |
| 4 | + | |
| 7 | 5 | import org.slf4j.Logger; |
| 8 | 6 | import org.slf4j.LoggerFactory; |
| 9 | 7 | import org.springframework.beans.factory.annotation.Autowired; |
| ... | ... | @@ -12,7 +10,10 @@ import org.springframework.security.core.userdetails.UserDetailsService; |
| 12 | 10 | import org.springframework.security.core.userdetails.UsernameNotFoundException; |
| 13 | 11 | import org.springframework.stereotype.Component; |
| 14 | 12 | |
| 15 | -import java.time.LocalDateTime; | |
| 13 | +import com.alibaba.excel.util.StringUtils; | |
| 14 | +import com.genersoft.iot.vmp.conf.security.dto.LoginUser; | |
| 15 | +import com.genersoft.iot.vmp.service.IUserService; | |
| 16 | +import com.genersoft.iot.vmp.storager.dao.dto.User; | |
| 16 | 17 | |
| 17 | 18 | /** |
| 18 | 19 | * 用户登录认证逻辑 |
| ... | ... | @@ -27,7 +28,7 @@ public class DefaultUserDetailsServiceImpl implements UserDetailsService { |
| 27 | 28 | |
| 28 | 29 | @Override |
| 29 | 30 | public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { |
| 30 | - if (StrUtil.isBlank(username)) { | |
| 31 | + if (StringUtils.isBlank(username)) { | |
| 31 | 32 | logger.info("登录用户:{} 不存在", username); |
| 32 | 33 | throw new UsernameNotFoundException("登录用户:" + username + " 不存在"); |
| 33 | 34 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/bean/CatalogData.java
| ... | ... | @@ -3,8 +3,14 @@ package com.genersoft.iot.vmp.gb28181.bean; |
| 3 | 3 | import java.time.Instant; |
| 4 | 4 | import java.util.List; |
| 5 | 5 | |
| 6 | +/** | |
| 7 | + * @author lin | |
| 8 | + */ | |
| 6 | 9 | public class CatalogData { |
| 7 | - private int sn; // 命令序列号 | |
| 10 | + /** | |
| 11 | + * 命令序列号 | |
| 12 | + */ | |
| 13 | + private int sn; | |
| 8 | 14 | private int total; |
| 9 | 15 | private List<DeviceChannel> channelList; |
| 10 | 16 | private Instant lastTime; | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/bean/ParentPlatform.java
| ... | ... | @@ -105,11 +105,6 @@ public class ParentPlatform { |
| 105 | 105 | private int channelCount; |
| 106 | 106 | |
| 107 | 107 | /** |
| 108 | - * 共享所有的直播流 | |
| 109 | - */ | |
| 110 | - private boolean shareAllLiveStream; | |
| 111 | - | |
| 112 | - /** | |
| 113 | 108 | * 默认目录Id,自动添加的通道多放在这个目录下 |
| 114 | 109 | */ |
| 115 | 110 | private String catalogId; |
| ... | ... | @@ -154,6 +149,11 @@ public class ParentPlatform { |
| 154 | 149 | */ |
| 155 | 150 | private String createTime; |
| 156 | 151 | |
| 152 | + /** | |
| 153 | + * 树类型 国标规定了两种树的展现方式 行政区划 CivilCode 和业务分组:BusinessGroup | |
| 154 | + */ | |
| 155 | + private String treeType; | |
| 156 | + | |
| 157 | 157 | public Integer getId() { |
| 158 | 158 | return id; |
| 159 | 159 | } |
| ... | ... | @@ -314,15 +314,6 @@ public class ParentPlatform { |
| 314 | 314 | this.channelCount = channelCount; |
| 315 | 315 | } |
| 316 | 316 | |
| 317 | - | |
| 318 | - public boolean isShareAllLiveStream() { | |
| 319 | - return shareAllLiveStream; | |
| 320 | - } | |
| 321 | - | |
| 322 | - public void setShareAllLiveStream(boolean shareAllLiveStream) { | |
| 323 | - this.shareAllLiveStream = shareAllLiveStream; | |
| 324 | - } | |
| 325 | - | |
| 326 | 317 | public String getCatalogId() { |
| 327 | 318 | return catalogId; |
| 328 | 319 | } |
| ... | ... | @@ -394,4 +385,12 @@ public class ParentPlatform { |
| 394 | 385 | public void setCreateTime(String createTime) { |
| 395 | 386 | this.createTime = createTime; |
| 396 | 387 | } |
| 388 | + | |
| 389 | + public String getTreeType() { | |
| 390 | + return treeType; | |
| 391 | + } | |
| 392 | + | |
| 393 | + public void setTreeType(String treeType) { | |
| 394 | + this.treeType = treeType; | |
| 395 | + } | |
| 397 | 396 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/bean/PlatformCatalog.java
| 1 | 1 | package com.genersoft.iot.vmp.gb28181.bean; |
| 2 | 2 | |
| 3 | +/** | |
| 4 | + * 国标级联-目录 | |
| 5 | + * @author lin | |
| 6 | + */ | |
| 3 | 7 | public class PlatformCatalog { |
| 4 | 8 | private String id; |
| 5 | 9 | private String name; |
| 6 | 10 | private String platformId; |
| 7 | 11 | private String parentId; |
| 8 | - private int childrenCount; // 子节点数 | |
| 9 | - private int type; // 0 目录, 1 国标通道, 2 直播流 | |
| 12 | + | |
| 13 | + private String civilCode; | |
| 14 | + | |
| 15 | + private String businessGroupId; | |
| 16 | + | |
| 17 | + /** | |
| 18 | + * 子节点数 | |
| 19 | + */ | |
| 20 | + private int childrenCount; | |
| 21 | + | |
| 22 | + /** | |
| 23 | + * 0 目录, 1 国标通道, 2 直播流 | |
| 24 | + */ | |
| 25 | + private int type; | |
| 10 | 26 | |
| 11 | 27 | public String getId() { |
| 12 | 28 | return id; |
| ... | ... | @@ -68,4 +84,19 @@ public class PlatformCatalog { |
| 68 | 84 | this.type = 2; |
| 69 | 85 | } |
| 70 | 86 | |
| 87 | + public String getCivilCode() { | |
| 88 | + return civilCode; | |
| 89 | + } | |
| 90 | + | |
| 91 | + public void setCivilCode(String civilCode) { | |
| 92 | + this.civilCode = civilCode; | |
| 93 | + } | |
| 94 | + | |
| 95 | + public String getBusinessGroupId() { | |
| 96 | + return businessGroupId; | |
| 97 | + } | |
| 98 | + | |
| 99 | + public void setBusinessGroupId(String businessGroupId) { | |
| 100 | + this.businessGroupId = businessGroupId; | |
| 101 | + } | |
| 71 | 102 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/bean/SyncStatus.java
| ... | ... | @@ -2,12 +2,15 @@ package com.genersoft.iot.vmp.gb28181.bean; |
| 2 | 2 | |
| 3 | 3 | /** |
| 4 | 4 | * 摄像机同步状态 |
| 5 | + * @author lin | |
| 5 | 6 | */ |
| 6 | 7 | public class SyncStatus { |
| 7 | 8 | private int total; |
| 8 | 9 | private int current; |
| 9 | 10 | private String errorMsg; |
| 10 | 11 | |
| 12 | + private boolean syncIng; | |
| 13 | + | |
| 11 | 14 | public int getTotal() { |
| 12 | 15 | return total; |
| 13 | 16 | } |
| ... | ... | @@ -31,4 +34,12 @@ public class SyncStatus { |
| 31 | 34 | public void setErrorMsg(String errorMsg) { |
| 32 | 35 | this.errorMsg = errorMsg; |
| 33 | 36 | } |
| 37 | + | |
| 38 | + public boolean isSyncIng() { | |
| 39 | + return syncIng; | |
| 40 | + } | |
| 41 | + | |
| 42 | + public void setSyncIng(boolean syncIng) { | |
| 43 | + this.syncIng = syncIng; | |
| 44 | + } | |
| 34 | 45 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/bean/TreeType.java
0 → 100644
src/main/java/com/genersoft/iot/vmp/gb28181/event/platformNotRegister/PlatformNotRegisterEventLister.java
| ... | ... | @@ -65,7 +65,6 @@ public class PlatformNotRegisterEventLister implements ApplicationListener<Platf |
| 65 | 65 | } |
| 66 | 66 | // 查询是否有推流, 如果有则都停止 |
| 67 | 67 | List<SendRtpItem> sendRtpItems = redisCatchStorage.querySendRTPServer(event.getPlatformGbID()); |
| 68 | - logger.info("[ 平台未注册事件 ] 停止[ {} ]的所有推流size", sendRtpItems.size()); | |
| 69 | 68 | if (sendRtpItems != null && sendRtpItems.size() > 0) { |
| 70 | 69 | logger.info("[ 平台未注册事件 ] 停止[ {} ]的所有推流", event.getPlatformGbID()); |
| 71 | 70 | for (SendRtpItem sendRtpItem : sendRtpItems) { | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/event/subscribe/catalog/CatalogEvent.java
| ... | ... | @@ -11,13 +11,40 @@ public class CatalogEvent extends ApplicationEvent { |
| 11 | 11 | super(source); |
| 12 | 12 | } |
| 13 | 13 | |
| 14 | - public static final String ON = "ON"; // 上线 | |
| 15 | - public static final String OFF = "OFF"; // 离线 | |
| 16 | - public static final String VLOST = "VLOST"; // 视频丢失 | |
| 17 | - public static final String DEFECT = "DEFECT"; // 故障 | |
| 18 | - public static final String ADD = "ADD"; // 增加 | |
| 19 | - public static final String DEL = "DEL"; // 删除 | |
| 20 | - public static final String UPDATE = "UPDATE"; // 更新 | |
| 14 | + /** | |
| 15 | + * 上线 | |
| 16 | + */ | |
| 17 | + public static final String ON = "ON"; | |
| 18 | + | |
| 19 | + /** | |
| 20 | + * 离线 | |
| 21 | + */ | |
| 22 | + public static final String OFF = "OFF"; | |
| 23 | + | |
| 24 | + /** | |
| 25 | + * 视频丢失 | |
| 26 | + */ | |
| 27 | + public static final String VLOST = "VLOST"; | |
| 28 | + | |
| 29 | + /** | |
| 30 | + * 故障 | |
| 31 | + */ | |
| 32 | + public static final String DEFECT = "DEFECT"; | |
| 33 | + | |
| 34 | + /** | |
| 35 | + * 增加 | |
| 36 | + */ | |
| 37 | + public static final String ADD = "ADD"; | |
| 38 | + | |
| 39 | + /** | |
| 40 | + * 删除 | |
| 41 | + */ | |
| 42 | + public static final String DEL = "DEL"; | |
| 43 | + | |
| 44 | + /** | |
| 45 | + * 更新 | |
| 46 | + */ | |
| 47 | + public static final String UPDATE = "UPDATE"; | |
| 21 | 48 | |
| 22 | 49 | private List<DeviceChannel> deviceChannels; |
| 23 | 50 | private List<GbStream> gbStreams; | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/event/subscribe/catalog/CatalogEventLister.java
| ... | ... | @@ -58,17 +58,16 @@ public class CatalogEventLister implements ApplicationListener<CatalogEvent> { |
| 58 | 58 | ParentPlatform parentPlatform = null; |
| 59 | 59 | |
| 60 | 60 | Map<String, List<ParentPlatform>> parentPlatformMap = new HashMap<>(); |
| 61 | - if (event.getPlatformId() != null) { | |
| 61 | + if (!StringUtils.isEmpty(event.getPlatformId())) { | |
| 62 | + subscribe = subscribeHolder.getCatalogSubscribe(event.getPlatformId()); | |
| 63 | + if (subscribe == null) { | |
| 64 | + return; | |
| 65 | + } | |
| 62 | 66 | parentPlatform = storager.queryParentPlatByServerGBId(event.getPlatformId()); |
| 63 | 67 | if (parentPlatform != null && !parentPlatform.isStatus()) { |
| 64 | 68 | return; |
| 65 | 69 | } |
| 66 | - subscribe = subscribeHolder.getCatalogSubscribe(event.getPlatformId()); | |
| 67 | 70 | |
| 68 | - if (subscribe == null) { | |
| 69 | - logger.info("发送订阅消息时发现订阅信息已经不存在: {}", event.getPlatformId()); | |
| 70 | - return; | |
| 71 | - } | |
| 72 | 71 | }else { |
| 73 | 72 | // 获取所用订阅 |
| 74 | 73 | List<String> platforms = subscribeHolder.getAllCatalogSubscribePlatform(); |
| ... | ... | @@ -144,11 +143,8 @@ public class CatalogEventLister implements ApplicationListener<CatalogEvent> { |
| 144 | 143 | } |
| 145 | 144 | if (event.getGbStreams() != null && event.getGbStreams().size() > 0){ |
| 146 | 145 | for (GbStream gbStream : event.getGbStreams()) { |
| 147 | - DeviceChannel deviceChannelByStream = gbStreamService.getDeviceChannelListByStream(gbStream, gbStream.getCatalogId(), parentPlatform); | |
| 148 | - if (deviceChannelByStream.getParentId().length() <= 10) { // 父节点是行政区划,则设置CivilCode使用此行政区划 | |
| 149 | - deviceChannelByStream.setCivilCode(deviceChannelByStream.getParentId()); | |
| 150 | - } | |
| 151 | - deviceChannelList.add(deviceChannelByStream); | |
| 146 | + deviceChannelList.add( | |
| 147 | + gbStreamService.getDeviceChannelListByStream(gbStream, gbStream.getCatalogId(), parentPlatform)); | |
| 152 | 148 | } |
| 153 | 149 | } |
| 154 | 150 | if (deviceChannelList.size() > 0) { | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/session/CatalogDataCatch.java
| ... | ... | @@ -84,6 +84,11 @@ public class CatalogDataCatch { |
| 84 | 84 | syncStatus.setCurrent(catalogData.getChannelList().size()); |
| 85 | 85 | syncStatus.setTotal(catalogData.getTotal()); |
| 86 | 86 | syncStatus.setErrorMsg(catalogData.getErrorMsg()); |
| 87 | + if (catalogData.getStatus().equals(CatalogData.CatalogDataStatus.end)) { | |
| 88 | + syncStatus.setSyncIng(false); | |
| 89 | + }else { | |
| 90 | + syncStatus.setSyncIng(true); | |
| 91 | + } | |
| 87 | 92 | return syncStatus; |
| 88 | 93 | } |
| 89 | 94 | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/task/impl/MobilePositionSubscribeHandlerTask.java
| ... | ... | @@ -57,23 +57,17 @@ public class MobilePositionSubscribeHandlerTask implements ISubscribeTask { |
| 57 | 57 | SubscribeInfo subscribe = subscribeHolder.getMobilePositionSubscribe(platform.getServerGBId()); |
| 58 | 58 | if (subscribe != null) { |
| 59 | 59 | |
| 60 | -// if (!parentPlatform.isStatus()) { | |
| 61 | -// logger.info("发送订阅时发现平台已经离线:{}", platformId); | |
| 62 | -// return; | |
| 63 | -// } | |
| 64 | 60 | // TODO 暂时只处理视频流的回复,后续增加对国标设备的支持 |
| 65 | - List<GbStream> gbStreams = storager.queryGbStreamListInPlatform(platform.getServerGBId()); | |
| 61 | + List<DeviceChannel> gbStreams = storager.queryGbStreamListInPlatform(platform.getServerGBId()); | |
| 66 | 62 | if (gbStreams.size() == 0) { |
| 67 | 63 | logger.info("发送订阅时发现平台已经没有关联的直播流:{}", platform.getServerGBId()); |
| 68 | 64 | return; |
| 69 | 65 | } |
| 70 | - for (GbStream gbStream : gbStreams) { | |
| 71 | - String gbId = gbStream.getGbId(); | |
| 66 | + for (DeviceChannel deviceChannel : gbStreams) { | |
| 67 | + String gbId = deviceChannel.getChannelId(); | |
| 72 | 68 | GPSMsgInfo gpsMsgInfo = redisCatchStorage.getGpsMsgInfo(gbId); |
| 73 | - if (gpsMsgInfo != null) { // 无最新位置不发送 | |
| 74 | - if (logger.isDebugEnabled()) { | |
| 75 | - logger.debug("无最新位置不发送"); | |
| 76 | - } | |
| 69 | + // 无最新位置不发送 | |
| 70 | + if (gpsMsgInfo != null) { | |
| 77 | 71 | // 经纬度都为0不发送 |
| 78 | 72 | if (gpsMsgInfo.getLng() == 0 && gpsMsgInfo.getLat() == 0) { |
| 79 | 73 | continue; | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/task/impl/MobilePositionSubscribeTask.java
| ... | ... | @@ -39,9 +39,9 @@ public class MobilePositionSubscribeTask implements ISubscribeTask { |
| 39 | 39 | dynamicTask.stop(taskKey); |
| 40 | 40 | } |
| 41 | 41 | sipCommander.mobilePositionSubscribe(device, dialog, eventResult -> { |
| 42 | -// if (eventResult.dialog != null || eventResult.dialog.getState().equals(DialogState.CONFIRMED)) { | |
| 43 | -// dialog = eventResult.dialog; | |
| 44 | -// } | |
| 42 | + if (eventResult.dialog != null || eventResult.dialog.getState().equals(DialogState.CONFIRMED)) { | |
| 43 | + dialog = eventResult.dialog; | |
| 44 | + } | |
| 45 | 45 | ResponseEvent event = (ResponseEvent) eventResult.event; |
| 46 | 46 | if (event.getResponse().getRawContent() != null) { |
| 47 | 47 | // 成功 | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java
| ... | ... | @@ -10,6 +10,9 @@ import com.genersoft.iot.vmp.gb28181.event.SipSubscribe; |
| 10 | 10 | import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager; |
| 11 | 11 | import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander; |
| 12 | 12 | import com.genersoft.iot.vmp.gb28181.transmit.cmd.SIPRequestHeaderProvider; |
| 13 | +import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeFactory; | |
| 14 | +import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForStreamChange; | |
| 15 | +import com.genersoft.iot.vmp.media.zlm.dto.HookType; | |
| 13 | 16 | import com.genersoft.iot.vmp.utils.DateUtil; |
| 14 | 17 | import com.genersoft.iot.vmp.gb28181.utils.NumericUtil; |
| 15 | 18 | import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe; |
| ... | ... | @@ -348,25 +351,19 @@ public class SIPCommander implements ISIPCommander { |
| 348 | 351 | @Override |
| 349 | 352 | public void playStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, |
| 350 | 353 | ZLMHttpHookSubscribe.Event event, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) { |
| 351 | - String streamId = ssrcInfo.getStream(); | |
| 354 | + String stream = ssrcInfo.getStream(); | |
| 352 | 355 | try { |
| 353 | 356 | if (device == null) { |
| 354 | 357 | return; |
| 355 | 358 | } |
| 356 | 359 | String streamMode = device.getStreamMode().toUpperCase(); |
| 357 | 360 | |
| 358 | - logger.info("{} 分配的ZLM为: {} [{}:{}]", streamId, mediaServerItem.getId(), mediaServerItem.getIp(), ssrcInfo.getPort()); | |
| 359 | - // 添加订阅 | |
| 360 | - JSONObject subscribeKey = new JSONObject(); | |
| 361 | - subscribeKey.put("app", "rtp"); | |
| 362 | - subscribeKey.put("stream", streamId); | |
| 363 | - subscribeKey.put("regist", true); | |
| 364 | - subscribeKey.put("schema", "rtmp"); | |
| 365 | - subscribeKey.put("mediaServerId", mediaServerItem.getId()); | |
| 366 | - subscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey, | |
| 367 | - (MediaServerItem mediaServerItemInUse, JSONObject json)->{ | |
| 361 | + logger.info("{} 分配的ZLM为: {} [{}:{}]", stream, mediaServerItem.getId(), mediaServerItem.getIp(), ssrcInfo.getPort()); | |
| 362 | + HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", stream, true, "rtmp", mediaServerItem.getId()); | |
| 363 | + subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, JSONObject json)->{ | |
| 368 | 364 | if (event != null) { |
| 369 | 365 | event.response(mediaServerItemInUse, json); |
| 366 | + subscribe.removeSubscribe(hookSubscribe); | |
| 370 | 367 | } |
| 371 | 368 | }); |
| 372 | 369 | // |
| ... | ... | @@ -440,7 +437,7 @@ public class SIPCommander implements ISIPCommander { |
| 440 | 437 | errorEvent.response(e); |
| 441 | 438 | }), e ->{ |
| 442 | 439 | // 这里为例避免一个通道的点播只有一个callID这个参数使用一个固定值 |
| 443 | - streamSession.put(device.getDeviceId(), channelId ,"play", streamId, ssrcInfo.getSsrc(), mediaServerItem.getId(), ((ResponseEvent)e.event).getClientTransaction(), VideoStreamSessionManager.SessionType.play); | |
| 440 | + streamSession.put(device.getDeviceId(), channelId ,"play", stream, ssrcInfo.getSsrc(), mediaServerItem.getId(), ((ResponseEvent)e.event).getClientTransaction(), VideoStreamSessionManager.SessionType.play); | |
| 444 | 441 | streamSession.put(device.getDeviceId(), channelId ,"play", e.dialog); |
| 445 | 442 | okEvent.response(e); |
| 446 | 443 | }); |
| ... | ... | @@ -530,21 +527,14 @@ public class SIPCommander implements ISIPCommander { |
| 530 | 527 | |
| 531 | 528 | CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId() |
| 532 | 529 | : udpSipProvider.getNewCallId(); |
| 533 | - | |
| 530 | + HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", ssrcInfo.getStream(), true, "rtmp", mediaServerItem.getId()); | |
| 534 | 531 | // 添加订阅 |
| 535 | - JSONObject subscribeKey = new JSONObject(); | |
| 536 | - subscribeKey.put("app", "rtp"); | |
| 537 | - subscribeKey.put("stream", ssrcInfo.getStream()); | |
| 538 | - subscribeKey.put("regist", true); | |
| 539 | - subscribeKey.put("schema", "rtmp"); | |
| 540 | - subscribeKey.put("mediaServerId", mediaServerItem.getId()); | |
| 541 | - logger.debug("录像回放添加订阅,订阅内容:" + subscribeKey); | |
| 542 | - subscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey, | |
| 543 | - (MediaServerItem mediaServerItemInUse, JSONObject json)->{ | |
| 532 | + subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, JSONObject json)->{ | |
| 544 | 533 | if (hookEvent != null) { |
| 545 | 534 | InviteStreamInfo inviteStreamInfo = new InviteStreamInfo(mediaServerItemInUse, json, callIdHeader.getCallId(), "rtp", ssrcInfo.getStream()); |
| 546 | 535 | hookEvent.call(inviteStreamInfo); |
| 547 | 536 | } |
| 537 | + subscribe.removeSubscribe(hookSubscribe); | |
| 548 | 538 | }); |
| 549 | 539 | Request request = headerProvider.createPlaybackInviteRequest(device, channelId, content.toString(), null, "fromplybck" + tm, null, callIdHeader, ssrcInfo.getSsrc()); |
| 550 | 540 | |
| ... | ... | @@ -643,21 +633,15 @@ public class SIPCommander implements ISIPCommander { |
| 643 | 633 | CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId() |
| 644 | 634 | : udpSipProvider.getNewCallId(); |
| 645 | 635 | |
| 636 | + HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", ssrcInfo.getStream(), true, null, mediaServerItem.getId()); | |
| 646 | 637 | // 添加订阅 |
| 647 | - JSONObject subscribeKey = new JSONObject(); | |
| 648 | - subscribeKey.put("app", "rtp"); | |
| 649 | - subscribeKey.put("stream", ssrcInfo.getStream()); | |
| 650 | - subscribeKey.put("regist", true); | |
| 651 | - subscribeKey.put("mediaServerId", mediaServerItem.getId()); | |
| 652 | - logger.debug("录像回放添加订阅,订阅内容:" + subscribeKey.toString()); | |
| 653 | - subscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey, | |
| 654 | - (MediaServerItem mediaServerItemInUse, JSONObject json)->{ | |
| 638 | + subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, JSONObject json)->{ | |
| 655 | 639 | hookEvent.call(new InviteStreamInfo(mediaServerItem, json, callIdHeader.getCallId(), "rtp", ssrcInfo.getStream())); |
| 656 | - subscribe.removeSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey); | |
| 657 | - subscribeKey.put("regist", false); | |
| 658 | - subscribeKey.put("schema", "rtmp"); | |
| 640 | + subscribe.removeSubscribe(hookSubscribe); | |
| 641 | + hookSubscribe.getContent().put("regist", false); | |
| 642 | + hookSubscribe.getContent().put("schema", "rtmp"); | |
| 659 | 643 | // 添加流注销的订阅,注销了后向设备发送bye |
| 660 | - subscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey, | |
| 644 | + subscribe.addSubscribe(hookSubscribe, | |
| 661 | 645 | (MediaServerItem mediaServerItemForEnd, JSONObject jsonForEnd)->{ |
| 662 | 646 | ClientTransaction transaction = streamSession.getTransaction(device.getDeviceId(), channelId, ssrcInfo.getStream(), callIdHeader.getCallId()); |
| 663 | 647 | if (transaction != null) { | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java
| ... | ... | @@ -257,37 +257,37 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { |
| 257 | 257 | catalogXml.append("<DeviceList Num=\"" + channels.size() +"\">\r\n"); |
| 258 | 258 | if (channels.size() > 0) { |
| 259 | 259 | for (DeviceChannel channel : channels) { |
| 260 | + if (parentPlatform.getServerGBId().equals(channel.getParentId())) { | |
| 261 | + channel.setParentId(parentPlatform.getDeviceGBId()); | |
| 262 | + } | |
| 260 | 263 | catalogXml.append("<Item>\r\n"); |
| 264 | + // 行政区划分组只需要这两项就可以 | |
| 261 | 265 | catalogXml.append("<DeviceID>" + channel.getChannelId() + "</DeviceID>\r\n"); |
| 262 | 266 | catalogXml.append("<Name>" + channel.getName() + "</Name>\r\n"); |
| 263 | - catalogXml.append("<Parental>" + channel.getParental() + "</Parental>\r\n"); | |
| 264 | 267 | if (channel.getParentId() != null) { |
| 268 | + // 业务分组加上这一项即可,提高兼容性, | |
| 265 | 269 | catalogXml.append("<ParentID>" + channel.getParentId() + "</ParentID>\r\n"); |
| 266 | 270 | } |
| 267 | - if (channel.getChannelId().length() == 20) { | |
| 268 | - if (Integer.parseInt(channel.getChannelId().substring(10, 13)) == 216) { // 虚拟组织增加BusinessGroupID字段 | |
| 269 | - catalogXml.append("<BusinessGroupID>" + channel.getParentId() + "</BusinessGroupID>\r\n"); | |
| 270 | - } | |
| 271 | + if (channel.getChannelId().length() == 20 && Integer.parseInt(channel.getChannelId().substring(10, 13)) == 216) { | |
| 272 | + // 虚拟组织增加BusinessGroupID字段 | |
| 273 | + catalogXml.append("<BusinessGroupID>" + channel.getParentId() + "</BusinessGroupID>\r\n"); | |
| 274 | + } | |
| 275 | + catalogXml.append("<Parental>" + channel.getParental() + "</Parental>\r\n"); | |
| 276 | + if (channel.getParental() == 0) { | |
| 277 | + // 通道项 | |
| 271 | 278 | catalogXml.append("<Manufacturer>" + channel.getManufacture() + "</Manufacturer>\r\n"); |
| 279 | + catalogXml.append("<Secrecy>" + channel.getSecrecy() + "</Secrecy>\r\n"); | |
| 272 | 280 | catalogXml.append("<RegisterWay>" + channel.getRegisterWay() + "</RegisterWay>\r\n"); |
| 273 | - catalogXml.append("<Status>" + (channel.getStatus() == 0?"OFF":"ON") + "</Status>\r\n"); | |
| 274 | - if (channel.getChannelType() != 2) { // 业务分组/虚拟组织/行政区划 不设置以下字段 | |
| 275 | - catalogXml.append("<Secrecy>" + channel.getSecrecy() + "</Secrecy>\r\n"); | |
| 281 | + catalogXml.append("<Status>" + (channel.getStatus() == 0 ? "OFF" : "ON") + "</Status>\r\n"); | |
| 282 | + | |
| 283 | + if (channel.getChannelType() != 2) { // 业务分组/虚拟组织/行政区划 不设置以下属性 | |
| 276 | 284 | catalogXml.append("<Model>" + channel.getModel() + "</Model>\r\n"); |
| 277 | - catalogXml.append("<Owner>" + channel.getOwner() + "</Owner>\r\n"); | |
| 285 | + catalogXml.append("<Owner> " + channel.getOwner()+ "</Owner>\r\n"); | |
| 278 | 286 | catalogXml.append("<CivilCode>" + channel.getCivilCode() + "</CivilCode>\r\n"); |
| 279 | 287 | catalogXml.append("<Address>" + channel.getAddress() + "</Address>\r\n"); |
| 280 | - catalogXml.append("<Longitude>" + channel.getLongitudeWgs84() + "</Longitude>\r\n"); | |
| 281 | - catalogXml.append("<Latitude>" + channel.getLatitudeWgs84() + "</Latitude>\r\n"); | |
| 282 | - catalogXml.append("<IPAddress>" + channel.getIpAddress() + "</IPAddress>\r\n"); | |
| 283 | - catalogXml.append("<Port>" + channel.getPort() + "</Port>\r\n"); | |
| 284 | - catalogXml.append("<Info>\r\n"); | |
| 285 | - catalogXml.append("<PTZType>" + channel.getPTZType() + "</PTZType>\r\n"); | |
| 286 | - catalogXml.append("</Info>\r\n"); | |
| 287 | 288 | } |
| 288 | - } | |
| 289 | - | |
| 290 | 289 | |
| 290 | + } | |
| 291 | 291 | catalogXml.append("</Item>\r\n"); |
| 292 | 292 | } |
| 293 | 293 | } |
| ... | ... | @@ -592,27 +592,35 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { |
| 592 | 592 | channel.setParentId(parentPlatform.getDeviceGBId()); |
| 593 | 593 | } |
| 594 | 594 | catalogXml.append("<Item>\r\n"); |
| 595 | + // 行政区划分组只需要这两项就可以 | |
| 595 | 596 | catalogXml.append("<DeviceID>" + channel.getChannelId() + "</DeviceID>\r\n"); |
| 596 | 597 | catalogXml.append("<Name>" + channel.getName() + "</Name>\r\n"); |
| 597 | - catalogXml.append("<Manufacturer>" + channel.getManufacture() + "</Manufacturer>\r\n"); | |
| 598 | - catalogXml.append("<Parental>" + channel.getParental() + "</Parental>\r\n"); | |
| 599 | 598 | if (channel.getParentId() != null) { |
| 599 | + // 业务分组加上这一项即可,提高兼容性, | |
| 600 | 600 | catalogXml.append("<ParentID>" + channel.getParentId() + "</ParentID>\r\n"); |
| 601 | 601 | } |
| 602 | - catalogXml.append("<Secrecy>" + channel.getSecrecy() + "</Secrecy>\r\n"); | |
| 603 | - catalogXml.append("<RegisterWay>" + channel.getRegisterWay() + "</RegisterWay>\r\n"); | |
| 604 | - catalogXml.append("<Status>" + (channel.getStatus() == 0 ? "OFF" : "ON") + "</Status>\r\n"); | |
| 605 | - if (channel.getChannelId().length() == 20 && Integer.parseInt(channel.getChannelId().substring(10, 13)) == 216) { // 虚拟组织增加BusinessGroupID字段 | |
| 602 | + if (channel.getChannelId().length() == 20 && Integer.parseInt(channel.getChannelId().substring(10, 13)) == 216) { | |
| 603 | + // 虚拟组织增加BusinessGroupID字段 | |
| 606 | 604 | catalogXml.append("<BusinessGroupID>" + channel.getParentId() + "</BusinessGroupID>\r\n"); |
| 607 | 605 | } |
| 608 | - if (channel.getChannelType() == 2) { // 业务分组/虚拟组织/行政区划 不设置以下属性 | |
| 609 | - catalogXml.append("<Model>" + channel.getModel() + "</Model>\r\n"); | |
| 610 | - catalogXml.append("<Owner>0</Owner>\r\n"); | |
| 611 | - catalogXml.append("<CivilCode>CivilCode</CivilCode>\r\n"); | |
| 612 | - catalogXml.append("<Address>" + channel.getAddress() + "</Address>\r\n"); | |
| 613 | - } | |
| 614 | - if (!"presence".equals(subscribeInfo.getEventType())) { | |
| 615 | - catalogXml.append("<Event>" + type + "</Event>\r\n"); | |
| 606 | + catalogXml.append("<Parental>" + channel.getParental() + "</Parental>\r\n"); | |
| 607 | + if (channel.getParental() == 0) { | |
| 608 | + // 通道项 | |
| 609 | + catalogXml.append("<Manufacturer>" + channel.getManufacture() + "</Manufacturer>\r\n"); | |
| 610 | + catalogXml.append("<Secrecy>" + channel.getSecrecy() + "</Secrecy>\r\n"); | |
| 611 | + catalogXml.append("<RegisterWay>" + channel.getRegisterWay() + "</RegisterWay>\r\n"); | |
| 612 | + catalogXml.append("<Status>" + (channel.getStatus() == 0 ? "OFF" : "ON") + "</Status>\r\n"); | |
| 613 | + | |
| 614 | + if (channel.getChannelType() != 2) { // 业务分组/虚拟组织/行政区划 不设置以下属性 | |
| 615 | + catalogXml.append("<Model>" + channel.getModel() + "</Model>\r\n"); | |
| 616 | + catalogXml.append("<Owner> " + channel.getOwner()+ "</Owner>\r\n"); | |
| 617 | + catalogXml.append("<CivilCode>" + channel.getCivilCode() + "</CivilCode>\r\n"); | |
| 618 | + catalogXml.append("<Address>" + channel.getAddress() + "</Address>\r\n"); | |
| 619 | + } | |
| 620 | + if (!"presence".equals(subscribeInfo.getEventType())) { | |
| 621 | + catalogXml.append("<Event>" + type + "</Event>\r\n"); | |
| 622 | + } | |
| 623 | + | |
| 616 | 624 | } |
| 617 | 625 | catalogXml.append("</Item>\r\n"); |
| 618 | 626 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/ByeRequestProcessor.java
| ... | ... | @@ -133,7 +133,7 @@ public class ByeRequestProcessor extends SIPRequestProcessorParent implements In |
| 133 | 133 | SsrcTransaction ssrcTransactionForPlay = streamSession.getSsrcTransaction(device.getDeviceId(), channelId, "play", null); |
| 134 | 134 | if (ssrcTransactionForPlay != null){ |
| 135 | 135 | SIPDialog dialogForPlay = (SIPDialog) SerializeUtils.deSerialize(ssrcTransactionForPlay.getDialog()); |
| 136 | - if (dialogForPlay.getCallId().equals(callIdHeader.getCallId())){ | |
| 136 | + if (dialogForPlay.getCallId().getCallId().equals(callIdHeader.getCallId())){ | |
| 137 | 137 | // 释放ssrc |
| 138 | 138 | MediaServerItem mediaServerItem = mediaServerService.getOne(ssrcTransactionForPlay.getMediaServerId()); |
| 139 | 139 | if (mediaServerItem != null) { | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java
| ... | ... | @@ -30,6 +30,7 @@ import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem; |
| 30 | 30 | import com.genersoft.iot.vmp.service.IMediaServerService; |
| 31 | 31 | import com.genersoft.iot.vmp.service.IMediaService; |
| 32 | 32 | import com.genersoft.iot.vmp.service.IPlayService; |
| 33 | +import com.genersoft.iot.vmp.service.IStreamProxyService; | |
| 33 | 34 | import com.genersoft.iot.vmp.service.IStreamPushService; |
| 34 | 35 | import com.genersoft.iot.vmp.service.bean.MessageForPushChannel; |
| 35 | 36 | import com.genersoft.iot.vmp.service.bean.SSRCInfo; |
| ... | ... | @@ -81,6 +82,9 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements |
| 81 | 82 | private IStreamPushService streamPushService; |
| 82 | 83 | |
| 83 | 84 | @Autowired |
| 85 | + private IStreamProxyService streamProxyService; | |
| 86 | + | |
| 87 | + @Autowired | |
| 84 | 88 | private IRedisCatchStorage redisCatchStorage; |
| 85 | 89 | |
| 86 | 90 | @Autowired |
| ... | ... | @@ -94,7 +98,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements |
| 94 | 98 | |
| 95 | 99 | @Autowired |
| 96 | 100 | private ISIPCommander commander; |
| 97 | - | |
| 101 | + | |
| 98 | 102 | @Autowired |
| 99 | 103 | private AudioBroadcastManager audioBroadcastManager; |
| 100 | 104 | |
| ... | ... | @@ -153,10 +157,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements |
| 153 | 157 | // Invite Request消息实现,此消息一般为级联消息,上级给下级发送请求视频指令 |
| 154 | 158 | try { |
| 155 | 159 | Request request = evt.getRequest(); |
| 156 | - SipURI sipUri = (SipURI) request.getRequestURI(); | |
| 157 | - //从subject读取channelId,不再从request-line读取。 有些平台request-line是平台国标编码,不是设备国标编码。 | |
| 158 | - //String channelId = sipURI.getUser(); | |
| 159 | - String channelId = SipUtils.getChannelIdFromHeader(request); | |
| 160 | + String channelId = SipUtils.getChannelIdFromRequest(request); | |
| 160 | 161 | String requesterId = SipUtils.getUserIdFromFromHeader(request); |
| 161 | 162 | CallIdHeader callIdHeader = (CallIdHeader) request.getHeader(CallIdHeader.NAME); |
| 162 | 163 | if (requesterId == null || channelId == null) { |
| ... | ... | @@ -178,6 +179,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements |
| 178 | 179 | |
| 179 | 180 | MediaServerItem mediaServerItem = null; |
| 180 | 181 | StreamPushItem streamPushItem = null; |
| 182 | + StreamProxyItem proxyByAppAndStream =null; | |
| 181 | 183 | // 不是通道可能是直播流 |
| 182 | 184 | if (channel != null && gbStream == null) { |
| 183 | 185 | if (channel.getStatus() == 0) { |
| ... | ... | @@ -211,6 +213,13 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements |
| 211 | 213 | responseAck(evt, Response.GONE); |
| 212 | 214 | return; |
| 213 | 215 | } |
| 216 | + }else if("proxy".equals(gbStream.getStreamType())){ | |
| 217 | + proxyByAppAndStream = streamProxyService.getStreamProxyByAppAndStream(gbStream.getApp(), gbStream.getStream()); | |
| 218 | + if (proxyByAppAndStream == null) { | |
| 219 | + logger.info("[ app={}, stream={} ]找不到zlm {},返回410", gbStream.getApp(), gbStream.getStream(), mediaServerId); | |
| 220 | + responseAck(evt, Response.GONE); | |
| 221 | + return; | |
| 222 | + } | |
| 214 | 223 | } |
| 215 | 224 | } |
| 216 | 225 | responseAck(evt, Response.CALL_IS_BEING_FORWARDED); // 通道存在,发181,呼叫转接中 |
| ... | ... | @@ -452,18 +461,35 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements |
| 452 | 461 | } |
| 453 | 462 | } |
| 454 | 463 | } else if (gbStream != null) { |
| 455 | - if (streamPushItem.isStatus()) { | |
| 456 | - // 在线状态 | |
| 457 | - pushStream(evt, gbStream, streamPushItem, platform, callIdHeader, mediaServerItem, port, tcpActive, | |
| 458 | - mediaTransmissionTCP, channelId, addressStr, ssrc, requesterId); | |
| 459 | - } else { | |
| 460 | - // 不在线 拉起 | |
| 461 | - notifyStreamOnline(evt, gbStream, streamPushItem, platform, callIdHeader, mediaServerItem, port, tcpActive, | |
| 462 | - mediaTransmissionTCP, channelId, addressStr, ssrc, requesterId); | |
| 463 | - } | |
| 464 | + if("push".equals(gbStream.getStreamType())) { | |
| 465 | + if (streamPushItem != null && streamPushItem.isPushIng()) { | |
| 466 | + // 推流状态 | |
| 467 | + pushStream(evt, gbStream, streamPushItem, platform, callIdHeader, mediaServerItem, port, tcpActive, | |
| 468 | + mediaTransmissionTCP, channelId, addressStr, ssrc, requesterId); | |
| 469 | + } else { | |
| 470 | + // 未推流 拉起 | |
| 471 | + notifyStreamOnline(evt, gbStream, streamPushItem, platform, callIdHeader, mediaServerItem, port, tcpActive, | |
| 472 | + mediaTransmissionTCP, channelId, addressStr, ssrc, requesterId); | |
| 473 | + } | |
| 474 | + }else if ("proxy".equals(gbStream.getStreamType())){ | |
| 475 | + if(null != proxyByAppAndStream &&proxyByAppAndStream.isStatus()){ | |
| 476 | + pushProxyStream(evt, gbStream, platform, callIdHeader, mediaServerItem, port, tcpActive, | |
| 477 | + mediaTransmissionTCP, channelId, addressStr, ssrc, requesterId); | |
| 478 | + }else{ | |
| 479 | + //开启代理拉流 | |
| 480 | + boolean start1 = streamProxyService.start(gbStream.getApp(), gbStream.getStream()); | |
| 481 | + if(start1) { | |
| 482 | + pushProxyStream(evt, gbStream, platform, callIdHeader, mediaServerItem, port, tcpActive, | |
| 483 | + mediaTransmissionTCP, channelId, addressStr, ssrc, requesterId); | |
| 484 | + }else{ | |
| 485 | + //失败后通知 | |
| 486 | + notifyStreamOnline(evt, gbStream, null, platform, callIdHeader, mediaServerItem, port, tcpActive, | |
| 487 | + mediaTransmissionTCP, channelId, addressStr, ssrc, requesterId); | |
| 488 | + } | |
| 489 | + } | |
| 464 | 490 | |
| 491 | + } | |
| 465 | 492 | } |
| 466 | - | |
| 467 | 493 | } |
| 468 | 494 | |
| 469 | 495 | } catch (SipException | InvalidArgumentException | ParseException e) { |
| ... | ... | @@ -480,13 +506,45 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements |
| 480 | 506 | /** |
| 481 | 507 | * 安排推流 |
| 482 | 508 | */ |
| 509 | + private void pushProxyStream(RequestEvent evt, GbStream gbStream, ParentPlatform platform, | |
| 510 | + CallIdHeader callIdHeader, MediaServerItem mediaServerItem, | |
| 511 | + int port, Boolean tcpActive, boolean mediaTransmissionTCP, | |
| 512 | + String channelId, String addressStr, String ssrc, String requesterId) throws InvalidArgumentException, ParseException, SipException { | |
| 513 | + Boolean streamReady = zlmrtpServerFactory.isStreamReady(mediaServerItem, gbStream.getApp(), gbStream.getStream()); | |
| 514 | + if (streamReady) { | |
| 515 | + // 自平台内容 | |
| 516 | + SendRtpItem sendRtpItem = zlmrtpServerFactory.createSendRtpItem(mediaServerItem, addressStr, port, ssrc, requesterId, | |
| 517 | + gbStream.getApp(), gbStream.getStream(), channelId, | |
| 518 | + mediaTransmissionTCP); | |
| 519 | + | |
| 520 | + if (sendRtpItem == null) { | |
| 521 | + logger.warn("服务器端口资源不足"); | |
| 522 | + responseAck(evt, Response.BUSY_HERE); | |
| 523 | + return; | |
| 524 | + } | |
| 525 | + if (tcpActive != null) { | |
| 526 | + sendRtpItem.setTcpActive(tcpActive); | |
| 527 | + } | |
| 528 | + sendRtpItem.setPlayType(InviteStreamType.PUSH); | |
| 529 | + // 写入redis, 超时时回复 | |
| 530 | + sendRtpItem.setStatus(1); | |
| 531 | + sendRtpItem.setCallId(callIdHeader.getCallId()); | |
| 532 | + byte[] dialogByteArray = SerializeUtils.serialize(evt.getDialog()); | |
| 533 | + sendRtpItem.setDialog(dialogByteArray); | |
| 534 | + byte[] transactionByteArray = SerializeUtils.serialize(evt.getServerTransaction()); | |
| 535 | + sendRtpItem.setTransaction(transactionByteArray); | |
| 536 | + redisCatchStorage.updateSendRTPSever(sendRtpItem); | |
| 537 | + sendStreamAck(mediaServerItem, sendRtpItem, platform, evt); | |
| 538 | + | |
| 539 | + } | |
| 483 | 540 | |
| 541 | + } | |
| 484 | 542 | private void pushStream(RequestEvent evt, GbStream gbStream, StreamPushItem streamPushItem, ParentPlatform platform, |
| 485 | 543 | CallIdHeader callIdHeader, MediaServerItem mediaServerItem, |
| 486 | 544 | int port, Boolean tcpActive, boolean mediaTransmissionTCP, |
| 487 | 545 | String channelId, String addressStr, String ssrc, String requesterId) throws InvalidArgumentException, ParseException, SipException { |
| 488 | 546 | // 推流 |
| 489 | - if (streamPushItem.getServerId().equals(userSetting.getServerId())) { | |
| 547 | + if (streamPushItem.isSelf()) { | |
| 490 | 548 | Boolean streamReady = zlmrtpServerFactory.isStreamReady(mediaServerItem, gbStream.getApp(), gbStream.getStream()); |
| 491 | 549 | if (streamReady) { |
| 492 | 550 | // 自平台内容 |
| ... | ... | @@ -525,7 +583,6 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements |
| 525 | 583 | } |
| 526 | 584 | |
| 527 | 585 | } |
| 528 | - | |
| 529 | 586 | /** |
| 530 | 587 | * 通知流上线 |
| 531 | 588 | */ |
| ... | ... | @@ -535,7 +592,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements |
| 535 | 592 | String channelId, String addressStr, String ssrc, String requesterId) throws InvalidArgumentException, ParseException, SipException { |
| 536 | 593 | if ("proxy".equals(gbStream.getStreamType())) { |
| 537 | 594 | // TODO 控制启用以使设备上线 |
| 538 | - logger.info("[ app={}, stream={} ]通道离线,启用流后开始推流", gbStream.getApp(), gbStream.getStream()); | |
| 595 | + logger.info("[ app={}, stream={} ]通道未推流,启用流后开始推流", gbStream.getApp(), gbStream.getStream()); | |
| 539 | 596 | responseAck(evt, Response.BAD_REQUEST, "channel [" + gbStream.getGbId() + "] offline"); |
| 540 | 597 | } else if ("push".equals(gbStream.getStreamType())) { |
| 541 | 598 | if (!platform.isStartOfflinePush()) { |
| ... | ... | @@ -543,7 +600,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements |
| 543 | 600 | return; |
| 544 | 601 | } |
| 545 | 602 | // 发送redis消息以使设备上线 |
| 546 | - logger.info("[ app={}, stream={} ]通道离线,发送redis信息控制设备开始推流", gbStream.getApp(), gbStream.getStream()); | |
| 603 | + logger.info("[ app={}, stream={} ]通道未推流,发送redis信息控制设备开始推流", gbStream.getApp(), gbStream.getStream()); | |
| 547 | 604 | |
| 548 | 605 | MessageForPushChannel messageForPushChannel = MessageForPushChannel.getInstance(1, |
| 549 | 606 | gbStream.getApp(), gbStream.getStream(), gbStream.getGbId(), gbStream.getPlatformId(), |
| ... | ... | @@ -553,7 +610,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements |
| 553 | 610 | dynamicTask.startDelay(callIdHeader.getCallId(), () -> { |
| 554 | 611 | logger.info("[ app={}, stream={} ] 等待设备开始推流超时", gbStream.getApp(), gbStream.getStream()); |
| 555 | 612 | try { |
| 556 | - mediaListManager.removedChannelOnlineEventLister(gbStream.getGbId()); | |
| 613 | + mediaListManager.removedChannelOnlineEventLister(gbStream.getApp(), gbStream.getStream()); | |
| 557 | 614 | responseAck(evt, Response.REQUEST_TIMEOUT); // 超时 |
| 558 | 615 | } catch (SipException e) { |
| 559 | 616 | e.printStackTrace(); |
| ... | ... | @@ -568,7 +625,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements |
| 568 | 625 | Boolean finalTcpActive = tcpActive; |
| 569 | 626 | |
| 570 | 627 | // 添加在本机上线的通知 |
| 571 | - mediaListManager.addChannelOnlineEventLister(gbStream.getGbId(), (app, stream, serverId) -> { | |
| 628 | + mediaListManager.addChannelOnlineEventLister(gbStream.getApp(), gbStream.getStream(), (app, stream, serverId) -> { | |
| 572 | 629 | dynamicTask.stop(callIdHeader.getCallId()); |
| 573 | 630 | if (serverId.equals(userSetting.getServerId())) { |
| 574 | 631 | SendRtpItem sendRtpItem = zlmrtpServerFactory.createSendRtpItem(mediaServerItem, addressStr, finalPort, ssrc, requesterId, |
| ... | ... | @@ -656,7 +713,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements |
| 656 | 713 | // 离线 |
| 657 | 714 | // 查询是否在本机上线了 |
| 658 | 715 | StreamPushItem currentStreamPushItem = streamPushService.getPush(streamPushItem.getApp(), streamPushItem.getStream()); |
| 659 | - if (currentStreamPushItem.isStatus()) { | |
| 716 | + if (currentStreamPushItem.isPushIng()) { | |
| 660 | 717 | // 在线状态 |
| 661 | 718 | pushStream(evt, gbStream, streamPushItem, platform, callIdHeader, mediaServerItem, port, tcpActive, |
| 662 | 719 | mediaTransmissionTCP, channelId, addressStr, ssrc, requesterId); | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/NotifyRequestProcessor.java
| ... | ... | @@ -15,6 +15,7 @@ import com.genersoft.iot.vmp.gb28181.utils.Coordtransform; |
| 15 | 15 | import com.genersoft.iot.vmp.gb28181.utils.NumericUtil; |
| 16 | 16 | import com.genersoft.iot.vmp.gb28181.utils.SipUtils; |
| 17 | 17 | import com.genersoft.iot.vmp.gb28181.utils.XmlUtil; |
| 18 | +import com.genersoft.iot.vmp.service.IDeviceChannelService; | |
| 18 | 19 | import com.genersoft.iot.vmp.storager.IRedisCatchStorage; |
| 19 | 20 | import com.genersoft.iot.vmp.storager.IVideoManagerStorage; |
| 20 | 21 | import com.genersoft.iot.vmp.utils.DateUtil; |
| ... | ... | @@ -71,6 +72,9 @@ public class NotifyRequestProcessor extends SIPRequestProcessorParent implements |
| 71 | 72 | @Autowired |
| 72 | 73 | private SIPProcessorObserver sipProcessorObserver; |
| 73 | 74 | |
| 75 | + @Autowired | |
| 76 | + private IDeviceChannelService deviceChannelService; | |
| 77 | + | |
| 74 | 78 | private boolean taskQueueHandlerRun = false; |
| 75 | 79 | |
| 76 | 80 | private final ConcurrentLinkedQueue<HandlerCatchData> taskQueue = new ConcurrentLinkedQueue<>(); |
| ... | ... | @@ -88,39 +92,36 @@ public class NotifyRequestProcessor extends SIPRequestProcessorParent implements |
| 88 | 92 | @Override |
| 89 | 93 | public void process(RequestEvent evt) { |
| 90 | 94 | try { |
| 91 | - | |
| 92 | 95 | taskQueue.offer(new HandlerCatchData(evt, null, null)); |
| 93 | 96 | responseAck(evt, Response.OK); |
| 94 | 97 | if (!taskQueueHandlerRun) { |
| 95 | 98 | taskQueueHandlerRun = true; |
| 96 | 99 | taskExecutor.execute(()-> { |
| 97 | - while (!taskQueue.isEmpty()) { | |
| 98 | - try { | |
| 99 | - HandlerCatchData take = taskQueue.poll(); | |
| 100 | - Element rootElement = getRootElement(take.getEvt()); | |
| 101 | - String cmd = XmlUtil.getText(rootElement, "CmdType"); | |
| 102 | - | |
| 103 | - if (CmdType.CATALOG.equals(cmd)) { | |
| 104 | - logger.info("接收到Catalog通知"); | |
| 105 | - processNotifyCatalogList(take.getEvt()); | |
| 106 | - } else if (CmdType.ALARM.equals(cmd)) { | |
| 107 | - logger.info("接收到Alarm通知"); | |
| 108 | - processNotifyAlarm(take.getEvt()); | |
| 109 | - } else if (CmdType.MOBILE_POSITION.equals(cmd)) { | |
| 110 | - logger.info("接收到MobilePosition通知"); | |
| 111 | - processNotifyMobilePosition(take.getEvt()); | |
| 112 | - } else { | |
| 113 | - logger.info("接收到消息:" + cmd); | |
| 114 | - } | |
| 115 | - } catch (DocumentException e) { | |
| 116 | - throw new RuntimeException(e); | |
| 117 | - } | |
| 100 | + while (!taskQueue.isEmpty()) { | |
| 101 | + try { | |
| 102 | + HandlerCatchData take = taskQueue.poll(); | |
| 103 | + Element rootElement = getRootElement(take.getEvt()); | |
| 104 | + String cmd = XmlUtil.getText(rootElement, "CmdType"); | |
| 105 | + | |
| 106 | + if (CmdType.CATALOG.equals(cmd)) { | |
| 107 | + logger.info("接收到Catalog通知"); | |
| 108 | + processNotifyCatalogList(take.getEvt()); | |
| 109 | + } else if (CmdType.ALARM.equals(cmd)) { | |
| 110 | + logger.info("接收到Alarm通知"); | |
| 111 | + processNotifyAlarm(take.getEvt()); | |
| 112 | + } else if (CmdType.MOBILE_POSITION.equals(cmd)) { | |
| 113 | + logger.info("接收到MobilePosition通知"); | |
| 114 | + processNotifyMobilePosition(take.getEvt()); | |
| 115 | + } else { | |
| 116 | + logger.info("接收到消息:" + cmd); | |
| 118 | 117 | } |
| 119 | - taskQueueHandlerRun = false; | |
| 120 | - }); | |
| 118 | + } catch (DocumentException e) { | |
| 119 | + throw new RuntimeException(e); | |
| 120 | + } | |
| 121 | + } | |
| 122 | + taskQueueHandlerRun = false; | |
| 123 | + }); | |
| 121 | 124 | } |
| 122 | - | |
| 123 | - | |
| 124 | 125 | } catch (SipException | InvalidArgumentException | ParseException e) { |
| 125 | 126 | e.printStackTrace(); |
| 126 | 127 | } |
| ... | ... | @@ -170,31 +171,10 @@ public class NotifyRequestProcessor extends SIPRequestProcessorParent implements |
| 170 | 171 | } else { |
| 171 | 172 | mobilePosition.setAltitude(0.0); |
| 172 | 173 | } |
| 173 | - logger.info("[收到 移动位置订阅]:{}/{}->{}.{}", mobilePosition.getDeviceId(), mobilePosition.getChannelId(), | |
| 174 | + logger.info("[收到移动位置订阅通知]:{}/{}->{}.{}", mobilePosition.getDeviceId(), mobilePosition.getChannelId(), | |
| 174 | 175 | mobilePosition.getLongitude(), mobilePosition.getLatitude()); |
| 175 | 176 | mobilePosition.setReportSource("Mobile Position"); |
| 176 | - // 默认来源坐标系为WGS-84处理 | |
| 177 | - if ("WGS84".equals(device.getGeoCoordSys())) { | |
| 178 | - mobilePosition.setLongitudeWgs84(mobilePosition.getLongitude()); | |
| 179 | - mobilePosition.setLatitudeWgs84(mobilePosition.getLatitude()); | |
| 180 | - Double[] position = Coordtransform.WGS84ToGCJ02(mobilePosition.getLongitude(), mobilePosition.getLatitude()); | |
| 181 | - mobilePosition.setLongitudeGcj02(position[0]); | |
| 182 | - mobilePosition.setLatitudeGcj02(position[1]); | |
| 183 | - }else if ("GCJ02".equals(device.getGeoCoordSys())) { | |
| 184 | - mobilePosition.setLongitudeGcj02(mobilePosition.getLongitude()); | |
| 185 | - mobilePosition.setLatitudeGcj02(mobilePosition.getLatitude()); | |
| 186 | - Double[] position = Coordtransform.GCJ02ToWGS84(mobilePosition.getLongitude(), mobilePosition.getLatitude()); | |
| 187 | - mobilePosition.setLongitudeWgs84(position[0]); | |
| 188 | - mobilePosition.setLatitudeWgs84(position[1]); | |
| 189 | - }else { | |
| 190 | - mobilePosition.setLongitudeGcj02(0.00); | |
| 191 | - mobilePosition.setLatitudeGcj02(0.00); | |
| 192 | - mobilePosition.setLongitudeWgs84(0.00); | |
| 193 | - mobilePosition.setLatitudeWgs84(0.00); | |
| 194 | - } | |
| 195 | - if (userSetting.getSavePositionHistory()) { | |
| 196 | - storager.insertMobilePosition(mobilePosition); | |
| 197 | - } | |
| 177 | + | |
| 198 | 178 | |
| 199 | 179 | // 更新device channel 的经纬度 |
| 200 | 180 | DeviceChannel deviceChannel = new DeviceChannel(); |
| ... | ... | @@ -202,11 +182,18 @@ public class NotifyRequestProcessor extends SIPRequestProcessorParent implements |
| 202 | 182 | deviceChannel.setChannelId(channelId); |
| 203 | 183 | deviceChannel.setLongitude(mobilePosition.getLongitude()); |
| 204 | 184 | deviceChannel.setLatitude(mobilePosition.getLatitude()); |
| 205 | - deviceChannel.setLongitudeWgs84(mobilePosition.getLongitudeWgs84()); | |
| 206 | - deviceChannel.setLatitudeWgs84(mobilePosition.getLatitudeWgs84()); | |
| 207 | - deviceChannel.setLongitudeGcj02(mobilePosition.getLongitudeGcj02()); | |
| 208 | - deviceChannel.setLatitudeGcj02(mobilePosition.getLatitudeGcj02()); | |
| 209 | 185 | deviceChannel.setGpsTime(mobilePosition.getTime()); |
| 186 | + deviceChannel = deviceChannelService.updateGps(deviceChannel, device); | |
| 187 | + | |
| 188 | + mobilePosition.setLongitudeWgs84(deviceChannel.getLongitudeWgs84()); | |
| 189 | + mobilePosition.setLatitudeWgs84(deviceChannel.getLatitudeWgs84()); | |
| 190 | + mobilePosition.setLongitudeGcj02(deviceChannel.getLongitudeGcj02()); | |
| 191 | + mobilePosition.setLatitudeGcj02(deviceChannel.getLatitudeGcj02()); | |
| 192 | + | |
| 193 | + if (userSetting.getSavePositionHistory()) { | |
| 194 | + storager.insertMobilePosition(mobilePosition); | |
| 195 | + } | |
| 196 | + | |
| 210 | 197 | storager.updateChannelPosition(deviceChannel); |
| 211 | 198 | // 发送redis消息。 通知位置信息的变化 |
| 212 | 199 | JSONObject jsonObject = new JSONObject(); |
| ... | ... | @@ -281,38 +268,28 @@ public class NotifyRequestProcessor extends SIPRequestProcessorParent implements |
| 281 | 268 | mobilePosition.setLongitude(deviceAlarm.getLongitude()); |
| 282 | 269 | mobilePosition.setLatitude(deviceAlarm.getLatitude()); |
| 283 | 270 | mobilePosition.setReportSource("GPS Alarm"); |
| 284 | - if ("WGS84".equals(device.getGeoCoordSys())) { | |
| 285 | - mobilePosition.setLongitudeWgs84(mobilePosition.getLongitude()); | |
| 286 | - mobilePosition.setLatitudeWgs84(mobilePosition.getLatitude()); | |
| 287 | - Double[] position = Coordtransform.WGS84ToGCJ02(mobilePosition.getLongitude(), mobilePosition.getLatitude()); | |
| 288 | - mobilePosition.setLongitudeGcj02(position[0]); | |
| 289 | - mobilePosition.setLatitudeGcj02(position[1]); | |
| 290 | - }else if ("GCJ02".equals(device.getGeoCoordSys())) { | |
| 291 | - mobilePosition.setLongitudeGcj02(mobilePosition.getLongitude()); | |
| 292 | - mobilePosition.setLatitudeGcj02(mobilePosition.getLatitude()); | |
| 293 | - Double[] position = Coordtransform.GCJ02ToWGS84(mobilePosition.getLongitude(), mobilePosition.getLatitude()); | |
| 294 | - mobilePosition.setLongitudeWgs84(position[0]); | |
| 295 | - mobilePosition.setLatitudeWgs84(position[1]); | |
| 296 | - }else { | |
| 297 | - mobilePosition.setLongitudeGcj02(0.00); | |
| 298 | - mobilePosition.setLatitudeGcj02(0.00); | |
| 299 | - mobilePosition.setLongitudeWgs84(0.00); | |
| 300 | - mobilePosition.setLatitudeWgs84(0.00); | |
| 301 | - } | |
| 302 | - if (userSetting.getSavePositionHistory()) { | |
| 303 | - storager.insertMobilePosition(mobilePosition); | |
| 304 | - } | |
| 271 | + | |
| 272 | + | |
| 273 | + | |
| 305 | 274 | // 更新device channel 的经纬度 |
| 306 | 275 | DeviceChannel deviceChannel = new DeviceChannel(); |
| 307 | 276 | deviceChannel.setDeviceId(device.getDeviceId()); |
| 308 | 277 | deviceChannel.setChannelId(channelId); |
| 309 | 278 | deviceChannel.setLongitude(mobilePosition.getLongitude()); |
| 310 | 279 | deviceChannel.setLatitude(mobilePosition.getLatitude()); |
| 311 | - deviceChannel.setLongitudeWgs84(mobilePosition.getLongitudeWgs84()); | |
| 312 | - deviceChannel.setLatitudeWgs84(mobilePosition.getLatitudeWgs84()); | |
| 313 | - deviceChannel.setLongitudeGcj02(mobilePosition.getLongitudeGcj02()); | |
| 314 | - deviceChannel.setLatitudeGcj02(mobilePosition.getLatitudeGcj02()); | |
| 315 | 280 | deviceChannel.setGpsTime(mobilePosition.getTime()); |
| 281 | + | |
| 282 | + deviceChannel = deviceChannelService.updateGps(deviceChannel, device); | |
| 283 | + | |
| 284 | + mobilePosition.setLongitudeWgs84(deviceChannel.getLongitudeWgs84()); | |
| 285 | + mobilePosition.setLatitudeWgs84(deviceChannel.getLatitudeWgs84()); | |
| 286 | + mobilePosition.setLongitudeGcj02(deviceChannel.getLongitudeGcj02()); | |
| 287 | + mobilePosition.setLatitudeGcj02(deviceChannel.getLatitudeGcj02()); | |
| 288 | + | |
| 289 | + if (userSetting.getSavePositionHistory()) { | |
| 290 | + storager.insertMobilePosition(mobilePosition); | |
| 291 | + } | |
| 292 | + | |
| 316 | 293 | storager.updateChannelPosition(deviceChannel); |
| 317 | 294 | } |
| 318 | 295 | // TODO: 需要实现存储报警信息、报警分类 |
| ... | ... | @@ -338,7 +315,7 @@ public class NotifyRequestProcessor extends SIPRequestProcessorParent implements |
| 338 | 315 | |
| 339 | 316 | Device device = redisCatchStorage.getDevice(deviceId); |
| 340 | 317 | if (device == null || device.getOnline() == 0) { |
| 341 | - logger.warn("[收到 目录订阅]:{}, 但是设备已经离线", (device != null ? device.getDeviceId():"" )); | |
| 318 | + logger.warn("[收到目录订阅]:{}, 但是设备已经离线", (device != null ? device.getDeviceId():"" )); | |
| 342 | 319 | return; |
| 343 | 320 | } |
| 344 | 321 | Element rootElement = getRootElement(evt, device.getCharset()); |
| ... | ... | @@ -359,28 +336,28 @@ public class NotifyRequestProcessor extends SIPRequestProcessorParent implements |
| 359 | 336 | Element eventElement = itemDevice.element("Event"); |
| 360 | 337 | String event; |
| 361 | 338 | if (eventElement == null) { |
| 362 | - logger.warn("[收到 目录订阅]:{}, 但是Event为空, 设为默认值 ADD", (device != null ? device.getDeviceId():"" )); | |
| 339 | + logger.warn("[收到目录订阅]:{}, 但是Event为空, 设为默认值 ADD", (device != null ? device.getDeviceId():"" )); | |
| 363 | 340 | event = CatalogEvent.ADD; |
| 364 | 341 | }else { |
| 365 | 342 | event = eventElement.getText().toUpperCase(); |
| 366 | 343 | } |
| 367 | - DeviceChannel channel = XmlUtil.channelContentHander(itemDevice, device); | |
| 344 | + DeviceChannel channel = XmlUtil.channelContentHander(itemDevice, device, event); | |
| 368 | 345 | channel.setDeviceId(device.getDeviceId()); |
| 369 | - logger.info("[收到 目录订阅]:{}/{}", device.getDeviceId(), channel.getChannelId()); | |
| 346 | + logger.info("[收到目录订阅]:{}/{}", device.getDeviceId(), channel.getChannelId()); | |
| 370 | 347 | switch (event) { |
| 371 | 348 | case CatalogEvent.ON: |
| 372 | 349 | // 上线 |
| 373 | - logger.info("收到来自设备【{}】的通道【{}】上线通知", device.getDeviceId(), channel.getChannelId()); | |
| 350 | + logger.info("[收到通道上线通知] 来自设备: {}, 通道 {}", device.getDeviceId(), channel.getChannelId()); | |
| 374 | 351 | storager.deviceChannelOnline(deviceId, channel.getChannelId()); |
| 375 | 352 | break; |
| 376 | 353 | case CatalogEvent.OFF : |
| 377 | 354 | // 离线 |
| 378 | - logger.info("收到来自设备【{}】的通道【{}】离线通知", device.getDeviceId(), channel.getChannelId()); | |
| 355 | + logger.info("[收到通道离线通知] 来自设备: {}, 通道 {}", device.getDeviceId(), channel.getChannelId()); | |
| 379 | 356 | storager.deviceChannelOffline(deviceId, channel.getChannelId()); |
| 380 | 357 | break; |
| 381 | 358 | case CatalogEvent.VLOST: |
| 382 | 359 | // 视频丢失 |
| 383 | - logger.info("收到来自设备【{}】的通道【{}】视频丢失通知", device.getDeviceId(), channel.getChannelId()); | |
| 360 | + logger.info("[收到通道视频丢失通知] 来自设备: {}, 通道 {}", device.getDeviceId(), channel.getChannelId()); | |
| 384 | 361 | storager.deviceChannelOffline(deviceId, channel.getChannelId()); |
| 385 | 362 | break; |
| 386 | 363 | case CatalogEvent.DEFECT: |
| ... | ... | @@ -388,18 +365,18 @@ public class NotifyRequestProcessor extends SIPRequestProcessorParent implements |
| 388 | 365 | break; |
| 389 | 366 | case CatalogEvent.ADD: |
| 390 | 367 | // 增加 |
| 391 | - logger.info("收到来自设备【{}】的增加通道【{}】通知", device.getDeviceId(), channel.getChannelId()); | |
| 392 | - storager.updateChannel(deviceId, channel); | |
| 368 | + logger.info("[收到增加通道通知] 来自设备: {}, 通道 {}", device.getDeviceId(), channel.getChannelId()); | |
| 369 | + deviceChannelService.updateChannel(deviceId, channel); | |
| 393 | 370 | break; |
| 394 | 371 | case CatalogEvent.DEL: |
| 395 | 372 | // 删除 |
| 396 | - logger.info("收到来自设备【{}】的删除通道【{}】通知", device.getDeviceId(), channel.getChannelId()); | |
| 373 | + logger.info("[收到删除通道通知] 来自设备: {}, 通道 {}", device.getDeviceId(), channel.getChannelId()); | |
| 397 | 374 | storager.delChannel(deviceId, channel.getChannelId()); |
| 398 | 375 | break; |
| 399 | 376 | case CatalogEvent.UPDATE: |
| 400 | 377 | // 更新 |
| 401 | - logger.info("收到来自设备【{}】的更新通道【{}】通知", device.getDeviceId(), channel.getChannelId()); | |
| 402 | - storager.updateChannel(deviceId, channel); | |
| 378 | + logger.info("[收到更新通道通知] 来自设备: {}, 通道 {}", device.getDeviceId(), channel.getChannelId()); | |
| 379 | + deviceChannelService.updateChannel(deviceId, channel); | |
| 403 | 380 | break; |
| 404 | 381 | default: |
| 405 | 382 | logger.warn("[ NotifyCatalog ] event not found : {}", event ); | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/RegisterRequestProcessor.java
| ... | ... | @@ -143,6 +143,7 @@ public class RegisterRequestProcessor extends SIPRequestProcessorParent implemen |
| 143 | 143 | device.setGeoCoordSys("WGS84"); |
| 144 | 144 | device.setTreeType("CivilCode"); |
| 145 | 145 | device.setDeviceId(deviceId); |
| 146 | + device.setOnline(0); | |
| 146 | 147 | } |
| 147 | 148 | device.setIp(received); |
| 148 | 149 | device.setPort(rPort); | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/MessageRequestProcessor.java
| ... | ... | @@ -27,6 +27,7 @@ import javax.sip.SipException; |
| 27 | 27 | import javax.sip.address.SipURI; |
| 28 | 28 | import javax.sip.header.CSeqHeader; |
| 29 | 29 | import javax.sip.header.CallIdHeader; |
| 30 | +import javax.sip.message.Request; | |
| 30 | 31 | import javax.sip.message.Response; |
| 31 | 32 | import java.text.ParseException; |
| 32 | 33 | import java.util.Map; |
| ... | ... | @@ -68,22 +69,23 @@ public class MessageRequestProcessor extends SIPRequestProcessorParent implement |
| 68 | 69 | |
| 69 | 70 | @Override |
| 70 | 71 | public void process(RequestEvent evt) { |
| 72 | + SIPRequest sipRequest = (SIPRequest)evt.getRequest(); | |
| 71 | 73 | logger.debug("接收到消息:" + evt.getRequest()); |
| 72 | 74 | String deviceId = SipUtils.getUserIdFromFromHeader(evt.getRequest()); |
| 73 | - CallIdHeader callIdHeader = (CallIdHeader)evt.getRequest().getHeader(CallIdHeader.NAME); | |
| 75 | + CallIdHeader callIdHeader = sipRequest.getCallIdHeader(); | |
| 74 | 76 | // 先从会话内查找 |
| 75 | 77 | SsrcTransaction ssrcTransaction = sessionManager.getSsrcTransaction(null, null, callIdHeader.getCallId(), null); |
| 76 | - if (ssrcTransaction != null) { // 兼容海康 媒体通知 消息from字段不是设备ID的问题 | |
| 78 | + // 兼容海康 媒体通知 消息from字段不是设备ID的问题 | |
| 79 | + if (ssrcTransaction != null) { | |
| 77 | 80 | deviceId = ssrcTransaction.getDeviceId(); |
| 78 | 81 | } |
| 79 | 82 | // 查询设备是否存在 |
| 80 | - CSeqHeader cseqHeader = (CSeqHeader) evt.getRequest().getHeader(CSeqHeader.NAME); | |
| 81 | - String method = cseqHeader.getMethod(); | |
| 82 | 83 | Device device = redisCatchStorage.getDevice(deviceId); |
| 83 | 84 | // 查询上级平台是否存在 |
| 84 | 85 | ParentPlatform parentPlatform = storage.queryParentPlatByServerGBId(deviceId); |
| 85 | 86 | try { |
| 86 | 87 | if (device != null && parentPlatform != null) { |
| 88 | + | |
| 87 | 89 | logger.warn("[重复]平台与设备编号重复:{}", deviceId); |
| 88 | 90 | SIPRequest request = (SIPRequest) evt.getRequest(); |
| 89 | 91 | String hostAddress = request.getRemoteAddress().getHostAddress(); | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/NotifyMessageHandler.java
| ... | ... | @@ -9,6 +9,7 @@ import org.springframework.stereotype.Component; |
| 9 | 9 | /** |
| 10 | 10 | * 命令类型: 通知命令 |
| 11 | 11 | * 命令类型: 状态信息(心跳)报送, 报警通知, 媒体通知, 移动设备位置数据,语音广播通知(TODO), 设备预置位(TODO) |
| 12 | + * @author lin | |
| 12 | 13 | */ |
| 13 | 14 | @Component |
| 14 | 15 | public class NotifyMessageHandler extends MessageHandlerAbstract implements InitializingBean { | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/AlarmNotifyMessageHandler.java
| ... | ... | @@ -11,6 +11,7 @@ import com.genersoft.iot.vmp.gb28181.utils.Coordtransform; |
| 11 | 11 | import com.genersoft.iot.vmp.gb28181.utils.NumericUtil; |
| 12 | 12 | import com.genersoft.iot.vmp.gb28181.utils.XmlUtil; |
| 13 | 13 | import com.genersoft.iot.vmp.service.IDeviceAlarmService; |
| 14 | +import com.genersoft.iot.vmp.service.IDeviceChannelService; | |
| 14 | 15 | import com.genersoft.iot.vmp.storager.IRedisCatchStorage; |
| 15 | 16 | import com.genersoft.iot.vmp.storager.IVideoManagerStorage; |
| 16 | 17 | import com.genersoft.iot.vmp.utils.DateUtil; |
| ... | ... | @@ -58,6 +59,9 @@ public class AlarmNotifyMessageHandler extends SIPRequestProcessorParent impleme |
| 58 | 59 | @Autowired |
| 59 | 60 | private IDeviceAlarmService deviceAlarmService; |
| 60 | 61 | |
| 62 | + @Autowired | |
| 63 | + private IDeviceChannelService deviceChannelService; | |
| 64 | + | |
| 61 | 65 | @Override |
| 62 | 66 | public void afterPropertiesSet() throws Exception { |
| 63 | 67 | notifyMessageHandler.addHandler(cmdType, this); |
| ... | ... | @@ -65,7 +69,7 @@ public class AlarmNotifyMessageHandler extends SIPRequestProcessorParent impleme |
| 65 | 69 | |
| 66 | 70 | @Override |
| 67 | 71 | public void handForDevice(RequestEvent evt, Device device, Element rootElement) { |
| 68 | - logger.info("收到来自设备[{}]的报警通知", device.getDeviceId()); | |
| 72 | + logger.info("[收到报警通知]设备:{}", device.getDeviceId()); | |
| 69 | 73 | // 回复200 OK |
| 70 | 74 | try { |
| 71 | 75 | responseAck(evt, Response.OK); |
| ... | ... | @@ -119,38 +123,26 @@ public class AlarmNotifyMessageHandler extends SIPRequestProcessorParent impleme |
| 119 | 123 | mobilePosition.setLongitude(deviceAlarm.getLongitude()); |
| 120 | 124 | mobilePosition.setLatitude(deviceAlarm.getLatitude()); |
| 121 | 125 | mobilePosition.setReportSource("GPS Alarm"); |
| 122 | - if ("WGS84".equals(device.getGeoCoordSys())) { | |
| 123 | - mobilePosition.setLongitudeWgs84(mobilePosition.getLongitude()); | |
| 124 | - mobilePosition.setLatitudeWgs84(mobilePosition.getLatitude()); | |
| 125 | - Double[] position = Coordtransform.WGS84ToGCJ02(mobilePosition.getLongitude(), mobilePosition.getLatitude()); | |
| 126 | - mobilePosition.setLongitudeGcj02(position[0]); | |
| 127 | - mobilePosition.setLatitudeGcj02(position[1]); | |
| 128 | - }else if ("GCJ02".equals(device.getGeoCoordSys())) { | |
| 129 | - mobilePosition.setLongitudeGcj02(mobilePosition.getLongitude()); | |
| 130 | - mobilePosition.setLatitudeGcj02(mobilePosition.getLatitude()); | |
| 131 | - Double[] position = Coordtransform.GCJ02ToWGS84(mobilePosition.getLongitude(), mobilePosition.getLatitude()); | |
| 132 | - mobilePosition.setLongitudeWgs84(position[0]); | |
| 133 | - mobilePosition.setLatitudeWgs84(position[1]); | |
| 134 | - }else { | |
| 135 | - mobilePosition.setLongitudeGcj02(0.00); | |
| 136 | - mobilePosition.setLatitudeGcj02(0.00); | |
| 137 | - mobilePosition.setLongitudeWgs84(0.00); | |
| 138 | - mobilePosition.setLatitudeWgs84(0.00); | |
| 139 | - } | |
| 140 | - if (userSetting.getSavePositionHistory()) { | |
| 141 | - storager.insertMobilePosition(mobilePosition); | |
| 142 | - } | |
| 126 | + | |
| 127 | + | |
| 143 | 128 | // 更新device channel 的经纬度 |
| 144 | 129 | DeviceChannel deviceChannel = new DeviceChannel(); |
| 145 | 130 | deviceChannel.setDeviceId(device.getDeviceId()); |
| 146 | 131 | deviceChannel.setChannelId(channelId); |
| 147 | 132 | deviceChannel.setLongitude(mobilePosition.getLongitude()); |
| 148 | 133 | deviceChannel.setLatitude(mobilePosition.getLatitude()); |
| 149 | - deviceChannel.setLongitudeWgs84(mobilePosition.getLongitudeWgs84()); | |
| 150 | - deviceChannel.setLatitudeWgs84(mobilePosition.getLatitudeWgs84()); | |
| 151 | - deviceChannel.setLongitudeGcj02(mobilePosition.getLongitudeGcj02()); | |
| 152 | - deviceChannel.setLatitudeGcj02(mobilePosition.getLatitudeGcj02()); | |
| 153 | 134 | deviceChannel.setGpsTime(mobilePosition.getTime()); |
| 135 | + | |
| 136 | + deviceChannel = deviceChannelService.updateGps(deviceChannel, device); | |
| 137 | + | |
| 138 | + mobilePosition.setLongitudeWgs84(deviceChannel.getLongitudeWgs84()); | |
| 139 | + mobilePosition.setLatitudeWgs84(deviceChannel.getLatitudeWgs84()); | |
| 140 | + mobilePosition.setLongitudeGcj02(deviceChannel.getLongitudeGcj02()); | |
| 141 | + mobilePosition.setLatitudeGcj02(deviceChannel.getLatitudeGcj02()); | |
| 142 | + | |
| 143 | + if (userSetting.getSavePositionHistory()) { | |
| 144 | + storager.insertMobilePosition(mobilePosition); | |
| 145 | + } | |
| 154 | 146 | storager.updateChannelPosition(deviceChannel); |
| 155 | 147 | } |
| 156 | 148 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/CatalogNotifyMessageHandler.java
| ... | ... | @@ -58,85 +58,21 @@ public class CatalogNotifyMessageHandler extends SIPRequestProcessorParent imple |
| 58 | 58 | // 准备回复通道信息 |
| 59 | 59 | List<DeviceChannelInPlatform> deviceChannels = storage.queryChannelListInParentPlatform(parentPlatform.getServerGBId()); |
| 60 | 60 | // 查询关联的直播通道 |
| 61 | - List<GbStream> gbStreams = storage.queryGbStreamListInPlatform(parentPlatform.getServerGBId()); | |
| 61 | + List<DeviceChannel> gbStreams = storage.queryGbStreamListInPlatform(parentPlatform.getServerGBId()); | |
| 62 | + // 回复目录信息 | |
| 63 | + List<DeviceChannel> catalogs = storage.queryCatalogInPlatform(parentPlatform.getServerGBId()); | |
| 62 | 64 | |
| 63 | 65 | List<DeviceChannel> allChannels = new ArrayList<>(); |
| 64 | - // 回复目录信息 | |
| 65 | - List<PlatformCatalog> catalogs = storage.queryCatalogInPlatform(parentPlatform.getServerGBId()); | |
| 66 | 66 | if (catalogs.size() > 0) { |
| 67 | - for (PlatformCatalog catalog : catalogs) { | |
| 68 | - if (catalog.getParentId().equals(catalog.getPlatformId())) { | |
| 69 | - catalog.setParentId(parentPlatform.getDeviceGBId()); | |
| 70 | - } | |
| 71 | - DeviceChannel deviceChannel = new DeviceChannel(); | |
| 72 | - deviceChannel.setChannelId(catalog.getId()); | |
| 73 | - deviceChannel.setName(catalog.getName()); | |
| 74 | - deviceChannel.setLongitude(0.0); | |
| 75 | - deviceChannel.setLatitude(0.0); | |
| 76 | - deviceChannel.setDeviceId(parentPlatform.getDeviceGBId()); | |
| 77 | - deviceChannel.setManufacture("wvp-pro"); | |
| 78 | - deviceChannel.setStatus(1); | |
| 79 | - deviceChannel.setParental(1); | |
| 80 | - deviceChannel.setParentId(catalog.getParentId()); | |
| 81 | - deviceChannel.setRegisterWay(1); | |
| 82 | - if (catalog.getParentId() != null && catalog.getParentId().length() <= 10) { | |
| 83 | - deviceChannel.setCivilCode(catalog.getParentId()); | |
| 84 | - }else { | |
| 85 | - deviceChannel.setCivilCode(parentPlatform.getAdministrativeDivision()); | |
| 86 | - } | |
| 87 | - deviceChannel.setCivilCode(parentPlatform.getAdministrativeDivision()); | |
| 88 | - deviceChannel.setModel("live"); | |
| 89 | - deviceChannel.setOwner("wvp-pro"); | |
| 90 | - deviceChannel.setSecrecy("0"); | |
| 91 | - allChannels.add(deviceChannel); | |
| 92 | - } | |
| 67 | + allChannels.addAll(catalogs); | |
| 93 | 68 | } |
| 94 | 69 | // 回复级联的通道 |
| 95 | 70 | if (deviceChannels.size() > 0) { |
| 96 | - for (DeviceChannelInPlatform channel : deviceChannels) { | |
| 97 | - if (channel.getCatalogId().equals(parentPlatform.getServerGBId())) { | |
| 98 | - channel.setCatalogId(parentPlatform.getDeviceGBId()); | |
| 99 | - } | |
| 100 | - DeviceChannel deviceChannel = storage.queryChannel(channel.getDeviceId(), channel.getChannelId()); | |
| 101 | - deviceChannel.setParental(0); | |
| 102 | - deviceChannel.setParentId(channel.getCatalogId()); | |
| 103 | - if (channel.getCatalogId() != null && channel.getCatalogId().length() <= 10) { | |
| 104 | - channel.setCivilCode(channel.getCatalogId()); | |
| 105 | - }else { | |
| 106 | - deviceChannel.setCivilCode(parentPlatform.getAdministrativeDivision()); | |
| 107 | - } | |
| 108 | - | |
| 109 | - allChannels.add(deviceChannel); | |
| 110 | - } | |
| 71 | + allChannels.addAll(deviceChannels); | |
| 111 | 72 | } |
| 112 | 73 | // 回复直播的通道 |
| 113 | 74 | if (gbStreams.size() > 0) { |
| 114 | - for (GbStream gbStream : gbStreams) { | |
| 115 | - if (gbStream.getCatalogId().equals(parentPlatform.getServerGBId())) { | |
| 116 | - gbStream.setCatalogId(null); | |
| 117 | - } | |
| 118 | - DeviceChannel deviceChannel = new DeviceChannel(); | |
| 119 | - deviceChannel.setChannelId(gbStream.getGbId()); | |
| 120 | - deviceChannel.setName(gbStream.getName()); | |
| 121 | - deviceChannel.setLongitude(gbStream.getLongitude()); | |
| 122 | - deviceChannel.setLatitude(gbStream.getLatitude()); | |
| 123 | - deviceChannel.setDeviceId(parentPlatform.getDeviceGBId()); | |
| 124 | - deviceChannel.setManufacture("wvp-pro"); | |
| 125 | -// deviceChannel.setStatus(gbStream.isStatus()?1:0); | |
| 126 | - deviceChannel.setStatus(1); | |
| 127 | - deviceChannel.setParentId(gbStream.getCatalogId()); | |
| 128 | - deviceChannel.setRegisterWay(1); | |
| 129 | - if (gbStream.getCatalogId() != null && gbStream.getCatalogId().length() <= 10) { | |
| 130 | - deviceChannel.setCivilCode(gbStream.getCatalogId()); | |
| 131 | - }else { | |
| 132 | - deviceChannel.setCivilCode(parentPlatform.getAdministrativeDivision()); | |
| 133 | - } | |
| 134 | - deviceChannel.setModel("live"); | |
| 135 | - deviceChannel.setOwner("wvp-pro"); | |
| 136 | - deviceChannel.setParental(0); | |
| 137 | - deviceChannel.setSecrecy("0"); | |
| 138 | - allChannels.add(deviceChannel); | |
| 139 | - } | |
| 75 | + allChannels.addAll(gbStreams); | |
| 140 | 76 | } |
| 141 | 77 | if (allChannels.size() > 0) { |
| 142 | 78 | cmderFroPlatform.catalogQuery(allChannels, parentPlatform, sn, fromHeader.getTag()); | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/MobilePositionNotifyMessageHandler.java
| ... | ... | @@ -7,6 +7,7 @@ import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessag |
| 7 | 7 | import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.notify.NotifyMessageHandler; |
| 8 | 8 | import com.genersoft.iot.vmp.gb28181.utils.Coordtransform; |
| 9 | 9 | import com.genersoft.iot.vmp.gb28181.utils.NumericUtil; |
| 10 | +import com.genersoft.iot.vmp.service.IDeviceChannelService; | |
| 10 | 11 | import com.genersoft.iot.vmp.storager.IVideoManagerStorage; |
| 11 | 12 | import com.genersoft.iot.vmp.utils.DateUtil; |
| 12 | 13 | import com.genersoft.iot.vmp.utils.GpsUtil; |
| ... | ... | @@ -42,6 +43,9 @@ public class MobilePositionNotifyMessageHandler extends SIPRequestProcessorParen |
| 42 | 43 | @Autowired |
| 43 | 44 | private IVideoManagerStorage storager; |
| 44 | 45 | |
| 46 | + @Autowired | |
| 47 | + private IDeviceChannelService deviceChannelService; | |
| 48 | + | |
| 45 | 49 | @Override |
| 46 | 50 | public void afterPropertiesSet() throws Exception { |
| 47 | 51 | notifyMessageHandler.addHandler(cmdType, this); |
| ... | ... | @@ -79,38 +83,26 @@ public class MobilePositionNotifyMessageHandler extends SIPRequestProcessorParen |
| 79 | 83 | mobilePosition.setAltitude(0.0); |
| 80 | 84 | } |
| 81 | 85 | mobilePosition.setReportSource("Mobile Position"); |
| 82 | - if ("WGS84".equals(device.getGeoCoordSys())) { | |
| 83 | - mobilePosition.setLongitudeWgs84(mobilePosition.getLongitude()); | |
| 84 | - mobilePosition.setLatitudeWgs84(mobilePosition.getLatitude()); | |
| 85 | - Double[] position = Coordtransform.WGS84ToGCJ02(mobilePosition.getLongitude(), mobilePosition.getLatitude()); | |
| 86 | - mobilePosition.setLongitudeGcj02(position[0]); | |
| 87 | - mobilePosition.setLatitudeGcj02(position[1]); | |
| 88 | - }else if ("GCJ02".equals(device.getGeoCoordSys())) { | |
| 89 | - mobilePosition.setLongitudeGcj02(mobilePosition.getLongitude()); | |
| 90 | - mobilePosition.setLatitudeGcj02(mobilePosition.getLatitude()); | |
| 91 | - Double[] position = Coordtransform.GCJ02ToWGS84(mobilePosition.getLongitude(), mobilePosition.getLatitude()); | |
| 92 | - mobilePosition.setLongitudeWgs84(position[0]); | |
| 93 | - mobilePosition.setLatitudeWgs84(position[1]); | |
| 94 | - }else { | |
| 95 | - mobilePosition.setLongitudeGcj02(0.00); | |
| 96 | - mobilePosition.setLatitudeGcj02(0.00); | |
| 97 | - mobilePosition.setLongitudeWgs84(0.00); | |
| 98 | - mobilePosition.setLatitudeWgs84(0.00); | |
| 99 | - } | |
| 100 | - if (userSetting.getSavePositionHistory()) { | |
| 101 | - storager.insertMobilePosition(mobilePosition); | |
| 102 | - } | |
| 86 | + | |
| 87 | + | |
| 103 | 88 | // 更新device channel 的经纬度 |
| 104 | 89 | DeviceChannel deviceChannel = new DeviceChannel(); |
| 105 | 90 | deviceChannel.setDeviceId(device.getDeviceId()); |
| 106 | 91 | deviceChannel.setChannelId(mobilePosition.getChannelId()); |
| 107 | 92 | deviceChannel.setLongitude(mobilePosition.getLongitude()); |
| 108 | 93 | deviceChannel.setLatitude(mobilePosition.getLatitude()); |
| 109 | - deviceChannel.setLongitudeWgs84(mobilePosition.getLongitudeWgs84()); | |
| 110 | - deviceChannel.setLatitudeWgs84(mobilePosition.getLatitudeWgs84()); | |
| 111 | - deviceChannel.setLongitudeGcj02(mobilePosition.getLongitudeGcj02()); | |
| 112 | - deviceChannel.setLatitudeGcj02(mobilePosition.getLatitudeGcj02()); | |
| 113 | 94 | deviceChannel.setGpsTime(mobilePosition.getTime()); |
| 95 | + | |
| 96 | + deviceChannel = deviceChannelService.updateGps(deviceChannel, device); | |
| 97 | + | |
| 98 | + mobilePosition.setLongitudeWgs84(deviceChannel.getLongitudeWgs84()); | |
| 99 | + mobilePosition.setLatitudeWgs84(deviceChannel.getLatitudeWgs84()); | |
| 100 | + mobilePosition.setLongitudeGcj02(deviceChannel.getLongitudeGcj02()); | |
| 101 | + mobilePosition.setLatitudeGcj02(deviceChannel.getLatitudeGcj02()); | |
| 102 | + | |
| 103 | + if (userSetting.getSavePositionHistory()) { | |
| 104 | + storager.insertMobilePosition(mobilePosition); | |
| 105 | + } | |
| 114 | 106 | storager.updateChannelPosition(deviceChannel); |
| 115 | 107 | //回复 200 OK |
| 116 | 108 | responseAck(evt, Response.OK); | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/CatalogQueryMessageHandler.java
| ... | ... | @@ -70,86 +70,24 @@ public class CatalogQueryMessageHandler extends SIPRequestProcessorParent implem |
| 70 | 70 | Element snElement = rootElement.element("SN"); |
| 71 | 71 | String sn = snElement.getText(); |
| 72 | 72 | // 准备回复通道信息 |
| 73 | - List<DeviceChannelInPlatform> deviceChannelInPlatforms = storager.queryChannelListInParentPlatform(parentPlatform.getServerGBId()); | |
| 73 | + List<DeviceChannel> deviceChannelInPlatforms = storager.queryChannelWithCatalog(parentPlatform.getServerGBId()); | |
| 74 | 74 | // 查询关联的直播通道 |
| 75 | - List<GbStream> gbStreams = storager.queryGbStreamListInPlatform(parentPlatform.getServerGBId()); | |
| 75 | + List<DeviceChannel> gbStreams = storager.queryGbStreamListInPlatform(parentPlatform.getServerGBId()); | |
| 76 | 76 | // 回复目录信息 |
| 77 | - List<PlatformCatalog> catalogs = storager.queryCatalogInPlatform(parentPlatform.getServerGBId()); | |
| 77 | + List<DeviceChannel> catalogs = storager.queryCatalogInPlatform(parentPlatform.getServerGBId()); | |
| 78 | 78 | |
| 79 | 79 | List<DeviceChannel> allChannels = new ArrayList<>(); |
| 80 | + | |
| 80 | 81 | if (catalogs.size() > 0) { |
| 81 | - for (PlatformCatalog catalog : catalogs) { | |
| 82 | - if (catalog.getParentId().equals(catalog.getPlatformId())) { | |
| 83 | - catalog.setParentId(parentPlatform.getDeviceGBId()); | |
| 84 | - } | |
| 85 | - DeviceChannel deviceChannel = new DeviceChannel(); | |
| 86 | - // 通道的类型,0->国标通道 1->直播流通道 2->业务分组/虚拟组织/行政区划 | |
| 87 | - deviceChannel.setChannelType(2); | |
| 88 | - deviceChannel.setChannelId(catalog.getId()); | |
| 89 | - deviceChannel.setName(catalog.getName()); | |
| 90 | - deviceChannel.setDeviceId(parentPlatform.getDeviceGBId()); | |
| 91 | - deviceChannel.setManufacture("wvp-pro"); | |
| 92 | - deviceChannel.setStatus(1); | |
| 93 | - deviceChannel.setParental(1); | |
| 94 | - deviceChannel.setParentId(catalog.getParentId()); | |
| 95 | - deviceChannel.setRegisterWay(1); | |
| 96 | - if (catalog.getParentId() != null && catalog.getParentId().length() < 10) { | |
| 97 | - deviceChannel.setCivilCode(catalog.getParentId()); | |
| 98 | - }else { | |
| 99 | - deviceChannel.setCivilCode(parentPlatform.getAdministrativeDivision()); | |
| 100 | - } | |
| 101 | - allChannels.add(deviceChannel); | |
| 102 | - } | |
| 82 | + allChannels.addAll(catalogs); | |
| 103 | 83 | } |
| 104 | 84 | // 回复级联的通道 |
| 105 | 85 | if (deviceChannelInPlatforms.size() > 0) { |
| 106 | - for (DeviceChannelInPlatform channel : deviceChannelInPlatforms) { | |
| 107 | - if (channel.getCatalogId().equals(parentPlatform.getServerGBId())) { | |
| 108 | - channel.setCatalogId(parentPlatform.getDeviceGBId()); | |
| 109 | - } | |
| 110 | - DeviceChannel deviceChannel = storage.queryChannel(channel.getDeviceId(), channel.getChannelId()); | |
| 111 | - // 通道的类型,0->国标通道 1->直播流通道 2->业务分组/虚拟组织/行政区划 | |
| 112 | - deviceChannel.setChannelType(0); | |
| 113 | - deviceChannel.setParental(0); | |
| 114 | - deviceChannel.setParentId(channel.getCatalogId()); | |
| 115 | - if (channel.getCatalogId() != null && channel.getCatalogId().length() < 10) { | |
| 116 | - deviceChannel.setCivilCode(channel.getCatalogId()); | |
| 117 | - }else { | |
| 118 | - deviceChannel.setCivilCode(parentPlatform.getAdministrativeDivision()); | |
| 119 | - } | |
| 120 | - allChannels.add(deviceChannel); | |
| 121 | - } | |
| 86 | + allChannels.addAll(deviceChannelInPlatforms); | |
| 122 | 87 | } |
| 123 | 88 | // 回复直播的通道 |
| 124 | 89 | if (gbStreams.size() > 0) { |
| 125 | - for (GbStream gbStream : gbStreams) { | |
| 126 | - if (gbStream.getCatalogId().equals(parentPlatform.getServerGBId())) { | |
| 127 | - gbStream.setCatalogId(null); | |
| 128 | - } | |
| 129 | - DeviceChannel deviceChannel = new DeviceChannel(); | |
| 130 | - // 通道的类型,0->国标通道 1->直播流通道 2->业务分组/虚拟组织/行政区划 | |
| 131 | - deviceChannel.setChannelType(1); | |
| 132 | - deviceChannel.setChannelId(gbStream.getGbId()); | |
| 133 | - deviceChannel.setName(gbStream.getName()); | |
| 134 | - deviceChannel.setLongitude(gbStream.getLongitude()); | |
| 135 | - deviceChannel.setLatitude(gbStream.getLatitude()); | |
| 136 | - deviceChannel.setDeviceId(parentPlatform.getDeviceGBId()); | |
| 137 | - deviceChannel.setManufacture("wvp-pro"); | |
| 138 | -// deviceChannel.setStatus(gbStream.isStatus()?1:0); | |
| 139 | - deviceChannel.setStatus(1); | |
| 140 | - deviceChannel.setParentId(gbStream.getCatalogId()); | |
| 141 | - deviceChannel.setRegisterWay(1); | |
| 142 | - if (gbStream.getCatalogId() != null && gbStream.getCatalogId().length() < 10) { | |
| 143 | - deviceChannel.setCivilCode(gbStream.getCatalogId()); | |
| 144 | - }else { | |
| 145 | - deviceChannel.setCivilCode(parentPlatform.getAdministrativeDivision()); | |
| 146 | - } | |
| 147 | - deviceChannel.setModel("live"); | |
| 148 | - deviceChannel.setOwner("wvp-pro"); | |
| 149 | - deviceChannel.setParental(0); | |
| 150 | - deviceChannel.setSecrecy("0"); | |
| 151 | - allChannels.add(deviceChannel); | |
| 152 | - } | |
| 90 | + allChannels.addAll(gbStreams); | |
| 153 | 91 | } |
| 154 | 92 | if (allChannels.size() > 0) { |
| 155 | 93 | cmderFroPlatform.catalogQuery(allChannels, parentPlatform, sn, fromHeader.getTag()); | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/DeviceInfoQueryMessageHandler.java
| ... | ... | @@ -44,7 +44,7 @@ public class DeviceInfoQueryMessageHandler extends SIPRequestProcessorParent imp |
| 44 | 44 | |
| 45 | 45 | @Override |
| 46 | 46 | public void handForPlatform(RequestEvent evt, ParentPlatform parentPlatform, Element rootElement) { |
| 47 | - logger.info("接收到DeviceInfo查询消息"); | |
| 47 | + logger.info("[DeviceInfo查询]消息"); | |
| 48 | 48 | FromHeader fromHeader = (FromHeader) evt.getRequest().getHeader(FromHeader.NAME); |
| 49 | 49 | try { |
| 50 | 50 | // 回复200 OK | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/CatalogResponseMessageHandler.java
| ... | ... | @@ -111,6 +111,7 @@ public class CatalogResponseMessageHandler extends SIPRequestProcessorParent imp |
| 111 | 111 | int sumNum = Integer.parseInt(sumNumElement.getText()); |
| 112 | 112 | |
| 113 | 113 | if (sumNum == 0) { |
| 114 | + logger.info("[收到通道]设备:{}的: 0个", take.getDevice().getDeviceId()); | |
| 114 | 115 | // 数据已经完整接收 |
| 115 | 116 | storager.cleanChannelsForDevice(take.getDevice().getDeviceId()); |
| 116 | 117 | catalogDataCatch.setChannelSyncEnd(take.getDevice().getDeviceId(), null); |
| ... | ... | @@ -125,18 +126,14 @@ public class CatalogResponseMessageHandler extends SIPRequestProcessorParent imp |
| 125 | 126 | if (channelDeviceElement == null) { |
| 126 | 127 | continue; |
| 127 | 128 | } |
| 128 | - //by brewswang | |
| 129 | - // if (NumericUtil.isDouble(XmlUtil.getText(itemDevice, "Longitude"))) {//如果包含位置信息,就更新一下位置 | |
| 130 | - // processNotifyMobilePosition(evt, itemDevice); | |
| 131 | - // } | |
| 132 | - DeviceChannel deviceChannel = XmlUtil.channelContentHander(itemDevice, device); | |
| 129 | + DeviceChannel deviceChannel = XmlUtil.channelContentHander(itemDevice, device, null); | |
| 133 | 130 | deviceChannel.setDeviceId(take.getDevice().getDeviceId()); |
| 134 | 131 | |
| 135 | 132 | channelList.add(deviceChannel); |
| 136 | 133 | } |
| 137 | 134 | int sn = Integer.parseInt(snElement.getText()); |
| 138 | 135 | catalogDataCatch.put(take.getDevice().getDeviceId(), sn, sumNum, take.getDevice(), channelList); |
| 139 | - logger.info("收到来自设备【{}】的通道: {}个,{}/{}", take.getDevice().getDeviceId(), channelList.size(), catalogDataCatch.get(take.getDevice().getDeviceId()) == null ? 0 :catalogDataCatch.get(take.getDevice().getDeviceId()).size(), sumNum); | |
| 136 | + logger.info("[收到通道]设备: {} -> {}个,{}/{}", take.getDevice().getDeviceId(), channelList.size(), catalogDataCatch.get(take.getDevice().getDeviceId()) == null ? 0 :catalogDataCatch.get(take.getDevice().getDeviceId()).size(), sumNum); | |
| 140 | 137 | if (catalogDataCatch.get(take.getDevice().getDeviceId()).size() == sumNum) { |
| 141 | 138 | // 数据已经完整接收 |
| 142 | 139 | boolean resetChannelsResult = storager.resetChannels(take.getDevice().getDeviceId(), catalogDataCatch.get(take.getDevice().getDeviceId())); | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/DeviceInfoResponseMessageHandler.java
| ... | ... | @@ -87,7 +87,6 @@ public class DeviceInfoResponseMessageHandler extends SIPRequestProcessorParent |
| 87 | 87 | device.setStreamMode("UDP"); |
| 88 | 88 | } |
| 89 | 89 | deviceService.updateDevice(device); |
| 90 | -// storager.updateDevice(device); | |
| 91 | 90 | |
| 92 | 91 | RequestMessage msg = new RequestMessage(); |
| 93 | 92 | msg.setKey(key); | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/MobilePositionResponseMessageHandler.java
| ... | ... | @@ -7,6 +7,7 @@ import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessag |
| 7 | 7 | import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.ResponseMessageHandler; |
| 8 | 8 | import com.genersoft.iot.vmp.gb28181.utils.Coordtransform; |
| 9 | 9 | import com.genersoft.iot.vmp.gb28181.utils.NumericUtil; |
| 10 | +import com.genersoft.iot.vmp.service.IDeviceChannelService; | |
| 10 | 11 | import com.genersoft.iot.vmp.storager.IVideoManagerStorage; |
| 11 | 12 | import com.genersoft.iot.vmp.utils.DateUtil; |
| 12 | 13 | import com.genersoft.iot.vmp.utils.GpsUtil; |
| ... | ... | @@ -42,6 +43,9 @@ public class MobilePositionResponseMessageHandler extends SIPRequestProcessorPar |
| 42 | 43 | @Autowired |
| 43 | 44 | private IVideoManagerStorage storager; |
| 44 | 45 | |
| 46 | + @Autowired | |
| 47 | + private IDeviceChannelService deviceChannelService; | |
| 48 | + | |
| 45 | 49 | @Override |
| 46 | 50 | public void afterPropertiesSet() throws Exception { |
| 47 | 51 | responseMessageHandler.addHandler(cmdType, this); |
| ... | ... | @@ -79,38 +83,25 @@ public class MobilePositionResponseMessageHandler extends SIPRequestProcessorPar |
| 79 | 83 | mobilePosition.setAltitude(0.0); |
| 80 | 84 | } |
| 81 | 85 | mobilePosition.setReportSource("Mobile Position"); |
| 82 | - if ("WGS84".equals(device.getGeoCoordSys())) { | |
| 83 | - mobilePosition.setLongitudeWgs84(mobilePosition.getLongitude()); | |
| 84 | - mobilePosition.setLatitudeWgs84(mobilePosition.getLatitude()); | |
| 85 | - Double[] position = Coordtransform.WGS84ToGCJ02(mobilePosition.getLongitude(), mobilePosition.getLatitude()); | |
| 86 | - mobilePosition.setLongitudeGcj02(position[0]); | |
| 87 | - mobilePosition.setLatitudeGcj02(position[1]); | |
| 88 | - }else if ("GCJ02".equals(device.getGeoCoordSys())) { | |
| 89 | - mobilePosition.setLongitudeGcj02(mobilePosition.getLongitude()); | |
| 90 | - mobilePosition.setLatitudeGcj02(mobilePosition.getLatitude()); | |
| 91 | - Double[] position = Coordtransform.GCJ02ToWGS84(mobilePosition.getLongitude(), mobilePosition.getLatitude()); | |
| 92 | - mobilePosition.setLongitudeWgs84(position[0]); | |
| 93 | - mobilePosition.setLatitudeWgs84(position[1]); | |
| 94 | - }else { | |
| 95 | - mobilePosition.setLongitudeGcj02(0.00); | |
| 96 | - mobilePosition.setLatitudeGcj02(0.00); | |
| 97 | - mobilePosition.setLongitudeWgs84(0.00); | |
| 98 | - mobilePosition.setLatitudeWgs84(0.00); | |
| 99 | - } | |
| 100 | - if (userSetting.getSavePositionHistory()) { | |
| 101 | - storager.insertMobilePosition(mobilePosition); | |
| 102 | - } | |
| 86 | + | |
| 103 | 87 | // 更新device channel 的经纬度 |
| 104 | 88 | DeviceChannel deviceChannel = new DeviceChannel(); |
| 105 | 89 | deviceChannel.setDeviceId(device.getDeviceId()); |
| 106 | 90 | deviceChannel.setChannelId(mobilePosition.getChannelId()); |
| 107 | 91 | deviceChannel.setLongitude(mobilePosition.getLongitude()); |
| 108 | 92 | deviceChannel.setLatitude(mobilePosition.getLatitude()); |
| 109 | - deviceChannel.setLongitudeWgs84(mobilePosition.getLongitudeWgs84()); | |
| 110 | - deviceChannel.setLatitudeWgs84(mobilePosition.getLatitudeWgs84()); | |
| 111 | - deviceChannel.setLongitudeGcj02(mobilePosition.getLongitudeGcj02()); | |
| 112 | - deviceChannel.setLatitudeGcj02(mobilePosition.getLatitudeGcj02()); | |
| 113 | 93 | deviceChannel.setGpsTime(mobilePosition.getTime()); |
| 94 | + | |
| 95 | + deviceChannel = deviceChannelService.updateGps(deviceChannel, device); | |
| 96 | + | |
| 97 | + mobilePosition.setLongitudeWgs84(deviceChannel.getLongitudeWgs84()); | |
| 98 | + mobilePosition.setLatitudeWgs84(deviceChannel.getLatitudeWgs84()); | |
| 99 | + mobilePosition.setLongitudeGcj02(deviceChannel.getLongitudeGcj02()); | |
| 100 | + mobilePosition.setLatitudeGcj02(deviceChannel.getLatitudeGcj02()); | |
| 101 | + | |
| 102 | + if (userSetting.getSavePositionHistory()) { | |
| 103 | + storager.insertMobilePosition(mobilePosition); | |
| 104 | + } | |
| 114 | 105 | storager.updateChannelPosition(deviceChannel); |
| 115 | 106 | //回复 200 OK |
| 116 | 107 | responseAck(evt, Response.OK); | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/response/impl/RegisterResponseProcessor.java
| ... | ... | @@ -26,7 +26,7 @@ import javax.sip.message.Response; |
| 26 | 26 | @Component |
| 27 | 27 | public class RegisterResponseProcessor extends SIPResponseProcessorAbstract { |
| 28 | 28 | |
| 29 | - private Logger logger = LoggerFactory.getLogger(RegisterResponseProcessor.class); | |
| 29 | + private final Logger logger = LoggerFactory.getLogger(RegisterResponseProcessor.class); | |
| 30 | 30 | private final String method = "REGISTER"; |
| 31 | 31 | |
| 32 | 32 | @Autowired |
| ... | ... | @@ -69,11 +69,11 @@ public class RegisterResponseProcessor extends SIPResponseProcessorAbstract { |
| 69 | 69 | |
| 70 | 70 | ParentPlatformCatch parentPlatformCatch = redisCatchStorage.queryPlatformCatchInfo(platformGBId); |
| 71 | 71 | if (parentPlatformCatch == null) { |
| 72 | - logger.warn(String.format("收到 %s 的注册/注销%S请求, 但是平台缓存信息未查询到!!!", platformGBId, response.getStatusCode())); | |
| 72 | + logger.warn(String.format("[收到注册/注销%S请求]平台:%s,但是平台缓存信息未查询到!!!", response.getStatusCode(),platformGBId)); | |
| 73 | 73 | return; |
| 74 | 74 | } |
| 75 | 75 | String action = parentPlatformCatch.getParentPlatform().getExpires().equals("0") ? "注销" : "注册"; |
| 76 | - logger.info(String.format("收到 %s %s的%S响应", platformGBId, action, response.getStatusCode() )); | |
| 76 | + logger.info(String.format("[%s %S响应]%s ", action, response.getStatusCode(), platformGBId )); | |
| 77 | 77 | ParentPlatform parentPlatform = parentPlatformCatch.getParentPlatform(); |
| 78 | 78 | if (parentPlatform == null) { |
| 79 | 79 | logger.warn(String.format("收到 %s %s的%S请求, 但是平台信息未查询到!!!", platformGBId, action, response.getStatusCode())); | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/utils/SipUtils.java
| ... | ... | @@ -23,9 +23,10 @@ public class SipUtils { |
| 23 | 23 | /** |
| 24 | 24 | * 从subject读取channelId |
| 25 | 25 | * */ |
| 26 | - public static String getChannelIdFromHeader(Request request) { | |
| 26 | + public static String getChannelIdFromRequest(Request request) { | |
| 27 | 27 | Header subject = request.getHeader("subject"); |
| 28 | 28 | if (subject == null) { |
| 29 | + // 如果缺失subject | |
| 29 | 30 | return null; |
| 30 | 31 | } |
| 31 | 32 | return ((Subject) subject).getSubject().split(":")[0]; | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/utils/XmlUtil.java
| ... | ... | @@ -4,6 +4,8 @@ import com.alibaba.fastjson.JSONArray; |
| 4 | 4 | import com.alibaba.fastjson.JSONObject; |
| 5 | 5 | import com.genersoft.iot.vmp.gb28181.bean.Device; |
| 6 | 6 | import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; |
| 7 | +import com.genersoft.iot.vmp.gb28181.bean.TreeType; | |
| 8 | +import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent; | |
| 7 | 9 | import com.genersoft.iot.vmp.utils.DateUtil; |
| 8 | 10 | import org.dom4j.Attribute; |
| 9 | 11 | import org.dom4j.Document; |
| ... | ... | @@ -29,7 +31,7 @@ public class XmlUtil { |
| 29 | 31 | /** |
| 30 | 32 | * 日志服务 |
| 31 | 33 | */ |
| 32 | - private static Logger LOG = LoggerFactory.getLogger(XmlUtil.class); | |
| 34 | + private static Logger logger = LoggerFactory.getLogger(XmlUtil.class); | |
| 33 | 35 | |
| 34 | 36 | /** |
| 35 | 37 | * 解析XML为Document对象 |
| ... | ... | @@ -46,7 +48,7 @@ public class XmlUtil { |
| 46 | 48 | try { |
| 47 | 49 | document = saxReader.read(sr); |
| 48 | 50 | } catch (DocumentException e) { |
| 49 | - LOG.error("解析失败", e); | |
| 51 | + logger.error("解析失败", e); | |
| 50 | 52 | } |
| 51 | 53 | return null == document ? null : document.getRootElement(); |
| 52 | 54 | } |
| ... | ... | @@ -182,47 +184,69 @@ public class XmlUtil { |
| 182 | 184 | return xml.getRootElement(); |
| 183 | 185 | } |
| 184 | 186 | |
| 185 | - public static DeviceChannel channelContentHander(Element itemDevice, Device device){ | |
| 186 | - Element channdelNameElement = itemDevice.element("Name"); | |
| 187 | - String channelName = channdelNameElement != null ? channdelNameElement.getTextTrim().toString() : ""; | |
| 188 | - Element statusElement = itemDevice.element("Status"); | |
| 189 | - String status = statusElement != null ? statusElement.getTextTrim().toString() : "ON"; | |
| 187 | + private enum ChannelType{ | |
| 188 | + CivilCode, BusinessGroup,VirtualOrganization,Other | |
| 189 | + } | |
| 190 | + | |
| 191 | + public static DeviceChannel channelContentHander(Element itemDevice, Device device, String event){ | |
| 190 | 192 | DeviceChannel deviceChannel = new DeviceChannel(); |
| 191 | - deviceChannel.setName(channelName); | |
| 193 | + deviceChannel.setDeviceId(device.getDeviceId()); | |
| 192 | 194 | Element channdelIdElement = itemDevice.element("DeviceID"); |
| 193 | - String channelId = channdelIdElement != null ? channdelIdElement.getTextTrim().toString() : ""; | |
| 195 | + if (channdelIdElement == null) { | |
| 196 | + logger.warn("解析Catalog消息时发现缺少 DeviceID"); | |
| 197 | + return null; | |
| 198 | + } | |
| 199 | + String channelId = channdelIdElement.getTextTrim(); | |
| 200 | + if (StringUtils.isEmpty(channelId)) { | |
| 201 | + logger.warn("解析Catalog消息时发现缺少 DeviceID"); | |
| 202 | + return null; | |
| 203 | + } | |
| 194 | 204 | deviceChannel.setChannelId(channelId); |
| 195 | - // ONLINE OFFLINE HIKVISION DS-7716N-E4 NVR的兼容性处理 | |
| 196 | - if (status.equals("ON") || status.equals("On") || status.equals("ONLINE") || status.equals("OK")) { | |
| 197 | - deviceChannel.setStatus(1); | |
| 205 | + if (event != null && !event.equals(CatalogEvent.ADD) && !event.equals(CatalogEvent.UPDATE)) { | |
| 206 | + // 除了ADD和update情况下需要识别全部内容, | |
| 207 | + return deviceChannel; | |
| 198 | 208 | } |
| 199 | - if (status.equals("OFF") || status.equals("Off") || status.equals("OFFLINE")) { | |
| 200 | - deviceChannel.setStatus(0); | |
| 209 | + | |
| 210 | + ChannelType channelType = ChannelType.Other; | |
| 211 | + if (channelId.length() <= 8) { | |
| 212 | + channelType = ChannelType.CivilCode; | |
| 213 | + }else { | |
| 214 | + if (channelId.length() == 20) { | |
| 215 | + int code = Integer.parseInt(channelId.substring(10, 13)); | |
| 216 | + switch (code){ | |
| 217 | + case 215: | |
| 218 | + channelType = ChannelType.BusinessGroup; | |
| 219 | + break; | |
| 220 | + case 216: | |
| 221 | + channelType = ChannelType.VirtualOrganization; | |
| 222 | + break; | |
| 223 | + default: | |
| 224 | + break; | |
| 225 | + | |
| 226 | + } | |
| 227 | + } | |
| 201 | 228 | } |
| 202 | 229 | |
| 203 | - deviceChannel.setManufacture(XmlUtil.getText(itemDevice, "Manufacturer")); | |
| 204 | - deviceChannel.setModel(XmlUtil.getText(itemDevice, "Model")); | |
| 205 | - deviceChannel.setOwner(XmlUtil.getText(itemDevice, "Owner")); | |
| 206 | - deviceChannel.setCivilCode(XmlUtil.getText(itemDevice, "CivilCode")); | |
| 207 | - deviceChannel.setBlock(XmlUtil.getText(itemDevice, "Block")); | |
| 208 | - deviceChannel.setAddress(XmlUtil.getText(itemDevice, "Address")); | |
| 209 | - String businessGroupID = XmlUtil.getText(itemDevice, "BusinessGroupID"); | |
| 210 | - if (XmlUtil.getText(itemDevice, "Parental") == null | |
| 211 | - || XmlUtil.getText(itemDevice, "Parental").equals("")) { | |
| 212 | - if (deviceChannel.getChannelId().length() <= 10 | |
| 213 | - || (deviceChannel.getChannelId().length() == 20 && ( | |
| 214 | - Integer.parseInt(deviceChannel.getChannelId().substring(10, 13)) == 215 | |
| 215 | - || Integer.parseInt(deviceChannel.getChannelId().substring(10, 13)) == 216 | |
| 216 | - ) | |
| 217 | - ) | |
| 218 | - ) { | |
| 219 | - deviceChannel.setParental(1); | |
| 220 | - }else { | |
| 221 | - deviceChannel.setParental(0); | |
| 230 | + Element channdelNameElement = itemDevice.element("Name"); | |
| 231 | + String channelName = channdelNameElement != null ? channdelNameElement.getTextTrim() : ""; | |
| 232 | + deviceChannel.setName(channelName); | |
| 233 | + | |
| 234 | + String civilCode = XmlUtil.getText(itemDevice, "CivilCode"); | |
| 235 | + deviceChannel.setCivilCode(civilCode); | |
| 236 | + if (channelType == ChannelType.CivilCode && civilCode == null) { | |
| 237 | + deviceChannel.setParental(1); | |
| 238 | + // 行政区划如果没有传递具体值,则推测一个 | |
| 239 | + if (channelId.length() > 2) { | |
| 240 | + deviceChannel.setCivilCode(channelId.substring(0, channelId.length() - 2)); | |
| 222 | 241 | } |
| 223 | - } else { | |
| 224 | - // 由于海康会错误的发送65535作为这里的取值,所以这里除非是0否则认为是1 | |
| 225 | - deviceChannel.setParental(Integer.parseInt(XmlUtil.getText(itemDevice, "Parental")) == 1?1:0); | |
| 242 | + } | |
| 243 | + if (channelType.equals(ChannelType.CivilCode)) { | |
| 244 | + // 行政区划其他字段没必要识别了,默认在线即可 | |
| 245 | + deviceChannel.setStatus(1); | |
| 246 | + deviceChannel.setParental(1); | |
| 247 | + deviceChannel.setCreateTime(DateUtil.getNow()); | |
| 248 | + deviceChannel.setUpdateTime(DateUtil.getNow()); | |
| 249 | + return deviceChannel; | |
| 226 | 250 | } |
| 227 | 251 | /** |
| 228 | 252 | * 行政区划展示设备树与业务分组展示设备树是两种不同的模式 |
| ... | ... | @@ -230,7 +254,17 @@ public class XmlUtil { |
| 230 | 254 | * 河北省 |
| 231 | 255 | * --> 石家庄市 |
| 232 | 256 | * --> 摄像头 |
| 233 | - * --> 正定县 | |
| 257 | + *String parentId = XmlUtil.getText(itemDevice, "ParentID"); | |
| 258 | + if (parentId != null) { | |
| 259 | + if (parentId.contains("/")) { | |
| 260 | + String lastParentId = parentId.substring(parentId.lastIndexOf("/") + 1); | |
| 261 | + String businessGroup = parentId.substring(0, parentId.indexOf("/")); | |
| 262 | + deviceChannel.setParentId(lastParentId); | |
| 263 | + }else { | |
| 264 | + deviceChannel.setParentId(parentId); | |
| 265 | + } | |
| 266 | + } | |
| 267 | + deviceCh --> 正定县 | |
| 234 | 268 | * --> 摄像头 |
| 235 | 269 | * --> 摄像头 |
| 236 | 270 | * |
| ... | ... | @@ -243,59 +277,88 @@ public class XmlUtil { |
| 243 | 277 | * --> 摄像头 |
| 244 | 278 | */ |
| 245 | 279 | String parentId = XmlUtil.getText(itemDevice, "ParentID"); |
| 280 | + String businessGroupID = XmlUtil.getText(itemDevice, "BusinessGroupID"); | |
| 246 | 281 | if (parentId != null) { |
| 247 | 282 | if (parentId.contains("/")) { |
| 248 | 283 | String lastParentId = parentId.substring(parentId.lastIndexOf("/") + 1); |
| 284 | + if (businessGroupID == null) { | |
| 285 | + businessGroupID = parentId.substring(0, parentId.indexOf("/")); | |
| 286 | + } | |
| 249 | 287 | deviceChannel.setParentId(lastParentId); |
| 250 | 288 | }else { |
| 251 | 289 | deviceChannel.setParentId(parentId); |
| 252 | 290 | } |
| 253 | 291 | } |
| 254 | 292 | deviceChannel.setBusinessGroupId(businessGroupID); |
| 293 | + if (channelType.equals(ChannelType.BusinessGroup) || channelType.equals(ChannelType.VirtualOrganization)) { | |
| 294 | + // 业务分组和虚拟组织 其他字段没必要识别了,默认在线即可 | |
| 295 | + deviceChannel.setStatus(1); | |
| 296 | + deviceChannel.setParental(1); | |
| 297 | + deviceChannel.setCreateTime(DateUtil.getNow()); | |
| 298 | + deviceChannel.setUpdateTime(DateUtil.getNow()); | |
| 299 | + return deviceChannel; | |
| 300 | + } | |
| 255 | 301 | |
| 256 | -// else { | |
| 257 | -// if (deviceChannel.getChannelId().length() <= 10) { // 此时为行政区划, 上下级行政区划使用DeviceId关联 | |
| 258 | -// deviceChannel.setParentId(deviceChannel.getChannelId().substring(0, deviceChannel.getChannelId().length() - 2)); | |
| 259 | -// }else if (deviceChannel.getChannelId().length() == 20) { | |
| 260 | -// if (Integer.parseInt(deviceChannel.getChannelId().substring(10, 13)) == 216) { // 虚拟组织 | |
| 261 | -// deviceChannel.setBusinessGroupId(businessGroupID); | |
| 262 | -// }else if (Integer.parseInt(device.getDeviceId().substring(10, 13) )== 118) {//NVR 如果上级设备编号是NVR则直接将NVR的编号设置给通道的上级编号 | |
| 263 | -// deviceChannel.setParentId(device.getDeviceId()); | |
| 264 | -// }else if (deviceChannel.getCivilCode() != null) { | |
| 265 | -// // 设备, 无parentId的20位是使用CivilCode表示上级的设备, | |
| 266 | -// // 注:215 业务分组是需要有parentId的 | |
| 267 | -// deviceChannel.setParentId(deviceChannel.getCivilCode()); | |
| 268 | -// } | |
| 269 | -// }else { | |
| 270 | -// deviceChannel.setParentId(deviceChannel.getDeviceId()); | |
| 271 | -// } | |
| 272 | -// } | |
| 273 | - | |
| 274 | - if (XmlUtil.getText(itemDevice, "SafetyWay") == null | |
| 275 | - || XmlUtil.getText(itemDevice, "SafetyWay") == "") { | |
| 302 | + Element statusElement = itemDevice.element("Status"); | |
| 303 | + | |
| 304 | + if (statusElement != null) { | |
| 305 | + String status = statusElement.getTextTrim().trim(); | |
| 306 | + // ONLINE OFFLINE HIKVISION DS-7716N-E4 NVR的兼容性处理 | |
| 307 | + if (status.equals("ON") || status.equals("On") || status.equals("ONLINE") || status.equals("OK")) { | |
| 308 | + deviceChannel.setStatus(1); | |
| 309 | + } | |
| 310 | + if (status.equals("OFF") || status.equals("Off") || status.equals("OFFLINE")) { | |
| 311 | + deviceChannel.setStatus(0); | |
| 312 | + } | |
| 313 | + }else { | |
| 314 | + deviceChannel.setStatus(1); | |
| 315 | + } | |
| 316 | + // 识别自带的目录标识 | |
| 317 | + String parental = XmlUtil.getText(itemDevice, "Parental"); | |
| 318 | + // 由于海康会错误的发送65535作为这里的取值,所以这里除非是0否则认为是1 | |
| 319 | + if (!StringUtils.isEmpty(parental) && parental.length() == 1 && Integer.parseInt(parental) == 0) { | |
| 320 | + deviceChannel.setParental(0); | |
| 321 | + }else { | |
| 322 | + deviceChannel.setParental(1); | |
| 323 | + } | |
| 324 | + | |
| 325 | + | |
| 326 | + deviceChannel.setManufacture(XmlUtil.getText(itemDevice, "Manufacturer")); | |
| 327 | + deviceChannel.setModel(XmlUtil.getText(itemDevice, "Model")); | |
| 328 | + deviceChannel.setOwner(XmlUtil.getText(itemDevice, "Owner")); | |
| 329 | + deviceChannel.setCertNum(XmlUtil.getText(itemDevice, "CertNum")); | |
| 330 | + deviceChannel.setBlock(XmlUtil.getText(itemDevice, "Block")); | |
| 331 | + deviceChannel.setAddress(XmlUtil.getText(itemDevice, "Address")); | |
| 332 | + deviceChannel.setPassword(XmlUtil.getText(itemDevice, "Password")); | |
| 333 | + | |
| 334 | + String safetyWay = XmlUtil.getText(itemDevice, "SafetyWay"); | |
| 335 | + if (StringUtils.isEmpty(safetyWay)) { | |
| 276 | 336 | deviceChannel.setSafetyWay(0); |
| 277 | 337 | } else { |
| 278 | - deviceChannel.setSafetyWay(Integer.parseInt(XmlUtil.getText(itemDevice, "SafetyWay"))); | |
| 338 | + deviceChannel.setSafetyWay(Integer.parseInt(safetyWay)); | |
| 279 | 339 | } |
| 280 | - if (XmlUtil.getText(itemDevice, "RegisterWay") == null | |
| 281 | - || XmlUtil.getText(itemDevice, "RegisterWay") == "") { | |
| 340 | + | |
| 341 | + String registerWay = XmlUtil.getText(itemDevice, "RegisterWay"); | |
| 342 | + if (StringUtils.isEmpty(registerWay)) { | |
| 282 | 343 | deviceChannel.setRegisterWay(1); |
| 283 | 344 | } else { |
| 284 | - deviceChannel.setRegisterWay(Integer.parseInt(XmlUtil.getText(itemDevice, "RegisterWay"))); | |
| 345 | + deviceChannel.setRegisterWay(Integer.parseInt(registerWay)); | |
| 285 | 346 | } |
| 286 | - deviceChannel.setCertNum(XmlUtil.getText(itemDevice, "CertNum")); | |
| 347 | + | |
| 287 | 348 | if (XmlUtil.getText(itemDevice, "Certifiable") == null |
| 288 | 349 | || XmlUtil.getText(itemDevice, "Certifiable") == "") { |
| 289 | 350 | deviceChannel.setCertifiable(0); |
| 290 | 351 | } else { |
| 291 | 352 | deviceChannel.setCertifiable(Integer.parseInt(XmlUtil.getText(itemDevice, "Certifiable"))); |
| 292 | 353 | } |
| 354 | + | |
| 293 | 355 | if (XmlUtil.getText(itemDevice, "ErrCode") == null |
| 294 | 356 | || XmlUtil.getText(itemDevice, "ErrCode") == "") { |
| 295 | 357 | deviceChannel.setErrCode(0); |
| 296 | 358 | } else { |
| 297 | 359 | deviceChannel.setErrCode(Integer.parseInt(XmlUtil.getText(itemDevice, "ErrCode"))); |
| 298 | 360 | } |
| 361 | + | |
| 299 | 362 | deviceChannel.setEndTime(XmlUtil.getText(itemDevice, "EndTime")); |
| 300 | 363 | deviceChannel.setSecrecy(XmlUtil.getText(itemDevice, "Secrecy")); |
| 301 | 364 | deviceChannel.setIpAddress(XmlUtil.getText(itemDevice, "IPAddress")); |
| ... | ... | @@ -304,43 +367,23 @@ public class XmlUtil { |
| 304 | 367 | } else { |
| 305 | 368 | deviceChannel.setPort(Integer.parseInt(XmlUtil.getText(itemDevice, "Port"))); |
| 306 | 369 | } |
| 307 | - deviceChannel.setPassword(XmlUtil.getText(itemDevice, "Password")); | |
| 308 | - if (NumericUtil.isDouble(XmlUtil.getText(itemDevice, "Longitude"))) { | |
| 309 | - deviceChannel.setLongitude(Double.parseDouble(XmlUtil.getText(itemDevice, "Longitude"))); | |
| 370 | + | |
| 371 | + | |
| 372 | + String longitude = XmlUtil.getText(itemDevice, "Longitude"); | |
| 373 | + if (NumericUtil.isDouble(longitude)) { | |
| 374 | + deviceChannel.setLongitude(Double.parseDouble(longitude)); | |
| 310 | 375 | } else { |
| 311 | 376 | deviceChannel.setLongitude(0.00); |
| 312 | 377 | } |
| 313 | - if (NumericUtil.isDouble(XmlUtil.getText(itemDevice, "Latitude"))) { | |
| 314 | - deviceChannel.setLatitude(Double.parseDouble(XmlUtil.getText(itemDevice, "Latitude"))); | |
| 378 | + String latitude = XmlUtil.getText(itemDevice, "Latitude"); | |
| 379 | + if (NumericUtil.isDouble(latitude)) { | |
| 380 | + deviceChannel.setLatitude(Double.parseDouble(latitude)); | |
| 315 | 381 | } else { |
| 316 | 382 | deviceChannel.setLatitude(0.00); |
| 317 | 383 | } |
| 318 | 384 | deviceChannel.setGpsTime(DateUtil.getNow()); |
| 319 | - if (deviceChannel.getLongitude()*deviceChannel.getLatitude() > 0) { | |
| 320 | - if ("WGS84".equals(device.getGeoCoordSys())) { | |
| 321 | - deviceChannel.setLongitudeWgs84(deviceChannel.getLongitude()); | |
| 322 | - deviceChannel.setLatitudeWgs84(deviceChannel.getLatitude()); | |
| 323 | - Double[] position = Coordtransform.WGS84ToGCJ02(deviceChannel.getLongitude(), deviceChannel.getLatitude()); | |
| 324 | - deviceChannel.setLongitudeGcj02(position[0]); | |
| 325 | - deviceChannel.setLatitudeGcj02(position[1]); | |
| 326 | - }else if ("GCJ02".equals(device.getGeoCoordSys())) { | |
| 327 | - deviceChannel.setLongitudeGcj02(deviceChannel.getLongitude()); | |
| 328 | - deviceChannel.setLatitudeGcj02(deviceChannel.getLatitude()); | |
| 329 | - Double[] position = Coordtransform.GCJ02ToWGS84(deviceChannel.getLongitude(), deviceChannel.getLatitude()); | |
| 330 | - deviceChannel.setLongitudeWgs84(position[0]); | |
| 331 | - deviceChannel.setLatitudeWgs84(position[1]); | |
| 332 | - }else { | |
| 333 | - deviceChannel.setLongitudeGcj02(0.00); | |
| 334 | - deviceChannel.setLatitudeGcj02(0.00); | |
| 335 | - deviceChannel.setLongitudeWgs84(0.00); | |
| 336 | - deviceChannel.setLatitudeWgs84(0.00); | |
| 337 | - } | |
| 338 | - }else { | |
| 339 | - deviceChannel.setLongitudeGcj02(deviceChannel.getLongitude()); | |
| 340 | - deviceChannel.setLatitudeGcj02(deviceChannel.getLatitude()); | |
| 341 | - deviceChannel.setLongitudeWgs84(deviceChannel.getLongitude()); | |
| 342 | - deviceChannel.setLatitudeWgs84(deviceChannel.getLatitude()); | |
| 343 | - } | |
| 385 | + | |
| 386 | + | |
| 344 | 387 | if (XmlUtil.getText(itemDevice, "PTZType") == null || "".equals(XmlUtil.getText(itemDevice, "PTZType"))) { |
| 345 | 388 | //兼容INFO中的信息 |
| 346 | 389 | Element info = itemDevice.element("Info"); | ... | ... |
src/main/java/com/genersoft/iot/vmp/media/zlm/AssistRESTfulUtils.java
| ... | ... | @@ -136,4 +136,12 @@ public class AssistRESTfulUtils { |
| 136 | 136 | return sendGet(mediaServerItem, "api/record/file/duration",param, callback); |
| 137 | 137 | } |
| 138 | 138 | |
| 139 | + public JSONObject addStreamCallInfo(MediaServerItem mediaServerItem, String app, String stream, String callId, RequestCallback callback){ | |
| 140 | + Map<String, Object> param = new HashMap<>(); | |
| 141 | + param.put("app",app); | |
| 142 | + param.put("stream",stream); | |
| 143 | + param.put("callId",callId); | |
| 144 | + return sendGet(mediaServerItem, "api/record/addStreamCallInfo",param, callback); | |
| 145 | + } | |
| 146 | + | |
| 139 | 147 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java
| ... | ... | @@ -87,6 +87,9 @@ public class ZLMHttpHookListener { |
| 87 | 87 | @Autowired |
| 88 | 88 | private VideoStreamSessionManager sessionManager; |
| 89 | 89 | |
| 90 | + @Autowired | |
| 91 | + private AssistRESTfulUtils assistRESTfulUtils; | |
| 92 | + | |
| 90 | 93 | /** |
| 91 | 94 | * 服务器定时上报时间,上报间隔可配置,默认10s上报一次 |
| 92 | 95 | * |
| ... | ... | @@ -99,12 +102,13 @@ public class ZLMHttpHookListener { |
| 99 | 102 | logger.debug("[ ZLM HOOK ] on_server_keepalive API调用,参数:" + json.toString()); |
| 100 | 103 | } |
| 101 | 104 | String mediaServerId = json.getString("mediaServerId"); |
| 102 | - List<ZLMHttpHookSubscribe.Event> subscribes = this.subscribe.getSubscribes(ZLMHttpHookSubscribe.HookType.on_server_keepalive); | |
| 105 | + List<ZLMHttpHookSubscribe.Event> subscribes = this.subscribe.getSubscribes(HookType.on_server_keepalive); | |
| 103 | 106 | if (subscribes != null && subscribes.size() > 0) { |
| 104 | 107 | for (ZLMHttpHookSubscribe.Event subscribe : subscribes) { |
| 105 | 108 | subscribe.response(null, json); |
| 106 | 109 | } |
| 107 | 110 | } |
| 111 | + mediaServerService.updateMediaServerKeepalive(mediaServerId, json.getJSONObject("data")); | |
| 108 | 112 | |
| 109 | 113 | JSONObject ret = new JSONObject(); |
| 110 | 114 | ret.put("code", 0); |
| ... | ... | @@ -164,7 +168,7 @@ public class ZLMHttpHookListener { |
| 164 | 168 | logger.debug("[ ZLM HOOK ]on_play API调用,参数:" + JSON.toJSONString(param)); |
| 165 | 169 | } |
| 166 | 170 | String mediaServerId = param.getMediaServerId(); |
| 167 | - ZLMHttpHookSubscribe.Event subscribe = this.subscribe.getSubscribe(ZLMHttpHookSubscribe.HookType.on_play, json); | |
| 171 | + ZLMHttpHookSubscribe.Event subscribe = this.subscribe.sendNotify(HookType.on_play, json); | |
| 168 | 172 | if (subscribe != null ) { |
| 169 | 173 | MediaServerItem mediaInfo = mediaServerService.getOne(mediaServerId); |
| 170 | 174 | if (mediaInfo != null) { |
| ... | ... | @@ -200,7 +204,9 @@ public class ZLMHttpHookListener { |
| 200 | 204 | |
| 201 | 205 | logger.info("[ ZLM HOOK ]on_publish API调用,参数:" + json.toString()); |
| 202 | 206 | JSONObject ret = new JSONObject(); |
| 203 | - if (!"rtp".equals(param.getApp()) && !"broadcast".equals(param.getApp())) { | |
| 207 | + String mediaServerId = json.getString("mediaServerId"); | |
| 208 | + MediaServerItem mediaInfo = mediaServerService.getOne(mediaServerId); | |
| 209 | + if (!"rtp".equals(param.getApp())) { | |
| 204 | 210 | // 推流鉴权 |
| 205 | 211 | if (param.getParams() == null) { |
| 206 | 212 | logger.info("推流鉴权失败: 缺少不要参数:sign=md5(user表的pushKey)"); |
| ... | ... | @@ -231,6 +237,12 @@ public class ZLMHttpHookListener { |
| 231 | 237 | streamAuthorityInfo.setSign(sign); |
| 232 | 238 | // 鉴权通过 |
| 233 | 239 | redisCatchStorage.updateStreamAuthorityInfo(param.getApp(), param.getStream(), streamAuthorityInfo); |
| 240 | + // 通知assist新的callId | |
| 241 | + if (mediaInfo != null) { | |
| 242 | + assistRESTfulUtils.addStreamCallInfo(mediaInfo, param.getApp(), param.getStream(), callId, null); | |
| 243 | + } | |
| 244 | + }else { | |
| 245 | + zlmMediaListManager.sendStreamEvent(param.getApp(),param.getStream(), param.getMediaServerId()); | |
| 234 | 246 | } |
| 235 | 247 | |
| 236 | 248 | ret.put("code", 0); |
| ... | ... | @@ -240,10 +252,9 @@ public class ZLMHttpHookListener { |
| 240 | 252 | ret.put("enable_audio", true); |
| 241 | 253 | } |
| 242 | 254 | |
| 243 | - String mediaServerId = json.getString("mediaServerId"); | |
| 244 | - ZLMHttpHookSubscribe.Event subscribe = this.subscribe.getSubscribe(ZLMHttpHookSubscribe.HookType.on_publish, json); | |
| 255 | + | |
| 256 | + ZLMHttpHookSubscribe.Event subscribe = this.subscribe.sendNotify(HookType.on_publish, json); | |
| 245 | 257 | if (subscribe != null) { |
| 246 | - MediaServerItem mediaInfo = mediaServerService.getOne(mediaServerId); | |
| 247 | 258 | if (mediaInfo != null) { |
| 248 | 259 | subscribe.response(mediaInfo, json); |
| 249 | 260 | }else { |
| ... | ... | @@ -270,10 +281,12 @@ public class ZLMHttpHookListener { |
| 270 | 281 | ret.put("mp4_max_second", 10); |
| 271 | 282 | ret.put("enable_mp4", true); |
| 272 | 283 | ret.put("enable_audio", true); |
| 284 | + | |
| 273 | 285 | } |
| 274 | 286 | } |
| 275 | 287 | |
| 276 | 288 | |
| 289 | + | |
| 277 | 290 | return new ResponseEntity<String>(ret.toString(), HttpStatus.OK); |
| 278 | 291 | } |
| 279 | 292 | |
| ... | ... | @@ -364,7 +377,7 @@ public class ZLMHttpHookListener { |
| 364 | 377 | logger.debug("[ ZLM HOOK ]on_shell_login API调用,参数:" + json.toString()); |
| 365 | 378 | } |
| 366 | 379 | String mediaServerId = json.getString("mediaServerId"); |
| 367 | - ZLMHttpHookSubscribe.Event subscribe = this.subscribe.getSubscribe(ZLMHttpHookSubscribe.HookType.on_shell_login, json); | |
| 380 | + ZLMHttpHookSubscribe.Event subscribe = this.subscribe.sendNotify(HookType.on_shell_login, json); | |
| 368 | 381 | if (subscribe != null ) { |
| 369 | 382 | MediaServerItem mediaInfo = mediaServerService.getOne(mediaServerId); |
| 370 | 383 | if (mediaInfo != null) { |
| ... | ... | @@ -390,7 +403,7 @@ public class ZLMHttpHookListener { |
| 390 | 403 | logger.info("[ ZLM HOOK ]on_stream_changed API调用,参数:" + JSONObject.toJSONString(item)); |
| 391 | 404 | String mediaServerId = item.getMediaServerId(); |
| 392 | 405 | JSONObject json = (JSONObject) JSON.toJSON(item); |
| 393 | - ZLMHttpHookSubscribe.Event subscribe = this.subscribe.getSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, json); | |
| 406 | + ZLMHttpHookSubscribe.Event subscribe = this.subscribe.sendNotify(HookType.on_stream_changed, json); | |
| 394 | 407 | if (subscribe != null ) { |
| 395 | 408 | MediaServerItem mediaInfo = mediaServerService.getOne(mediaServerId); |
| 396 | 409 | if (mediaInfo != null) { |
| ... | ... | @@ -438,7 +451,6 @@ public class ZLMHttpHookListener { |
| 438 | 451 | redisCatchStorage.stopPlayback(streamInfo.getDeviceID(), streamInfo.getChannelId(), |
| 439 | 452 | streamInfo.getStream(), null); |
| 440 | 453 | } |
| 441 | - | |
| 442 | 454 | } |
| 443 | 455 | }else { |
| 444 | 456 | if (!"rtp".equals(app)){ |
| ... | ... | @@ -451,7 +463,6 @@ public class ZLMHttpHookListener { |
| 451 | 463 | StreamInfo streamInfoByAppAndStream = mediaService.getStreamInfoByAppAndStream(mediaServerItem, |
| 452 | 464 | app, stream, tracks, streamAuthorityInfo.getCallId()); |
| 453 | 465 | item.setStreamInfo(streamInfoByAppAndStream); |
| 454 | - | |
| 455 | 466 | redisCatchStorage.addStream(mediaServerItem, type, app, stream, item); |
| 456 | 467 | if (item.getOriginType() == OriginType.RTSP_PUSH.ordinal() |
| 457 | 468 | || item.getOriginType() == OriginType.RTMP_PUSH.ordinal() |
| ... | ... | @@ -459,20 +470,6 @@ public class ZLMHttpHookListener { |
| 459 | 470 | item.setSeverId(userSetting.getServerId()); |
| 460 | 471 | zlmMediaListManager.addPush(item); |
| 461 | 472 | } |
| 462 | - | |
| 463 | -// List<GbStream> gbStreams = new ArrayList<>(); | |
| 464 | -// if (streamPushItem == null || streamPushItem.getGbId() == null) { | |
| 465 | -// GbStream gbStream = storager.getGbStream(app, streamId); | |
| 466 | -// gbStreams.add(gbStream); | |
| 467 | -// }else { | |
| 468 | -// if (streamPushItem.getGbId() != null) { | |
| 469 | -// gbStreams.add(streamPushItem); | |
| 470 | -// } | |
| 471 | -// } | |
| 472 | -// if (gbStreams.size() > 0) { | |
| 473 | -// eventPublisher.catalogEventPublishForStream(null, gbStreams, CatalogEvent.ON); | |
| 474 | -// } | |
| 475 | - | |
| 476 | 473 | }else { |
| 477 | 474 | // 兼容流注销时类型从redis记录获取 |
| 478 | 475 | MediaItem mediaItem = redisCatchStorage.getStreamInfo(app, stream, mediaServerId); |
| ... | ... | @@ -616,16 +613,21 @@ public class ZLMHttpHookListener { |
| 616 | 613 | } |
| 617 | 614 | String remoteAddr = request.getRemoteAddr(); |
| 618 | 615 | jsonObject.put("ip", remoteAddr); |
| 619 | - List<ZLMHttpHookSubscribe.Event> subscribes = this.subscribe.getSubscribes(ZLMHttpHookSubscribe.HookType.on_server_started); | |
| 616 | + List<ZLMHttpHookSubscribe.Event> subscribes = this.subscribe.getSubscribes(HookType.on_server_started); | |
| 620 | 617 | if (subscribes != null && subscribes.size() > 0) { |
| 621 | 618 | for (ZLMHttpHookSubscribe.Event subscribe : subscribes) { |
| 622 | 619 | subscribe.response(null, jsonObject); |
| 623 | 620 | } |
| 624 | 621 | } |
| 622 | + | |
| 623 | + ZLMServerConfig zlmServerConfig = JSONObject.toJavaObject(jsonObject, ZLMServerConfig.class); | |
| 624 | + if (zlmServerConfig !=null ) { | |
| 625 | + mediaServerService.zlmServerOnline(zlmServerConfig); | |
| 626 | + } | |
| 625 | 627 | JSONObject ret = new JSONObject(); |
| 626 | 628 | ret.put("code", 0); |
| 627 | 629 | ret.put("msg", "success"); |
| 628 | - return new ResponseEntity<String>(ret.toString(),HttpStatus.OK); | |
| 630 | + return new ResponseEntity<>(ret.toString(),HttpStatus.OK); | |
| 629 | 631 | } |
| 630 | 632 | |
| 631 | 633 | private Map<String, String> urlParamToMap(String params) { | ... | ... |
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookSubscribe.java
| 1 | 1 | package com.genersoft.iot.vmp.media.zlm; |
| 2 | 2 | |
| 3 | 3 | import com.alibaba.fastjson.JSONObject; |
| 4 | +import com.genersoft.iot.vmp.media.zlm.dto.HookType; | |
| 5 | +import com.genersoft.iot.vmp.media.zlm.dto.IHookSubscribe; | |
| 4 | 6 | import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; |
| 5 | 7 | import org.springframework.stereotype.Component; |
| 6 | 8 | import org.springframework.util.CollectionUtils; |
| 7 | 9 | |
| 10 | +import java.time.Instant; | |
| 8 | 11 | import java.util.*; |
| 9 | 12 | import java.util.concurrent.ConcurrentHashMap; |
| 13 | +import java.util.concurrent.TimeUnit; | |
| 10 | 14 | |
| 11 | 15 | /** |
| 12 | 16 | * @description:针对 ZLMediaServer的hook事件订阅 |
| ... | ... | @@ -16,51 +20,39 @@ import java.util.concurrent.ConcurrentHashMap; |
| 16 | 20 | @Component |
| 17 | 21 | public class ZLMHttpHookSubscribe { |
| 18 | 22 | |
| 19 | - public enum HookType{ | |
| 20 | - on_flow_report, | |
| 21 | - on_http_access, | |
| 22 | - on_play, | |
| 23 | - on_publish, | |
| 24 | - on_record_mp4, | |
| 25 | - on_rtsp_auth, | |
| 26 | - on_rtsp_realm, | |
| 27 | - on_shell_login, | |
| 28 | - on_stream_changed, | |
| 29 | - on_stream_none_reader, | |
| 30 | - on_stream_not_found, | |
| 31 | - on_server_started, | |
| 32 | - on_server_keepalive | |
| 33 | - } | |
| 34 | - | |
| 35 | 23 | @FunctionalInterface |
| 36 | 24 | public interface Event{ |
| 37 | 25 | void response(MediaServerItem mediaServerItem, JSONObject response); |
| 38 | 26 | } |
| 39 | 27 | |
| 40 | - private Map<HookType, Map<JSONObject, ZLMHttpHookSubscribe.Event>> allSubscribes = new ConcurrentHashMap<>(); | |
| 28 | + private Map<HookType, Map<IHookSubscribe, ZLMHttpHookSubscribe.Event>> allSubscribes = new ConcurrentHashMap<>(); | |
| 41 | 29 | |
| 42 | - public void addSubscribe(HookType type, JSONObject hookResponse, ZLMHttpHookSubscribe.Event event) { | |
| 43 | - allSubscribes.computeIfAbsent(type, k -> new ConcurrentHashMap<>()).put(hookResponse, event); | |
| 30 | + public void addSubscribe(IHookSubscribe hookSubscribe, ZLMHttpHookSubscribe.Event event) { | |
| 31 | + if (hookSubscribe.getExpires() == null) { | |
| 32 | + // 默认5分钟过期 | |
| 33 | + Instant expiresInstant = Instant.now().plusSeconds(TimeUnit.MINUTES.toSeconds(5)); | |
| 34 | + hookSubscribe.setExpires(expiresInstant); | |
| 35 | + } | |
| 36 | + allSubscribes.computeIfAbsent(hookSubscribe.getHookType(), k -> new ConcurrentHashMap<>()).put(hookSubscribe, event); | |
| 44 | 37 | } |
| 45 | 38 | |
| 46 | - public ZLMHttpHookSubscribe.Event getSubscribe(HookType type, JSONObject hookResponse) { | |
| 39 | + public ZLMHttpHookSubscribe.Event sendNotify(HookType type, JSONObject hookResponse) { | |
| 47 | 40 | ZLMHttpHookSubscribe.Event event= null; |
| 48 | - Map<JSONObject, Event> eventMap = allSubscribes.get(type); | |
| 41 | + Map<IHookSubscribe, Event> eventMap = allSubscribes.get(type); | |
| 49 | 42 | if (eventMap == null) { |
| 50 | 43 | return null; |
| 51 | 44 | } |
| 52 | - for (JSONObject key : eventMap.keySet()) { | |
| 45 | + for (IHookSubscribe key : eventMap.keySet()) { | |
| 53 | 46 | Boolean result = null; |
| 54 | - for (String s : key.keySet()) { | |
| 47 | + for (String s : key.getContent().keySet()) { | |
| 55 | 48 | if (result == null) { |
| 56 | - result = key.getString(s).equals(hookResponse.getString(s)); | |
| 49 | + result = key.getContent().getString(s).equals(hookResponse.getString(s)); | |
| 57 | 50 | }else { |
| 58 | - if (key.getString(s) == null) { | |
| 51 | + if (key.getContent().getString(s) == null) { | |
| 59 | 52 | continue; |
| 60 | 53 | } |
| 61 | - result = result && key.getString(s).equals(hookResponse.getString(s)); | |
| 54 | + result = result && key.getContent().getString(s).equals(hookResponse.getString(s)); | |
| 62 | 55 | } |
| 63 | - | |
| 64 | 56 | } |
| 65 | 57 | if (null != result && result) { |
| 66 | 58 | event = eventMap.get(key); |
| ... | ... | @@ -69,26 +61,30 @@ public class ZLMHttpHookSubscribe { |
| 69 | 61 | return event; |
| 70 | 62 | } |
| 71 | 63 | |
| 72 | - public void removeSubscribe(HookType type, JSONObject hookResponse) { | |
| 73 | - Map<JSONObject, Event> eventMap = allSubscribes.get(type); | |
| 64 | + public void removeSubscribe(IHookSubscribe hookSubscribe) { | |
| 65 | + Map<IHookSubscribe, Event> eventMap = allSubscribes.get(hookSubscribe.getHookType()); | |
| 74 | 66 | if (eventMap == null) { |
| 75 | 67 | return; |
| 76 | 68 | } |
| 77 | 69 | |
| 78 | - Set<Map.Entry<JSONObject, Event>> entries = eventMap.entrySet(); | |
| 70 | + Set<Map.Entry<IHookSubscribe, Event>> entries = eventMap.entrySet(); | |
| 79 | 71 | if (entries.size() > 0) { |
| 80 | - List<Map.Entry<JSONObject, ZLMHttpHookSubscribe.Event>> entriesToRemove = new ArrayList<>(); | |
| 81 | - for (Map.Entry<JSONObject, ZLMHttpHookSubscribe.Event> entry : entries) { | |
| 82 | - JSONObject key = entry.getKey(); | |
| 72 | + List<Map.Entry<IHookSubscribe, ZLMHttpHookSubscribe.Event>> entriesToRemove = new ArrayList<>(); | |
| 73 | + for (Map.Entry<IHookSubscribe, ZLMHttpHookSubscribe.Event> entry : entries) { | |
| 74 | + JSONObject content = entry.getKey().getContent(); | |
| 75 | + if (content == null || content.size() == 0) { | |
| 76 | + entriesToRemove.add(entry); | |
| 77 | + continue; | |
| 78 | + } | |
| 83 | 79 | Boolean result = null; |
| 84 | - for (String s : key.keySet()) { | |
| 80 | + for (String s : content.keySet()) { | |
| 85 | 81 | if (result == null) { |
| 86 | - result = key.getString(s).equals(hookResponse.getString(s)); | |
| 82 | + result = content.getString(s).equals(hookSubscribe.getContent().getString(s)); | |
| 87 | 83 | }else { |
| 88 | - if (key.getString(s) == null) { | |
| 84 | + if (content.getString(s) == null) { | |
| 89 | 85 | continue; |
| 90 | 86 | } |
| 91 | - result = result && key.getString(s).equals(hookResponse.getString(s)); | |
| 87 | + result = result && content.getString(s).equals(hookSubscribe.getContent().getString(s)); | |
| 92 | 88 | } |
| 93 | 89 | } |
| 94 | 90 | if (null != result && result){ |
| ... | ... | @@ -97,7 +93,7 @@ public class ZLMHttpHookSubscribe { |
| 97 | 93 | } |
| 98 | 94 | |
| 99 | 95 | if (!CollectionUtils.isEmpty(entriesToRemove)) { |
| 100 | - for (Map.Entry<JSONObject, ZLMHttpHookSubscribe.Event> entry : entriesToRemove) { | |
| 96 | + for (Map.Entry<IHookSubscribe, ZLMHttpHookSubscribe.Event> entry : entriesToRemove) { | |
| 101 | 97 | entries.remove(entry); |
| 102 | 98 | } |
| 103 | 99 | } |
| ... | ... | @@ -111,17 +107,25 @@ public class ZLMHttpHookSubscribe { |
| 111 | 107 | * @return |
| 112 | 108 | */ |
| 113 | 109 | public List<ZLMHttpHookSubscribe.Event> getSubscribes(HookType type) { |
| 114 | - // ZLMHttpHookSubscribe.Event event= null; | |
| 115 | - Map<JSONObject, Event> eventMap = allSubscribes.get(type); | |
| 110 | + Map<IHookSubscribe, Event> eventMap = allSubscribes.get(type); | |
| 116 | 111 | if (eventMap == null) { |
| 117 | 112 | return null; |
| 118 | 113 | } |
| 119 | 114 | List<ZLMHttpHookSubscribe.Event> result = new ArrayList<>(); |
| 120 | - for (JSONObject key : eventMap.keySet()) { | |
| 115 | + for (IHookSubscribe key : eventMap.keySet()) { | |
| 121 | 116 | result.add(eventMap.get(key)); |
| 122 | 117 | } |
| 123 | 118 | return result; |
| 124 | 119 | } |
| 125 | 120 | |
| 121 | + public List<IHookSubscribe> getAll(){ | |
| 122 | + ArrayList<IHookSubscribe> result = new ArrayList<>(); | |
| 123 | + Collection<Map<IHookSubscribe, Event>> values = allSubscribes.values(); | |
| 124 | + for (Map<IHookSubscribe, Event> value : values) { | |
| 125 | + result.addAll(value.keySet()); | |
| 126 | + } | |
| 127 | + return result; | |
| 128 | + } | |
| 129 | + | |
| 126 | 130 | |
| 127 | 131 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMMediaListManager.java
| ... | ... | @@ -4,6 +4,7 @@ import com.alibaba.fastjson.JSONObject; |
| 4 | 4 | import com.genersoft.iot.vmp.conf.UserSetting; |
| 5 | 5 | import com.genersoft.iot.vmp.gb28181.bean.GbStream; |
| 6 | 6 | import com.genersoft.iot.vmp.media.zlm.dto.*; |
| 7 | +import com.genersoft.iot.vmp.service.IMediaServerService; | |
| 7 | 8 | import com.genersoft.iot.vmp.service.IStreamProxyService; |
| 8 | 9 | import com.genersoft.iot.vmp.service.IStreamPushService; |
| 9 | 10 | import com.genersoft.iot.vmp.service.bean.ThirdPartyGB; |
| ... | ... | @@ -63,125 +64,49 @@ public class ZLMMediaListManager { |
| 63 | 64 | @Autowired |
| 64 | 65 | private UserSetting userSetting; |
| 65 | 66 | |
| 66 | - private Map<String, ChannelOnlineEvent> channelOnlineEvents = new ConcurrentHashMap<>(); | |
| 67 | - | |
| 68 | - | |
| 69 | - public void updateMediaList(MediaServerItem mediaServerItem) { | |
| 70 | - storager.clearMediaList(); | |
| 71 | - | |
| 72 | - // 使用异步的当时更新媒体流列表 | |
| 73 | - zlmresTfulUtils.getMediaList(mediaServerItem, (mediaList ->{ | |
| 74 | - if (mediaList == null) { | |
| 75 | - return; | |
| 76 | - } | |
| 77 | - String dataStr = mediaList.getString("data"); | |
| 78 | - | |
| 79 | - Integer code = mediaList.getInteger("code"); | |
| 80 | - Map<String, StreamPushItem> result = new HashMap<>(); | |
| 81 | - List<StreamPushItem> streamPushItems = null; | |
| 82 | - // 获取所有的国标关联 | |
| 83 | -// List<GbStream> gbStreams = gbStreamMapper.selectAllByMediaServerId(mediaServerItem.getId()); | |
| 84 | - if (code == 0 ) { | |
| 85 | - if (dataStr != null) { | |
| 86 | - streamPushItems = streamPushService.handleJSON(dataStr, mediaServerItem); | |
| 87 | - } | |
| 88 | - }else { | |
| 89 | - logger.warn("更新视频流失败,错误code: " + code); | |
| 90 | - } | |
| 91 | - | |
| 92 | - if (streamPushItems != null) { | |
| 93 | - storager.updateMediaList(streamPushItems); | |
| 94 | - for (StreamPushItem streamPushItem : streamPushItems) { | |
| 95 | - JSONObject jsonObject = new JSONObject(); | |
| 96 | - jsonObject.put("app", streamPushItem.getApp()); | |
| 97 | - jsonObject.put("stream", streamPushItem.getStream()); | |
| 98 | - jsonObject.put("mediaServerId", mediaServerItem.getId()); | |
| 99 | - subscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_play,jsonObject, | |
| 100 | - (MediaServerItem mediaServerItemInuse, JSONObject response)->{ | |
| 101 | - updateMedia(mediaServerItem, response.getString("app"), response.getString("stream")); | |
| 102 | - } | |
| 103 | - ); | |
| 104 | - } | |
| 105 | - } | |
| 106 | - })); | |
| 67 | + @Autowired | |
| 68 | + private ZLMRTPServerFactory zlmrtpServerFactory; | |
| 107 | 69 | |
| 108 | - } | |
| 70 | + @Autowired | |
| 71 | + private IMediaServerService mediaServerService; | |
| 109 | 72 | |
| 110 | - public void addMedia(MediaServerItem mediaServerItem, String app, String streamId) { | |
| 111 | - //使用异步更新推流 | |
| 112 | - updateMedia(mediaServerItem, app, streamId); | |
| 113 | - } | |
| 73 | + private Map<String, ChannelOnlineEvent> channelOnPublishEvents = new ConcurrentHashMap<>(); | |
| 114 | 74 | |
| 115 | 75 | public StreamPushItem addPush(MediaItem mediaItem) { |
| 116 | 76 | // 查找此直播流是否存在redis预设gbId |
| 117 | 77 | StreamPushItem transform = streamPushService.transform(mediaItem); |
| 118 | 78 | StreamPushItem pushInDb = streamPushService.getPush(mediaItem.getApp(), mediaItem.getStream()); |
| 79 | + transform.setPushIng(mediaItem.isRegist()); | |
| 119 | 80 | transform.setUpdateTime(DateUtil.getNow()); |
| 120 | 81 | transform.setPushTime(DateUtil.getNow()); |
| 82 | + transform.setSelf(userSetting.getServerId().equals(mediaItem.getSeverId())); | |
| 121 | 83 | if (pushInDb == null) { |
| 122 | 84 | transform.setCreateTime(DateUtil.getNow()); |
| 123 | 85 | streamPushMapper.add(transform); |
| 124 | 86 | }else { |
| 125 | 87 | streamPushMapper.update(transform); |
| 126 | - | |
| 127 | - | |
| 128 | -// if (!StringUtils.isEmpty(pushInDb.getGbId())) { | |
| 129 | -// List<GbStream> gbStreamList = gbStreamMapper.selectByGBId(transform.getGbId()); | |
| 130 | -// if (gbStreamList != null && gbStreamList.size() == 1) { | |
| 131 | -// transform.setGbStreamId(gbStreamList.get(0).getGbStreamId()); | |
| 132 | -// transform.setPlatformId(gbStreamList.get(0).getPlatformId()); | |
| 133 | -// transform.setCatalogId(gbStreamList.get(0).getCatalogId()); | |
| 134 | -// transform.setGbId(gbStreamList.get(0).getGbId()); | |
| 135 | -// gbStreamMapper.update(transform); | |
| 136 | -// streamPushMapper.del(gbStreamList.get(0).getApp(), gbStreamList.get(0).getStream()); | |
| 137 | -// }else { | |
| 138 | -// transform.setCreateTime(DateUtil.getNow()); | |
| 139 | -// transform.setUpdateTime(DateUtil.getNow()); | |
| 140 | -// gbStreamMapper.add(transform); | |
| 141 | -// } | |
| 142 | - // 通知通道上线 | |
| 143 | -// if (transform != null) { | |
| 144 | -// if (channelOnlineEvents.get(transform.getGbId()) != null) { | |
| 145 | -// channelOnlineEvents.get(transform.getGbId()).run(transform.getApp(), transform.getStream(), transform.getServerId()); | |
| 146 | -// channelOnlineEvents.remove(transform.getGbId()); | |
| 147 | -// } | |
| 148 | -// } | |
| 149 | -// } | |
| 88 | + gbStreamMapper.updateMediaServer(mediaItem.getApp(), mediaItem.getStream(), mediaItem.getMediaServerId()); | |
| 89 | + } | |
| 90 | + if (transform != null) { | |
| 91 | + if (getChannelOnlineEventLister(transform.getApp(), transform.getStream()) != null) { | |
| 92 | + getChannelOnlineEventLister(transform.getApp(), transform.getStream()).run(transform.getApp(), transform.getStream(), transform.getServerId()); | |
| 93 | + removedChannelOnlineEventLister(transform.getApp(), transform.getStream()); | |
| 94 | + } | |
| 150 | 95 | } |
| 151 | - | |
| 152 | - | |
| 153 | - | |
| 154 | 96 | return transform; |
| 155 | 97 | } |
| 156 | 98 | |
| 157 | - | |
| 158 | - public void updateMedia(MediaServerItem mediaServerItem, String app, String streamId) { | |
| 159 | - //使用异步更新推流 | |
| 160 | - zlmresTfulUtils.getMediaList(mediaServerItem, app, streamId, "rtmp", json->{ | |
| 161 | - | |
| 162 | - if (json == null) { | |
| 163 | - return; | |
| 164 | - } | |
| 165 | - String dataStr = json.getString("data"); | |
| 166 | - | |
| 167 | - Integer code = json.getInteger("code"); | |
| 168 | - Map<String, StreamPushItem> result = new HashMap<>(); | |
| 169 | - List<StreamPushItem> streamPushItems = null; | |
| 170 | - if (code == 0 ) { | |
| 171 | - if (dataStr != null) { | |
| 172 | - streamPushItems = streamPushService.handleJSON(dataStr, mediaServerItem); | |
| 173 | - } | |
| 174 | - }else { | |
| 175 | - logger.warn("更新视频流失败,错误code: " + code); | |
| 99 | + public void sendStreamEvent(String app, String stream, String mediaServerId) { | |
| 100 | + MediaServerItem mediaServerItem = mediaServerService.getOne(mediaServerId); | |
| 101 | + // 查看推流状态 | |
| 102 | + if (zlmrtpServerFactory.isStreamReady(mediaServerItem, app, stream)) { | |
| 103 | + if (getChannelOnlineEventLister(app, stream) != null) { | |
| 104 | + getChannelOnlineEventLister(app, stream).run(app, stream, mediaServerId); | |
| 105 | + removedChannelOnlineEventLister(app, stream); | |
| 176 | 106 | } |
| 177 | - | |
| 178 | - if (streamPushItems != null && streamPushItems.size() == 1) { | |
| 179 | - storager.updateMedia(streamPushItems.get(0)); | |
| 180 | - } | |
| 181 | - }); | |
| 107 | + } | |
| 182 | 108 | } |
| 183 | 109 | |
| 184 | - | |
| 185 | 110 | public int removeMedia(String app, String streamId) { |
| 186 | 111 | // 查找是否关联了国标, 关联了不删除, 置为离线 |
| 187 | 112 | GbStream gbStream = gbStreamMapper.selectOne(app, streamId); |
| ... | ... | @@ -189,48 +114,21 @@ public class ZLMMediaListManager { |
| 189 | 114 | if (gbStream == null) { |
| 190 | 115 | result = storager.removeMedia(app, streamId); |
| 191 | 116 | }else { |
| 192 | - // TODO 暂不设置为离线 | |
| 193 | 117 | result =storager.mediaOffline(app, streamId); |
| 194 | 118 | } |
| 195 | 119 | return result; |
| 196 | 120 | } |
| 197 | 121 | |
| 198 | - public void addChannelOnlineEventLister(String key, ChannelOnlineEvent callback) { | |
| 199 | - this.channelOnlineEvents.put(key,callback); | |
| 122 | + public void addChannelOnlineEventLister(String app, String stream, ChannelOnlineEvent callback) { | |
| 123 | + this.channelOnPublishEvents.put(app + "_" + stream, callback); | |
| 200 | 124 | } |
| 201 | 125 | |
| 202 | - public void removedChannelOnlineEventLister(String key) { | |
| 203 | - this.channelOnlineEvents.remove(key); | |
| 126 | + public void removedChannelOnlineEventLister(String app, String stream) { | |
| 127 | + this.channelOnPublishEvents.remove(app + "_" + stream); | |
| 204 | 128 | } |
| 205 | 129 | |
| 130 | + public ChannelOnlineEvent getChannelOnlineEventLister(String app, String stream) { | |
| 131 | + return this.channelOnPublishEvents.get(app + "_" + stream); | |
| 132 | + } | |
| 206 | 133 | |
| 207 | - | |
| 208 | -// public void clearAllSessions() { | |
| 209 | -// logger.info("清空所有国标相关的session"); | |
| 210 | -// JSONObject allSessionJSON = zlmresTfulUtils.getAllSession(); | |
| 211 | -// ZLMServerConfig mediaInfo = redisCatchStorage.getMediaInfo(); | |
| 212 | -// HashSet<String> allLocalPorts = new HashSet(); | |
| 213 | -// if (allSessionJSON.getInteger("code") == 0) { | |
| 214 | -// JSONArray data = allSessionJSON.getJSONArray("data"); | |
| 215 | -// if (data.size() > 0) { | |
| 216 | -// for (int i = 0; i < data.size(); i++) { | |
| 217 | -// JSONObject sessionJOSN = data.getJSONObject(i); | |
| 218 | -// Integer local_port = sessionJOSN.getInteger("local_port"); | |
| 219 | -// if (!local_port.equals(Integer.valueOf(mediaInfo.getHttpPort())) && | |
| 220 | -// !local_port.equals(Integer.valueOf(mediaInfo.getHttpSSLport())) && | |
| 221 | -// !local_port.equals(Integer.valueOf(mediaInfo.getRtmpPort())) && | |
| 222 | -// !local_port.equals(Integer.valueOf(mediaInfo.getRtspPort())) && | |
| 223 | -// !local_port.equals(Integer.valueOf(mediaInfo.getRtspSSlport())) && | |
| 224 | -// !local_port.equals(Integer.valueOf(mediaInfo.getHookOnFlowReport()))){ | |
| 225 | -// allLocalPorts.add(sessionJOSN.getInteger("local_port") + ""); | |
| 226 | -// } | |
| 227 | -// } | |
| 228 | -// } | |
| 229 | -// } | |
| 230 | -// if (allLocalPorts.size() > 0) { | |
| 231 | -// List<String> result = new ArrayList<>(allLocalPorts); | |
| 232 | -// String localPortSStr = String.join(",", result); | |
| 233 | -// zlmresTfulUtils.kickSessions(localPortSStr); | |
| 234 | -// } | |
| 235 | -// } | |
| 236 | 134 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRTPServerFactory.java
| ... | ... | @@ -87,7 +87,7 @@ public class ZLMRTPServerFactory { |
| 87 | 87 | return result; |
| 88 | 88 | } |
| 89 | 89 | |
| 90 | - public int createRTPServer(MediaServerItem mediaServerItem, String streamId, int ssrc) { | |
| 90 | + public int createRTPServer(MediaServerItem mediaServerItem, String streamId, int ssrc, Integer port) { | |
| 91 | 91 | int result = -1; |
| 92 | 92 | // 查询此rtp server 是否已经存在 |
| 93 | 93 | JSONObject rtpInfo = zlmresTfulUtils.getRtpInfo(mediaServerItem, streamId); |
| ... | ... | @@ -105,7 +105,11 @@ public class ZLMRTPServerFactory { |
| 105 | 105 | param.put("enable_tcp", 1); |
| 106 | 106 | param.put("stream_id", streamId); |
| 107 | 107 | // 推流端口设置0则使用随机端口 |
| 108 | - param.put("port", 0); | |
| 108 | + if (port == null) { | |
| 109 | + param.put("port", 0); | |
| 110 | + }else { | |
| 111 | + param.put("port", port); | |
| 112 | + } | |
| 109 | 113 | param.put("ssrc", ssrc); |
| 110 | 114 | JSONObject openRtpServerResultJson = zlmresTfulUtils.openRtpServer(mediaServerItem, param); |
| 111 | 115 | |
| ... | ... | @@ -280,8 +284,10 @@ public class ZLMRTPServerFactory { |
| 280 | 284 | * 查询待转推的流是否就绪 |
| 281 | 285 | */ |
| 282 | 286 | public Boolean isStreamReady(MediaServerItem mediaServerItem, String app, String streamId) { |
| 283 | - JSONObject mediaInfo = zlmresTfulUtils.getMediaInfo(mediaServerItem, app, "rtsp", streamId); | |
| 284 | - return (mediaInfo.getInteger("code") == 0 && mediaInfo.getBoolean("online") != null && mediaInfo.getBoolean("online")); | |
| 287 | + JSONObject mediaInfo = zlmresTfulUtils.getMediaList(mediaServerItem, app, streamId); | |
| 288 | + return (mediaInfo.getInteger("code") == 0 | |
| 289 | + && mediaInfo.getJSONArray("data") != null | |
| 290 | + && mediaInfo.getJSONArray("data").size() > 0); | |
| 285 | 291 | } |
| 286 | 292 | |
| 287 | 293 | /** | ... | ... |
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRunner.java
| ... | ... | @@ -6,22 +6,22 @@ import com.alibaba.fastjson.JSONObject; |
| 6 | 6 | import com.genersoft.iot.vmp.conf.DynamicTask; |
| 7 | 7 | import com.genersoft.iot.vmp.conf.MediaConfig; |
| 8 | 8 | import com.genersoft.iot.vmp.gb28181.event.EventPublisher; |
| 9 | +import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeFactory; | |
| 10 | +import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForServerStarted; | |
| 11 | +import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForStreamChange; | |
| 9 | 12 | import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; |
| 10 | 13 | import com.genersoft.iot.vmp.service.IMediaServerService; |
| 11 | -import com.genersoft.iot.vmp.service.IStreamProxyService; | |
| 12 | -import com.genersoft.iot.vmp.storager.IRedisCatchStorage; | |
| 13 | 14 | import org.slf4j.Logger; |
| 14 | 15 | import org.slf4j.LoggerFactory; |
| 15 | 16 | import org.springframework.beans.factory.annotation.Autowired; |
| 16 | -import org.springframework.beans.factory.annotation.Qualifier; | |
| 17 | 17 | import org.springframework.boot.CommandLineRunner; |
| 18 | 18 | import org.springframework.core.annotation.Order; |
| 19 | 19 | import org.springframework.scheduling.annotation.Async; |
| 20 | -import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; | |
| 21 | 20 | import org.springframework.stereotype.Component; |
| 22 | -import org.springframework.util.StringUtils; | |
| 23 | 21 | |
| 22 | +import java.time.Instant; | |
| 24 | 23 | import java.util.*; |
| 24 | +import java.util.concurrent.TimeUnit; | |
| 25 | 25 | |
| 26 | 26 | @Component |
| 27 | 27 | @Order(value=1) |
| ... | ... | @@ -38,18 +38,12 @@ public class ZLMRunner implements CommandLineRunner { |
| 38 | 38 | private ZLMHttpHookSubscribe hookSubscribe; |
| 39 | 39 | |
| 40 | 40 | @Autowired |
| 41 | - private IStreamProxyService streamProxyService; | |
| 42 | - | |
| 43 | - @Autowired | |
| 44 | 41 | private EventPublisher publisher; |
| 45 | 42 | |
| 46 | 43 | @Autowired |
| 47 | 44 | private IMediaServerService mediaServerService; |
| 48 | 45 | |
| 49 | 46 | @Autowired |
| 50 | - private IRedisCatchStorage redisCatchStorage; | |
| 51 | - | |
| 52 | - @Autowired | |
| 53 | 47 | private MediaConfig mediaConfig; |
| 54 | 48 | |
| 55 | 49 | @Autowired |
| ... | ... | @@ -67,26 +61,24 @@ public class ZLMRunner implements CommandLineRunner { |
| 67 | 61 | mediaServerService.updateToDatabase(mediaSerItem); |
| 68 | 62 | } |
| 69 | 63 | mediaServerService.syncCatchFromDatabase(); |
| 64 | + HookSubscribeForServerStarted hookSubscribeForServerStarted = HookSubscribeFactory.on_server_started(); | |
| 65 | +// Instant expiresInstant = Instant.now().plusSeconds(TimeUnit.SECONDS.toSeconds(60)); | |
| 66 | +// hookSubscribeForStreamChange.setExpires(expiresInstant); | |
| 70 | 67 | // 订阅 zlm启动事件, 新的zlm也会从这里进入系统 |
| 71 | - hookSubscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_server_started,new JSONObject(), | |
| 68 | + hookSubscribe.addSubscribe(hookSubscribeForServerStarted, | |
| 72 | 69 | (MediaServerItem mediaServerItem, JSONObject response)->{ |
| 73 | 70 | ZLMServerConfig zlmServerConfig = JSONObject.toJavaObject(response, ZLMServerConfig.class); |
| 74 | 71 | if (zlmServerConfig !=null ) { |
| 75 | 72 | if (startGetMedia != null) { |
| 76 | 73 | startGetMedia.remove(zlmServerConfig.getGeneralMediaServerId()); |
| 74 | + if (startGetMedia.size() == 0) { | |
| 75 | + hookSubscribe.removeSubscribe(HookSubscribeFactory.on_server_started()); | |
| 76 | + } | |
| 77 | 77 | } |
| 78 | - mediaServerService.zlmServerOnline(zlmServerConfig); | |
| 79 | 78 | } |
| 80 | 79 | }); |
| 81 | 80 | |
| 82 | - // 订阅 zlm保活事件, 当zlm离线时做业务的处理 | |
| 83 | - hookSubscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_server_keepalive,new JSONObject(), | |
| 84 | - (MediaServerItem mediaServerItem, JSONObject response)->{ | |
| 85 | - String mediaServerId = response.getString("mediaServerId"); | |
| 86 | - if (mediaServerId !=null ) { | |
| 87 | - mediaServerService.updateMediaServerKeepalive(mediaServerId, response.getJSONObject("data")); | |
| 88 | - } | |
| 89 | - }); | |
| 81 | + | |
| 90 | 82 | |
| 91 | 83 | // 获取zlm信息 |
| 92 | 84 | logger.info("[zlm] 等待默认zlm中..."); |
| ... | ... | @@ -125,6 +117,9 @@ public class ZLMRunner implements CommandLineRunner { |
| 125 | 117 | zlmServerConfigFirst.setIp(mediaServerItem.getIp()); |
| 126 | 118 | zlmServerConfigFirst.setHttpPort(mediaServerItem.getHttpPort()); |
| 127 | 119 | startGetMedia.remove(mediaServerItem.getId()); |
| 120 | + if (startGetMedia.size() == 0) { | |
| 121 | + hookSubscribe.removeSubscribe(HookSubscribeFactory.on_server_started()); | |
| 122 | + } | |
| 128 | 123 | mediaServerService.zlmServerOnline(zlmServerConfigFirst); |
| 129 | 124 | }else { |
| 130 | 125 | logger.info("[ {} ]-[ {}:{} ]主动连接失败, 清理相关资源, 开始尝试重试连接", |
| ... | ... | @@ -139,6 +134,9 @@ public class ZLMRunner implements CommandLineRunner { |
| 139 | 134 | zlmServerConfig.setIp(mediaServerItem.getIp()); |
| 140 | 135 | zlmServerConfig.setHttpPort(mediaServerItem.getHttpPort()); |
| 141 | 136 | startGetMedia.remove(mediaServerItem.getId()); |
| 137 | + if (startGetMedia.size() == 0) { | |
| 138 | + hookSubscribe.removeSubscribe(HookSubscribeFactory.on_server_started()); | |
| 139 | + } | |
| 142 | 140 | mediaServerService.zlmServerOnline(zlmServerConfig); |
| 143 | 141 | } |
| 144 | 142 | }, 2000); | ... | ... |
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/HookSubscribeFactory.java
0 → 100644
| 1 | +package com.genersoft.iot.vmp.media.zlm.dto; | |
| 2 | + | |
| 3 | + | |
| 4 | +import com.alibaba.fastjson.JSONObject; | |
| 5 | + | |
| 6 | +/** | |
| 7 | + * hook 订阅工厂 | |
| 8 | + * @author lin | |
| 9 | + */ | |
| 10 | +public class HookSubscribeFactory { | |
| 11 | + | |
| 12 | + public static HookSubscribeForStreamChange on_stream_changed(String app, String stream, boolean regist, String scheam, String mediaServerId) { | |
| 13 | + HookSubscribeForStreamChange hookSubscribe = new HookSubscribeForStreamChange(); | |
| 14 | + JSONObject subscribeKey = new com.alibaba.fastjson.JSONObject(); | |
| 15 | + subscribeKey.put("app", app); | |
| 16 | + subscribeKey.put("stream", stream); | |
| 17 | + subscribeKey.put("regist", regist); | |
| 18 | + if (scheam != null) { | |
| 19 | + subscribeKey.put("schema", scheam); | |
| 20 | + } | |
| 21 | + subscribeKey.put("mediaServerId", mediaServerId); | |
| 22 | + hookSubscribe.setContent(subscribeKey); | |
| 23 | + | |
| 24 | + return hookSubscribe; | |
| 25 | + } | |
| 26 | + | |
| 27 | + public static HookSubscribeForServerStarted on_server_started() { | |
| 28 | + HookSubscribeForServerStarted hookSubscribe = new HookSubscribeForServerStarted(); | |
| 29 | + hookSubscribe.setContent(new JSONObject()); | |
| 30 | + | |
| 31 | + return hookSubscribe; | |
| 32 | + } | |
| 33 | +} | ... | ... |
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/HookSubscribeForServerStarted.java
0 → 100644
| 1 | +package com.genersoft.iot.vmp.media.zlm.dto; | |
| 2 | + | |
| 3 | +import com.alibaba.fastjson.JSONObject; | |
| 4 | +import com.alibaba.fastjson.annotation.JSONField; | |
| 5 | + | |
| 6 | +import java.time.Instant; | |
| 7 | + | |
| 8 | +/** | |
| 9 | + * hook订阅-流变化 | |
| 10 | + * @author lin | |
| 11 | + */ | |
| 12 | +public class HookSubscribeForServerStarted implements IHookSubscribe{ | |
| 13 | + | |
| 14 | + private HookType hookType = HookType.on_server_started; | |
| 15 | + | |
| 16 | + private JSONObject content; | |
| 17 | + | |
| 18 | + @JSONField(format="yyyy-MM-dd HH:mm:ss") | |
| 19 | + private Instant expires; | |
| 20 | + | |
| 21 | + @Override | |
| 22 | + public HookType getHookType() { | |
| 23 | + return hookType; | |
| 24 | + } | |
| 25 | + | |
| 26 | + @Override | |
| 27 | + public JSONObject getContent() { | |
| 28 | + return content; | |
| 29 | + } | |
| 30 | + | |
| 31 | + public void setContent(JSONObject content) { | |
| 32 | + this.content = content; | |
| 33 | + } | |
| 34 | + | |
| 35 | + @Override | |
| 36 | + public Instant getExpires() { | |
| 37 | + return expires; | |
| 38 | + } | |
| 39 | + | |
| 40 | + @Override | |
| 41 | + public void setExpires(Instant expires) { | |
| 42 | + this.expires = expires; | |
| 43 | + } | |
| 44 | +} | ... | ... |
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/HookSubscribeForStreamChange.java
0 → 100644
| 1 | +package com.genersoft.iot.vmp.media.zlm.dto; | |
| 2 | + | |
| 3 | +import com.alibaba.fastjson.JSONObject; | |
| 4 | +import com.alibaba.fastjson.annotation.JSONField; | |
| 5 | + | |
| 6 | +import java.time.Instant; | |
| 7 | + | |
| 8 | +/** | |
| 9 | + * hook订阅-流变化 | |
| 10 | + * @author lin | |
| 11 | + */ | |
| 12 | +public class HookSubscribeForStreamChange implements IHookSubscribe{ | |
| 13 | + | |
| 14 | + private HookType hookType = HookType.on_stream_changed; | |
| 15 | + | |
| 16 | + private JSONObject content; | |
| 17 | + | |
| 18 | + private Instant expires; | |
| 19 | + | |
| 20 | + @Override | |
| 21 | + public HookType getHookType() { | |
| 22 | + return hookType; | |
| 23 | + } | |
| 24 | + | |
| 25 | + @Override | |
| 26 | + public JSONObject getContent() { | |
| 27 | + return content; | |
| 28 | + } | |
| 29 | + | |
| 30 | + public void setContent(JSONObject content) { | |
| 31 | + this.content = content; | |
| 32 | + } | |
| 33 | + | |
| 34 | + @Override | |
| 35 | + public Instant getExpires() { | |
| 36 | + return expires; | |
| 37 | + } | |
| 38 | + | |
| 39 | + @Override | |
| 40 | + public void setExpires(Instant expires) { | |
| 41 | + this.expires = expires; | |
| 42 | + } | |
| 43 | +} | ... | ... |
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/HookType.java
0 → 100644
| 1 | +package com.genersoft.iot.vmp.media.zlm.dto; | |
| 2 | + | |
| 3 | +/** | |
| 4 | + * hook类型 | |
| 5 | + * @author lin | |
| 6 | + */ | |
| 7 | + | |
| 8 | +public enum HookType { | |
| 9 | + | |
| 10 | + on_flow_report, | |
| 11 | + on_http_access, | |
| 12 | + on_play, | |
| 13 | + on_publish, | |
| 14 | + on_record_mp4, | |
| 15 | + on_rtsp_auth, | |
| 16 | + on_rtsp_realm, | |
| 17 | + on_shell_login, | |
| 18 | + on_stream_changed, | |
| 19 | + on_stream_none_reader, | |
| 20 | + on_stream_not_found, | |
| 21 | + on_server_started, | |
| 22 | + on_server_keepalive | |
| 23 | +} | ... | ... |
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/IHookSubscribe.java
0 → 100644
| 1 | +package com.genersoft.iot.vmp.media.zlm.dto; | |
| 2 | + | |
| 3 | +import com.alibaba.fastjson.JSONObject; | |
| 4 | + | |
| 5 | +import java.time.Instant; | |
| 6 | + | |
| 7 | +/** | |
| 8 | + * zlm hook事件的参数 | |
| 9 | + * @author lin | |
| 10 | + */ | |
| 11 | +public interface IHookSubscribe { | |
| 12 | + | |
| 13 | + /** | |
| 14 | + * 获取hook类型 | |
| 15 | + * @return hook类型 | |
| 16 | + */ | |
| 17 | + HookType getHookType(); | |
| 18 | + | |
| 19 | + /** | |
| 20 | + * 获取hook的具体内容 | |
| 21 | + * @return hook的具体内容 | |
| 22 | + */ | |
| 23 | + JSONObject getContent(); | |
| 24 | + | |
| 25 | + /** | |
| 26 | + * 设置过期时间 | |
| 27 | + * @param instant 过期时间 | |
| 28 | + */ | |
| 29 | + void setExpires(Instant instant); | |
| 30 | + | |
| 31 | + /** | |
| 32 | + * 获取过期时间 | |
| 33 | + * @return 过期时间 | |
| 34 | + */ | |
| 35 | + Instant getExpires(); | |
| 36 | +} | ... | ... |
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/MediaItem.java
| ... | ... | @@ -4,6 +4,9 @@ import com.genersoft.iot.vmp.common.StreamInfo; |
| 4 | 4 | |
| 5 | 5 | import java.util.List; |
| 6 | 6 | |
| 7 | +/** | |
| 8 | + * @author lin | |
| 9 | + */ | |
| 7 | 10 | public class MediaItem { |
| 8 | 11 | |
| 9 | 12 | /** |
| ... | ... | @@ -22,6 +25,11 @@ public class MediaItem { |
| 22 | 25 | private String stream; |
| 23 | 26 | |
| 24 | 27 | /** |
| 28 | + * 推流鉴权Id | |
| 29 | + */ | |
| 30 | + private String callId; | |
| 31 | + | |
| 32 | + /** | |
| 25 | 33 | * 观看总人数,包括hls/rtsp/rtmp/http-flv/ws-flv |
| 26 | 34 | */ |
| 27 | 35 | private String totalReaderCount; |
| ... | ... | @@ -427,4 +435,12 @@ public class MediaItem { |
| 427 | 435 | public void setSeverId(String severId) { |
| 428 | 436 | this.severId = severId; |
| 429 | 437 | } |
| 438 | + | |
| 439 | + public String getCallId() { | |
| 440 | + return callId; | |
| 441 | + } | |
| 442 | + | |
| 443 | + public void setCallId(String callId) { | |
| 444 | + this.callId = callId; | |
| 445 | + } | |
| 430 | 446 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/StreamPushItem.java
| ... | ... | @@ -103,6 +103,18 @@ public class StreamPushItem extends GbStream implements Comparable<StreamPushIte |
| 103 | 103 | */ |
| 104 | 104 | private String createTime; |
| 105 | 105 | |
| 106 | + /** | |
| 107 | + * 是否正在推流 | |
| 108 | + */ | |
| 109 | + private boolean pushIng; | |
| 110 | + | |
| 111 | + /** | |
| 112 | + * 是否自己平台的推流 | |
| 113 | + */ | |
| 114 | + private boolean self; | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 106 | 118 | public String getVhost() { |
| 107 | 119 | return vhost; |
| 108 | 120 | } |
| ... | ... | @@ -277,5 +289,21 @@ public class StreamPushItem extends GbStream implements Comparable<StreamPushIte |
| 277 | 289 | public void setCreateTime(String createTime) { |
| 278 | 290 | this.createTime = createTime; |
| 279 | 291 | } |
| 292 | + | |
| 293 | + public boolean isPushIng() { | |
| 294 | + return pushIng; | |
| 295 | + } | |
| 296 | + | |
| 297 | + public void setPushIng(boolean pushIng) { | |
| 298 | + this.pushIng = pushIng; | |
| 299 | + } | |
| 300 | + | |
| 301 | + public boolean isSelf() { | |
| 302 | + return self; | |
| 303 | + } | |
| 304 | + | |
| 305 | + public void setSelf(boolean self) { | |
| 306 | + this.self = self; | |
| 307 | + } | |
| 280 | 308 | } |
| 281 | 309 | ... | ... |
src/main/java/com/genersoft/iot/vmp/service/IDeviceChannelService.java
0 → 100644
| 1 | +package com.genersoft.iot.vmp.service; | |
| 2 | + | |
| 3 | +import com.genersoft.iot.vmp.gb28181.bean.Device; | |
| 4 | +import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; | |
| 5 | + | |
| 6 | +import java.util.List; | |
| 7 | + | |
| 8 | +/** | |
| 9 | + * 国标通道业务类 | |
| 10 | + * @author lin | |
| 11 | + */ | |
| 12 | +public interface IDeviceChannelService { | |
| 13 | + | |
| 14 | + /** | |
| 15 | + * 更新gps信息 | |
| 16 | + */ | |
| 17 | + DeviceChannel updateGps(DeviceChannel deviceChannel, Device device); | |
| 18 | + | |
| 19 | + /** | |
| 20 | + * 添加设备通道 | |
| 21 | + * | |
| 22 | + * @param deviceId 设备id | |
| 23 | + * @param channel 通道 | |
| 24 | + */ | |
| 25 | + void updateChannel(String deviceId, DeviceChannel channel); | |
| 26 | + | |
| 27 | + /** | |
| 28 | + * 批量添加设备通道 | |
| 29 | + * | |
| 30 | + * @param deviceId 设备id | |
| 31 | + * @param channels 多个通道 | |
| 32 | + */ | |
| 33 | + int updateChannels(String deviceId, List<DeviceChannel> channels); | |
| 34 | + | |
| 35 | +} | ... | ... |
src/main/java/com/genersoft/iot/vmp/service/IGbStreamService.java
| ... | ... | @@ -18,7 +18,7 @@ public interface IGbStreamService { |
| 18 | 18 | * @param count |
| 19 | 19 | * @return |
| 20 | 20 | */ |
| 21 | - PageInfo<GbStream> getAll(Integer page, Integer count, String platFormId, String catalogId,String query,Boolean pushing,String mediaServerId); | |
| 21 | + PageInfo<GbStream> getAll(Integer page, Integer count, String platFormId, String catalogId,String query,String mediaServerId); | |
| 22 | 22 | |
| 23 | 23 | |
| 24 | 24 | /** | ... | ... |
src/main/java/com/genersoft/iot/vmp/service/IMediaServerService.java
| ... | ... | @@ -47,6 +47,8 @@ public interface IMediaServerService { |
| 47 | 47 | |
| 48 | 48 | SSRCInfo openRTPServer(MediaServerItem mediaServerItem, String streamId, String ssrc, boolean ssrcCheck, boolean isPlayback); |
| 49 | 49 | |
| 50 | + SSRCInfo openRTPServer(MediaServerItem mediaServerItem, String streamId, String ssrc, boolean ssrcCheck, boolean isPlayback, Integer port); | |
| 51 | + | |
| 50 | 52 | void closeRTPServer(String deviceId, String channelId, String ssrc); |
| 51 | 53 | |
| 52 | 54 | void clearRTPServer(MediaServerItem mediaServerItem); | ... | ... |
src/main/java/com/genersoft/iot/vmp/service/IPlatformChannelService.java
0 → 100644
| 1 | +package com.genersoft.iot.vmp.service; | |
| 2 | + | |
| 3 | +import com.genersoft.iot.vmp.vmanager.gb28181.platform.bean.ChannelReduce; | |
| 4 | + | |
| 5 | +import java.util.List; | |
| 6 | + | |
| 7 | +/** | |
| 8 | + * 平台关联通道管理 | |
| 9 | + * @author lin | |
| 10 | + */ | |
| 11 | +public interface IPlatformChannelService { | |
| 12 | + | |
| 13 | + /** | |
| 14 | + * 更新目录下的通道 | |
| 15 | + * @param platformId 平台编号 | |
| 16 | + * @param channelReduces 通道信息 | |
| 17 | + * @param catalogId 目录编号 | |
| 18 | + * @return | |
| 19 | + */ | |
| 20 | + int updateChannelForGB(String platformId, List<ChannelReduce> channelReduces, String catalogId); | |
| 21 | + | |
| 22 | +} | ... | ... |
src/main/java/com/genersoft/iot/vmp/service/IStreamProxyService.java
src/main/java/com/genersoft/iot/vmp/service/IStreamPushService.java
| ... | ... | @@ -5,6 +5,7 @@ import com.genersoft.iot.vmp.media.zlm.ZLMServerConfig; |
| 5 | 5 | import com.genersoft.iot.vmp.media.zlm.dto.MediaItem; |
| 6 | 6 | import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; |
| 7 | 7 | import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem; |
| 8 | +import com.genersoft.iot.vmp.service.bean.StreamPushItemFromRedis; | |
| 8 | 9 | import com.genersoft.iot.vmp.vmanager.bean.StreamPushExcelDto; |
| 9 | 10 | import com.github.pagehelper.PageInfo; |
| 10 | 11 | |
| ... | ... | @@ -44,31 +45,59 @@ public interface IStreamPushService { |
| 44 | 45 | * 停止一路推流 |
| 45 | 46 | * @param app 应用名 |
| 46 | 47 | * @param streamId 流ID |
| 47 | - * @return | |
| 48 | 48 | */ |
| 49 | 49 | boolean stop(String app, String streamId); |
| 50 | 50 | |
| 51 | 51 | /** |
| 52 | 52 | * 新的节点加入 |
| 53 | - * @param mediaServerId | |
| 54 | - * @return | |
| 55 | 53 | */ |
| 56 | 54 | void zlmServerOnline(String mediaServerId); |
| 57 | 55 | |
| 58 | 56 | /** |
| 59 | 57 | * 节点离线 |
| 60 | - * @param mediaServerId | |
| 61 | - * @return | |
| 62 | 58 | */ |
| 63 | 59 | void zlmServerOffline(String mediaServerId); |
| 64 | 60 | |
| 61 | + /** | |
| 62 | + * 清空 | |
| 63 | + */ | |
| 65 | 64 | void clean(); |
| 66 | 65 | |
| 66 | + | |
| 67 | 67 | boolean saveToRandomGB(); |
| 68 | 68 | |
| 69 | + /** | |
| 70 | + * 批量添加 | |
| 71 | + */ | |
| 69 | 72 | void batchAdd(List<StreamPushItem> streamPushExcelDtoList); |
| 70 | 73 | |
| 74 | + /** | |
| 75 | + * 中止多个推流 | |
| 76 | + */ | |
| 71 | 77 | boolean batchStop(List<GbStream> streamPushItems); |
| 72 | 78 | |
| 79 | + /** | |
| 80 | + * 导入时批量增加 | |
| 81 | + */ | |
| 73 | 82 | void batchAddForUpload(List<StreamPushItem> streamPushItems, Map<String, List<String[]>> streamPushItemsForAll); |
| 83 | + | |
| 84 | + /** | |
| 85 | + * 全部离线 | |
| 86 | + */ | |
| 87 | + void allStreamOffline(); | |
| 88 | + | |
| 89 | + /** | |
| 90 | + * 推流离线 | |
| 91 | + */ | |
| 92 | + void offline(List<StreamPushItemFromRedis> offlineStreams); | |
| 93 | + | |
| 94 | + /** | |
| 95 | + * 推流上线 | |
| 96 | + */ | |
| 97 | + void online(List<StreamPushItemFromRedis> onlineStreams); | |
| 98 | + | |
| 99 | + /** | |
| 100 | + * 增加推流 | |
| 101 | + */ | |
| 102 | + boolean add(StreamPushItem stream); | |
| 74 | 103 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/service/IUserService.java
| 1 | 1 | package com.genersoft.iot.vmp.service; |
| 2 | 2 | |
| 3 | 3 | import com.genersoft.iot.vmp.storager.dao.dto.User; |
| 4 | +import com.github.pagehelper.PageInfo; | |
| 4 | 5 | |
| 5 | 6 | import java.util.List; |
| 6 | 7 | |
| ... | ... | @@ -21,4 +22,8 @@ public interface IUserService { |
| 21 | 22 | int updateUsers(User user); |
| 22 | 23 | |
| 23 | 24 | boolean checkPushAuthority(String callId, String sign); |
| 25 | + | |
| 26 | + PageInfo<User> getUsers(int page, int count); | |
| 27 | + | |
| 28 | + int changePushKey(int id, String pushKey); | |
| 24 | 29 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/service/StreamGPSSubscribeTask.java deleted
100644 → 0
| 1 | -package com.genersoft.iot.vmp.service; | |
| 2 | - | |
| 3 | -import com.genersoft.iot.vmp.service.bean.GPSMsgInfo; | |
| 4 | -import com.genersoft.iot.vmp.storager.IRedisCatchStorage; | |
| 5 | -import com.genersoft.iot.vmp.storager.IVideoManagerStorage; | |
| 6 | -import org.springframework.beans.factory.annotation.Autowired; | |
| 7 | -import org.springframework.scheduling.annotation.Scheduled; | |
| 8 | -import org.springframework.stereotype.Component; | |
| 9 | - | |
| 10 | -import java.util.List; | |
| 11 | - | |
| 12 | - | |
| 13 | -/** | |
| 14 | - * 定时查找redis中的GPS推送消息,并保存到对应的流中 | |
| 15 | - */ | |
| 16 | -@Component | |
| 17 | -public class StreamGPSSubscribeTask { | |
| 18 | - | |
| 19 | - @Autowired | |
| 20 | - private IRedisCatchStorage redisCatchStorage; | |
| 21 | - | |
| 22 | - @Autowired | |
| 23 | - private IVideoManagerStorage storager; | |
| 24 | - | |
| 25 | - | |
| 26 | - @Scheduled(fixedRate = 30 * 1000) //每30秒执行一次 | |
| 27 | - public void execute(){ | |
| 28 | - List<GPSMsgInfo> gpsMsgInfo = redisCatchStorage.getAllGpsMsgInfo(); | |
| 29 | - if (gpsMsgInfo.size() > 0) { | |
| 30 | - storager.updateStreamGPS(gpsMsgInfo); | |
| 31 | - for (GPSMsgInfo msgInfo : gpsMsgInfo) { | |
| 32 | - msgInfo.setStored(true); | |
| 33 | - redisCatchStorage.updateGpsMsgInfo(msgInfo); | |
| 34 | - } | |
| 35 | - } | |
| 36 | - | |
| 37 | - } | |
| 38 | -} |
src/main/java/com/genersoft/iot/vmp/service/impl/DeviceAlarmServiceImpl.java
| ... | ... | @@ -17,7 +17,6 @@ public class DeviceAlarmServiceImpl implements IDeviceAlarmService { |
| 17 | 17 | @Autowired |
| 18 | 18 | private DeviceAlarmMapper deviceAlarmMapper; |
| 19 | 19 | |
| 20 | - | |
| 21 | 20 | @Override |
| 22 | 21 | public PageInfo<DeviceAlarm> getAllAlarm(int page, int count, String deviceId, String alarmPriority, String alarmMethod, String alarmType, String startTime, String endTime) { |
| 23 | 22 | PageHelper.startPage(page, count); | ... | ... |
src/main/java/com/genersoft/iot/vmp/service/impl/DeviceChannelServiceImpl.java
0 → 100644
| 1 | +package com.genersoft.iot.vmp.service.impl; | |
| 2 | + | |
| 3 | +import com.genersoft.iot.vmp.common.StreamInfo; | |
| 4 | +import com.genersoft.iot.vmp.gb28181.bean.Device; | |
| 5 | +import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; | |
| 6 | +import com.genersoft.iot.vmp.gb28181.utils.Coordtransform; | |
| 7 | +import com.genersoft.iot.vmp.service.IDeviceChannelService; | |
| 8 | +import com.genersoft.iot.vmp.storager.IRedisCatchStorage; | |
| 9 | +import com.genersoft.iot.vmp.storager.dao.DeviceChannelMapper; | |
| 10 | +import com.genersoft.iot.vmp.storager.dao.DeviceMapper; | |
| 11 | +import com.genersoft.iot.vmp.utils.DateUtil; | |
| 12 | +import org.slf4j.Logger; | |
| 13 | +import org.slf4j.LoggerFactory; | |
| 14 | +import org.springframework.beans.factory.annotation.Autowired; | |
| 15 | +import org.springframework.stereotype.Service; | |
| 16 | + | |
| 17 | +import java.util.ArrayList; | |
| 18 | +import java.util.HashMap; | |
| 19 | +import java.util.List; | |
| 20 | + | |
| 21 | +/** | |
| 22 | + * @author lin | |
| 23 | + */ | |
| 24 | +@Service | |
| 25 | +public class DeviceChannelServiceImpl implements IDeviceChannelService { | |
| 26 | + | |
| 27 | + private final static Logger logger = LoggerFactory.getLogger(DeviceChannelServiceImpl.class); | |
| 28 | + | |
| 29 | + @Autowired | |
| 30 | + private IRedisCatchStorage redisCatchStorage; | |
| 31 | + | |
| 32 | + @Autowired | |
| 33 | + private DeviceChannelMapper channelMapper; | |
| 34 | + | |
| 35 | + @Autowired | |
| 36 | + private DeviceMapper deviceMapper; | |
| 37 | + | |
| 38 | + @Override | |
| 39 | + public DeviceChannel updateGps(DeviceChannel deviceChannel, Device device) { | |
| 40 | + if (deviceChannel.getLongitude()*deviceChannel.getLatitude() > 0) { | |
| 41 | + if (device == null) { | |
| 42 | + device = deviceMapper.getDeviceByDeviceId(deviceChannel.getDeviceId()); | |
| 43 | + } | |
| 44 | + | |
| 45 | + if ("WGS84".equals(device.getGeoCoordSys())) { | |
| 46 | + deviceChannel.setLongitudeWgs84(deviceChannel.getLongitude()); | |
| 47 | + deviceChannel.setLatitudeWgs84(deviceChannel.getLatitude()); | |
| 48 | + Double[] position = Coordtransform.WGS84ToGCJ02(deviceChannel.getLongitude(), deviceChannel.getLatitude()); | |
| 49 | + deviceChannel.setLongitudeGcj02(position[0]); | |
| 50 | + deviceChannel.setLatitudeGcj02(position[1]); | |
| 51 | + }else if ("GCJ02".equals(device.getGeoCoordSys())) { | |
| 52 | + deviceChannel.setLongitudeGcj02(deviceChannel.getLongitude()); | |
| 53 | + deviceChannel.setLatitudeGcj02(deviceChannel.getLatitude()); | |
| 54 | + Double[] position = Coordtransform.GCJ02ToWGS84(deviceChannel.getLongitude(), deviceChannel.getLatitude()); | |
| 55 | + deviceChannel.setLongitudeWgs84(position[0]); | |
| 56 | + deviceChannel.setLatitudeWgs84(position[1]); | |
| 57 | + }else { | |
| 58 | + deviceChannel.setLongitudeGcj02(0.00); | |
| 59 | + deviceChannel.setLatitudeGcj02(0.00); | |
| 60 | + deviceChannel.setLongitudeWgs84(0.00); | |
| 61 | + deviceChannel.setLatitudeWgs84(0.00); | |
| 62 | + } | |
| 63 | + }else { | |
| 64 | + deviceChannel.setLongitudeGcj02(deviceChannel.getLongitude()); | |
| 65 | + deviceChannel.setLatitudeGcj02(deviceChannel.getLatitude()); | |
| 66 | + deviceChannel.setLongitudeWgs84(deviceChannel.getLongitude()); | |
| 67 | + deviceChannel.setLatitudeWgs84(deviceChannel.getLatitude()); | |
| 68 | + } | |
| 69 | + return deviceChannel; | |
| 70 | + } | |
| 71 | + | |
| 72 | + @Override | |
| 73 | + public void updateChannel(String deviceId, DeviceChannel channel) { | |
| 74 | + String channelId = channel.getChannelId(); | |
| 75 | + channel.setDeviceId(deviceId); | |
| 76 | + StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(deviceId, channelId); | |
| 77 | + if (streamInfo != null) { | |
| 78 | + channel.setStreamId(streamInfo.getStream()); | |
| 79 | + } | |
| 80 | + String now = DateUtil.getNow(); | |
| 81 | + channel.setUpdateTime(now); | |
| 82 | + DeviceChannel deviceChannel = channelMapper.queryChannel(deviceId, channelId); | |
| 83 | + channel = updateGps(channel, null); | |
| 84 | + if (deviceChannel == null) { | |
| 85 | + channel.setCreateTime(now); | |
| 86 | + channelMapper.add(channel); | |
| 87 | + }else { | |
| 88 | + channelMapper.update(channel); | |
| 89 | + } | |
| 90 | + channelMapper.updateChannelSubCount(deviceId,channel.getParentId()); | |
| 91 | + } | |
| 92 | + | |
| 93 | + @Override | |
| 94 | + public int updateChannels(String deviceId, List<DeviceChannel> channels) { | |
| 95 | + List<DeviceChannel> addChannels = new ArrayList<>(); | |
| 96 | + List<DeviceChannel> updateChannels = new ArrayList<>(); | |
| 97 | + HashMap<String, DeviceChannel> channelsInStore = new HashMap<>(); | |
| 98 | + Device device = deviceMapper.getDeviceByDeviceId(deviceId); | |
| 99 | + if (channels != null && channels.size() > 0) { | |
| 100 | + List<DeviceChannel> channelList = channelMapper.queryChannels(deviceId, null, null, null, null); | |
| 101 | + if (channelList.size() == 0) { | |
| 102 | + for (DeviceChannel channel : channels) { | |
| 103 | + channel.setDeviceId(deviceId); | |
| 104 | + StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(deviceId, channel.getChannelId()); | |
| 105 | + if (streamInfo != null) { | |
| 106 | + channel.setStreamId(streamInfo.getStream()); | |
| 107 | + } | |
| 108 | + String now = DateUtil.getNow(); | |
| 109 | + channel.setUpdateTime(now); | |
| 110 | + channel.setCreateTime(now); | |
| 111 | + channel = updateGps(channel, device); | |
| 112 | + addChannels.add(channel); | |
| 113 | + } | |
| 114 | + }else { | |
| 115 | + for (DeviceChannel deviceChannel : channelList) { | |
| 116 | + channelsInStore.put(deviceChannel.getChannelId(), deviceChannel); | |
| 117 | + } | |
| 118 | + for (DeviceChannel channel : channels) { | |
| 119 | + channel.setDeviceId(deviceId); | |
| 120 | + StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(deviceId, channel.getChannelId()); | |
| 121 | + if (streamInfo != null) { | |
| 122 | + channel.setStreamId(streamInfo.getStream()); | |
| 123 | + } | |
| 124 | + String now = DateUtil.getNow(); | |
| 125 | + channel.setUpdateTime(now); | |
| 126 | + channel = updateGps(channel, device); | |
| 127 | + if (channelsInStore.get(channel.getChannelId()) != null) { | |
| 128 | + updateChannels.add(channel); | |
| 129 | + }else { | |
| 130 | + addChannels.add(channel); | |
| 131 | + channel.setCreateTime(now); | |
| 132 | + } | |
| 133 | + } | |
| 134 | + } | |
| 135 | + int limitCount = 300; | |
| 136 | + if (addChannels.size() > 0) { | |
| 137 | + if (addChannels.size() > limitCount) { | |
| 138 | + for (int i = 0; i < addChannels.size(); i += limitCount) { | |
| 139 | + int toIndex = i + limitCount; | |
| 140 | + if (i + limitCount > addChannels.size()) { | |
| 141 | + toIndex = addChannels.size(); | |
| 142 | + } | |
| 143 | + channelMapper.batchAdd(addChannels.subList(i, toIndex)); | |
| 144 | + } | |
| 145 | + }else { | |
| 146 | + channelMapper.batchAdd(addChannels); | |
| 147 | + } | |
| 148 | + } | |
| 149 | + if (updateChannels.size() > 0) { | |
| 150 | + if (updateChannels.size() > limitCount) { | |
| 151 | + for (int i = 0; i < updateChannels.size(); i += limitCount) { | |
| 152 | + int toIndex = i + limitCount; | |
| 153 | + if (i + limitCount > updateChannels.size()) { | |
| 154 | + toIndex = updateChannels.size(); | |
| 155 | + } | |
| 156 | + channelMapper.batchUpdate(updateChannels.subList(i, toIndex)); | |
| 157 | + } | |
| 158 | + }else { | |
| 159 | + channelMapper.batchUpdate(updateChannels); | |
| 160 | + } | |
| 161 | + } | |
| 162 | + } | |
| 163 | + return addChannels.size() + updateChannels.size(); | |
| 164 | + } | |
| 165 | +} | ... | ... |
src/main/java/com/genersoft/iot/vmp/service/impl/DeviceServiceImpl.java
| ... | ... | @@ -7,6 +7,7 @@ import com.genersoft.iot.vmp.gb28181.task.ISubscribeTask; |
| 7 | 7 | import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander; |
| 8 | 8 | import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.cmd.CatalogResponseMessageHandler; |
| 9 | 9 | import com.genersoft.iot.vmp.gb28181.utils.Coordtransform; |
| 10 | +import com.genersoft.iot.vmp.service.IDeviceChannelService; | |
| 10 | 11 | import com.genersoft.iot.vmp.service.IDeviceService; |
| 11 | 12 | import com.genersoft.iot.vmp.gb28181.task.impl.CatalogSubscribeTask; |
| 12 | 13 | import com.genersoft.iot.vmp.gb28181.task.impl.MobilePositionSubscribeTask; |
| ... | ... | @@ -56,6 +57,9 @@ public class DeviceServiceImpl implements IDeviceService { |
| 56 | 57 | private DeviceMapper deviceMapper; |
| 57 | 58 | |
| 58 | 59 | @Autowired |
| 60 | + private IDeviceChannelService deviceChannelService; | |
| 61 | + | |
| 62 | + @Autowired | |
| 59 | 63 | private DeviceChannelMapper deviceChannelMapper; |
| 60 | 64 | |
| 61 | 65 | @Autowired |
| ... | ... | @@ -82,10 +86,10 @@ public class DeviceServiceImpl implements IDeviceService { |
| 82 | 86 | redisCatchStorage.clearCatchByDeviceId(device.getDeviceId()); |
| 83 | 87 | } |
| 84 | 88 | device.setUpdateTime(now); |
| 85 | - device.setOnline(1); | |
| 86 | 89 | |
| 87 | - // 第一次上线 | |
| 90 | + // 第一次上线 或则设备之前是离线状态--进行通道同步和设备信息查询 | |
| 88 | 91 | if (device.getCreateTime() == null) { |
| 92 | + device.setOnline(1); | |
| 89 | 93 | device.setCreateTime(now); |
| 90 | 94 | logger.info("[设备上线,首次注册]: {},查询设备信息以及通道信息", device.getDeviceId()); |
| 91 | 95 | deviceMapper.add(device); |
| ... | ... | @@ -93,8 +97,19 @@ public class DeviceServiceImpl implements IDeviceService { |
| 93 | 97 | commander.deviceInfoQuery(device); |
| 94 | 98 | sync(device); |
| 95 | 99 | }else { |
| 96 | - deviceMapper.update(device); | |
| 97 | - redisCatchStorage.updateDevice(device); | |
| 100 | + if(device.getOnline() == 0){ | |
| 101 | + device.setOnline(1); | |
| 102 | + device.setCreateTime(now); | |
| 103 | + logger.info("[设备上线,离线状态下重新注册]: {},查询设备信息以及通道信息", device.getDeviceId()); | |
| 104 | + deviceMapper.update(device); | |
| 105 | + redisCatchStorage.updateDevice(device); | |
| 106 | + commander.deviceInfoQuery(device); | |
| 107 | + sync(device); | |
| 108 | + }else { | |
| 109 | + deviceMapper.update(device); | |
| 110 | + redisCatchStorage.updateDevice(device); | |
| 111 | + } | |
| 112 | + | |
| 98 | 113 | } |
| 99 | 114 | |
| 100 | 115 | // 上线添加订阅 |
| ... | ... | @@ -121,6 +136,8 @@ public class DeviceServiceImpl implements IDeviceService { |
| 121 | 136 | device.setOnline(0); |
| 122 | 137 | redisCatchStorage.updateDevice(device); |
| 123 | 138 | deviceMapper.update(device); |
| 139 | + //进行通道离线 | |
| 140 | + deviceChannelMapper.offlineByDeviceId(deviceId); | |
| 124 | 141 | // 离线释放所有ssrc |
| 125 | 142 | List<SsrcTransaction> ssrcTransactions = streamSession.getSsrcTransactionForAll(deviceId, null, null, null); |
| 126 | 143 | if (ssrcTransactions != null && ssrcTransactions.size() > 0) { |
| ... | ... | @@ -143,7 +160,7 @@ public class DeviceServiceImpl implements IDeviceService { |
| 143 | 160 | logger.info("[添加目录订阅] 设备{}", device.getDeviceId()); |
| 144 | 161 | // 添加目录订阅 |
| 145 | 162 | CatalogSubscribeTask catalogSubscribeTask = new CatalogSubscribeTask(device, sipCommander, dynamicTask); |
| 146 | - // 提前开始刷新订阅 | |
| 163 | + // 刷新订阅 | |
| 147 | 164 | int subscribeCycleForCatalog = Math.max(device.getSubscribeCycleForCatalog(),30); |
| 148 | 165 | // 设置最小值为30 |
| 149 | 166 | dynamicTask.startCron(device.getDeviceId() + "catalog", catalogSubscribeTask, (subscribeCycleForCatalog -1) * 1000); |
| ... | ... | @@ -178,8 +195,8 @@ public class DeviceServiceImpl implements IDeviceService { |
| 178 | 195 | MobilePositionSubscribeTask mobilePositionSubscribeTask = new MobilePositionSubscribeTask(device, sipCommander, dynamicTask); |
| 179 | 196 | // 设置最小值为30 |
| 180 | 197 | int subscribeCycleForCatalog = Math.max(device.getSubscribeCycleForMobilePosition(),30); |
| 181 | - // 提前开始刷新订阅 | |
| 182 | - dynamicTask.startCron(device.getDeviceId() + "mobile_position" , mobilePositionSubscribeTask, (subscribeCycleForCatalog -1 ) * 1000); | |
| 198 | + // 刷新订阅 | |
| 199 | + dynamicTask.startCron(device.getDeviceId() + "mobile_position" , mobilePositionSubscribeTask, (subscribeCycleForCatalog) * 1000); | |
| 183 | 200 | return true; |
| 184 | 201 | } |
| 185 | 202 | |
| ... | ... | @@ -324,23 +341,12 @@ public class DeviceServiceImpl implements IDeviceService { |
| 324 | 341 | private void updateDeviceChannelGeoCoordSys(Device device) { |
| 325 | 342 | List<DeviceChannel> deviceChannels = deviceChannelMapper.getAllChannelWithCoordinate(device.getDeviceId()); |
| 326 | 343 | if (deviceChannels.size() > 0) { |
| 344 | + List<DeviceChannel> deviceChannelsForStore = new ArrayList<>(); | |
| 327 | 345 | for (DeviceChannel deviceChannel : deviceChannels) { |
| 328 | - if ("WGS84".equals(device.getGeoCoordSys())) { | |
| 329 | - deviceChannel.setLongitudeWgs84(deviceChannel.getLongitude()); | |
| 330 | - deviceChannel.setLatitudeWgs84(deviceChannel.getLatitude()); | |
| 331 | - Double[] position = Coordtransform.WGS84ToGCJ02(deviceChannel.getLongitude(), deviceChannel.getLatitude()); | |
| 332 | - deviceChannel.setLongitudeGcj02(position[0]); | |
| 333 | - deviceChannel.setLatitudeGcj02(position[1]); | |
| 334 | - }else if ("GCJ02".equals(device.getGeoCoordSys())) { | |
| 335 | - deviceChannel.setLongitudeGcj02(deviceChannel.getLongitude()); | |
| 336 | - deviceChannel.setLatitudeGcj02(deviceChannel.getLatitude()); | |
| 337 | - Double[] position = Coordtransform.GCJ02ToWGS84(deviceChannel.getLongitude(), deviceChannel.getLatitude()); | |
| 338 | - deviceChannel.setLongitudeWgs84(position[0]); | |
| 339 | - deviceChannel.setLatitudeWgs84(position[1]); | |
| 340 | - } | |
| 346 | + deviceChannelsForStore.add(deviceChannelService.updateGps(deviceChannel, device)); | |
| 341 | 347 | } |
| 348 | + deviceChannelService.updateChannels(device.getDeviceId(), deviceChannelsForStore); | |
| 342 | 349 | } |
| 343 | - storage.updateChannels(device.getDeviceId(), deviceChannels); | |
| 344 | 350 | } |
| 345 | 351 | |
| 346 | 352 | |
| ... | ... | @@ -352,11 +358,11 @@ public class DeviceServiceImpl implements IDeviceService { |
| 352 | 358 | } |
| 353 | 359 | if (parentId == null || parentId.equals(deviceId)) { |
| 354 | 360 | // 字根节点开始查询 |
| 355 | - List<DeviceChannel> rootNodes = getRootNodes(deviceId, "CivilCode".equals(device.getTreeType()), true, !onlyCatalog); | |
| 361 | + List<DeviceChannel> rootNodes = getRootNodes(deviceId, TreeType.CIVIL_CODE.equals(device.getTreeType()), true, !onlyCatalog); | |
| 356 | 362 | return transportChannelsToTree(rootNodes, ""); |
| 357 | 363 | } |
| 358 | 364 | |
| 359 | - if ("CivilCode".equals(device.getTreeType())) { | |
| 365 | + if (TreeType.CIVIL_CODE.equals(device.getTreeType())) { | |
| 360 | 366 | if (parentId.length()%2 != 0) { |
| 361 | 367 | return null; |
| 362 | 368 | } |
| ... | ... | @@ -386,7 +392,7 @@ public class DeviceServiceImpl implements IDeviceService { |
| 386 | 392 | |
| 387 | 393 | } |
| 388 | 394 | // 使用业务分组展示树 |
| 389 | - if ("BusinessGroup".equals(device.getTreeType())) { | |
| 395 | + if (TreeType.BUSINESS_GROUP.equals(device.getTreeType())) { | |
| 390 | 396 | if (parentId.length() < 14 ) { |
| 391 | 397 | return null; |
| 392 | 398 | } |
| ... | ... | @@ -406,11 +412,11 @@ public class DeviceServiceImpl implements IDeviceService { |
| 406 | 412 | } |
| 407 | 413 | if (parentId == null || parentId.equals(deviceId)) { |
| 408 | 414 | // 字根节点开始查询 |
| 409 | - List<DeviceChannel> rootNodes = getRootNodes(deviceId, "CivilCode".equals(device.getTreeType()), false, true); | |
| 415 | + List<DeviceChannel> rootNodes = getRootNodes(deviceId, TreeType.CIVIL_CODE.equals(device.getTreeType()), false, true); | |
| 410 | 416 | return rootNodes; |
| 411 | 417 | } |
| 412 | 418 | |
| 413 | - if ("CivilCode".equals(device.getTreeType())) { | |
| 419 | + if (TreeType.CIVIL_CODE.equals(device.getTreeType())) { | |
| 414 | 420 | if (parentId.length()%2 != 0) { |
| 415 | 421 | return null; |
| 416 | 422 | } |
| ... | ... | @@ -431,7 +437,7 @@ public class DeviceServiceImpl implements IDeviceService { |
| 431 | 437 | |
| 432 | 438 | } |
| 433 | 439 | // 使用业务分组展示树 |
| 434 | - if ("BusinessGroup".equals(device.getTreeType())) { | |
| 440 | + if (TreeType.BUSINESS_GROUP.equals(device.getTreeType())) { | |
| 435 | 441 | if (parentId.length() < 14 ) { |
| 436 | 442 | return null; |
| 437 | 443 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/service/impl/GbStreamServiceImpl.java
| 1 | 1 | package com.genersoft.iot.vmp.service.impl; |
| 2 | 2 | |
| 3 | 3 | import com.genersoft.iot.vmp.conf.SipConfig; |
| 4 | -import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; | |
| 5 | -import com.genersoft.iot.vmp.gb28181.bean.GbStream; | |
| 6 | -import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; | |
| 4 | +import com.genersoft.iot.vmp.gb28181.bean.*; | |
| 7 | 5 | import com.genersoft.iot.vmp.gb28181.event.EventPublisher; |
| 8 | 6 | import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent; |
| 9 | 7 | import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem; |
| 10 | 8 | import com.genersoft.iot.vmp.storager.dao.GbStreamMapper; |
| 11 | 9 | import com.genersoft.iot.vmp.storager.dao.ParentPlatformMapper; |
| 10 | +import com.genersoft.iot.vmp.storager.dao.PlatformCatalogMapper; | |
| 12 | 11 | import com.genersoft.iot.vmp.storager.dao.PlatformGbStreamMapper; |
| 13 | 12 | import com.genersoft.iot.vmp.service.IGbStreamService; |
| 14 | 13 | import com.github.pagehelper.PageHelper; |
| ... | ... | @@ -46,15 +45,15 @@ public class GbStreamServiceImpl implements IGbStreamService { |
| 46 | 45 | private ParentPlatformMapper platformMapper; |
| 47 | 46 | |
| 48 | 47 | @Autowired |
| 49 | - private SipConfig sipConfig; | |
| 48 | + private PlatformCatalogMapper catalogMapper; | |
| 50 | 49 | |
| 51 | 50 | @Autowired |
| 52 | 51 | private EventPublisher eventPublisher; |
| 53 | 52 | |
| 54 | 53 | @Override |
| 55 | - public PageInfo<GbStream> getAll(Integer page, Integer count, String platFormId, String catalogId, String query, Boolean pushing, String mediaServerId) { | |
| 54 | + public PageInfo<GbStream> getAll(Integer page, Integer count, String platFormId, String catalogId, String query, String mediaServerId) { | |
| 56 | 55 | PageHelper.startPage(page, count); |
| 57 | - List<GbStream> all = gbStreamMapper.selectAll(platFormId, catalogId, query, pushing, mediaServerId); | |
| 56 | + List<GbStream> all = gbStreamMapper.selectAll(platFormId, catalogId, query, mediaServerId); | |
| 58 | 57 | return new PageInfo<>(all); |
| 59 | 58 | } |
| 60 | 59 | |
| ... | ... | @@ -102,16 +101,25 @@ public class GbStreamServiceImpl implements IGbStreamService { |
| 102 | 101 | deviceChannel.setLatitude(gbStream.getLatitude()); |
| 103 | 102 | deviceChannel.setDeviceId(platform.getDeviceGBId()); |
| 104 | 103 | deviceChannel.setManufacture("wvp-pro"); |
| 105 | -// deviceChannel.setStatus(gbStream.isStatus()?1:0); | |
| 106 | - deviceChannel.setStatus(1); | |
| 107 | - deviceChannel.setParentId(catalogId ==null?gbStream.getCatalogId():catalogId); | |
| 104 | + deviceChannel.setStatus(gbStream.isStatus()?1:0); | |
| 105 | + | |
| 108 | 106 | deviceChannel.setRegisterWay(1); |
| 109 | - if (catalogId.length() > 0 && catalogId.length() <= 10) { | |
| 110 | - // 父节点是行政区划,则设置CivilCode使用此行政区划 | |
| 107 | + deviceChannel.setCivilCode(platform.getAdministrativeDivision()); | |
| 108 | + | |
| 109 | + if (platform.getTreeType().equals(TreeType.CIVIL_CODE)){ | |
| 111 | 110 | deviceChannel.setCivilCode(catalogId); |
| 112 | - }else { | |
| 113 | - deviceChannel.setCivilCode(platform.getAdministrativeDivision()); | |
| 111 | + }else if (platform.getTreeType().equals(TreeType.BUSINESS_GROUP)){ | |
| 112 | + PlatformCatalog catalog = catalogMapper.select(catalogId); | |
| 113 | + if (catalog == null) { | |
| 114 | + deviceChannel.setParentId(platform.getDeviceGBId()); | |
| 115 | + deviceChannel.setBusinessGroupId(null); | |
| 116 | + }else { | |
| 117 | + deviceChannel.setParentId(catalog.getId()); | |
| 118 | + deviceChannel.setBusinessGroupId(catalog.getBusinessGroupId()); | |
| 119 | + } | |
| 120 | + | |
| 114 | 121 | } |
| 122 | + | |
| 115 | 123 | deviceChannel.setModel("live"); |
| 116 | 124 | deviceChannel.setOwner("wvp-pro"); |
| 117 | 125 | deviceChannel.setParental(0); | ... | ... |
src/main/java/com/genersoft/iot/vmp/service/impl/MediaServerServiceImpl.java
| 1 | 1 | package com.genersoft.iot.vmp.service.impl; |
| 2 | 2 | |
| 3 | +import java.time.LocalDateTime; | |
| 4 | +import java.util.ArrayList; | |
| 5 | +import java.util.Collections; | |
| 6 | +import java.util.HashMap; | |
| 7 | +import java.util.List; | |
| 8 | +import java.util.Map; | |
| 9 | +import java.util.Set; | |
| 10 | + | |
| 11 | +import com.genersoft.iot.vmp.media.zlm.ZLMRunner; | |
| 12 | +import com.genersoft.iot.vmp.service.IStreamProxyService; | |
| 13 | +import com.genersoft.iot.vmp.storager.IVideoManagerStorage; | |
| 14 | +import org.slf4j.Logger; | |
| 15 | +import org.slf4j.LoggerFactory; | |
| 16 | +import org.springframework.beans.factory.annotation.Autowired; | |
| 17 | +import org.springframework.beans.factory.annotation.Value; | |
| 18 | +import org.springframework.jdbc.datasource.DataSourceTransactionManager; | |
| 19 | +import org.springframework.stereotype.Service; | |
| 20 | +import org.springframework.transaction.TransactionDefinition; | |
| 21 | +import org.springframework.transaction.TransactionStatus; | |
| 22 | +import org.springframework.util.StringUtils; | |
| 23 | + | |
| 3 | 24 | import com.alibaba.fastjson.JSON; |
| 4 | 25 | import com.alibaba.fastjson.JSONArray; |
| 5 | 26 | import com.alibaba.fastjson.JSONObject; |
| ... | ... | @@ -14,25 +35,16 @@ import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory; |
| 14 | 35 | import com.genersoft.iot.vmp.media.zlm.ZLMServerConfig; |
| 15 | 36 | import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; |
| 16 | 37 | import com.genersoft.iot.vmp.service.IMediaServerService; |
| 17 | -import com.genersoft.iot.vmp.service.IStreamProxyService; | |
| 18 | 38 | import com.genersoft.iot.vmp.service.bean.SSRCInfo; |
| 19 | -import com.genersoft.iot.vmp.storager.IVideoManagerStorage; | |
| 20 | 39 | import com.genersoft.iot.vmp.storager.dao.MediaServerMapper; |
| 21 | 40 | import com.genersoft.iot.vmp.utils.DateUtil; |
| 22 | 41 | import com.genersoft.iot.vmp.utils.redis.JedisUtil; |
| 23 | 42 | import com.genersoft.iot.vmp.utils.redis.RedisUtil; |
| 24 | 43 | import com.genersoft.iot.vmp.vmanager.bean.WVPResult; |
| 25 | -import okhttp3.*; | |
| 26 | -import org.slf4j.Logger; | |
| 27 | -import org.slf4j.LoggerFactory; | |
| 28 | -import org.springframework.beans.factory.annotation.Autowired; | |
| 29 | -import org.springframework.beans.factory.annotation.Value; | |
| 30 | -import org.springframework.jdbc.datasource.DataSourceTransactionManager; | |
| 31 | -import org.springframework.stereotype.Service; | |
| 32 | -import org.springframework.transaction.TransactionDefinition; | |
| 33 | -import org.springframework.transaction.TransactionStatus; | |
| 34 | -import org.springframework.util.StringUtils; | |
| 35 | 44 | |
| 45 | +import okhttp3.OkHttpClient; | |
| 46 | +import okhttp3.Request; | |
| 47 | +import okhttp3.Response; | |
| 36 | 48 | import java.time.LocalDateTime; |
| 37 | 49 | import java.util.*; |
| 38 | 50 | |
| ... | ... | @@ -47,6 +59,9 @@ public class MediaServerServiceImpl implements IMediaServerService { |
| 47 | 59 | @Autowired |
| 48 | 60 | private SipConfig sipConfig; |
| 49 | 61 | |
| 62 | + @Autowired | |
| 63 | + private ZLMRunner zlmRunner; | |
| 64 | + | |
| 50 | 65 | @Value("${server.ssl.enabled:false}") |
| 51 | 66 | private boolean sslEnabled; |
| 52 | 67 | |
| ... | ... | @@ -120,7 +135,7 @@ public class MediaServerServiceImpl implements IMediaServerService { |
| 120 | 135 | } |
| 121 | 136 | |
| 122 | 137 | @Override |
| 123 | - public SSRCInfo openRTPServer(MediaServerItem mediaServerItem, String streamId, String presetSsrc, boolean ssrcCheck, boolean isPlayback) { | |
| 138 | + public SSRCInfo openRTPServer(MediaServerItem mediaServerItem, String streamId, String presetSsrc, boolean ssrcCheck, boolean isPlayback, Integer port) { | |
| 124 | 139 | if (mediaServerItem == null || mediaServerItem.getId() == null) { |
| 125 | 140 | return null; |
| 126 | 141 | } |
| ... | ... | @@ -148,7 +163,7 @@ public class MediaServerServiceImpl implements IMediaServerService { |
| 148 | 163 | } |
| 149 | 164 | int rtpServerPort = mediaServerItem.getRtpProxyPort(); |
| 150 | 165 | if (mediaServerItem.isRtpEnable()) { |
| 151 | - rtpServerPort = zlmrtpServerFactory.createRTPServer(mediaServerItem, streamId, ssrcCheck?Integer.parseInt(ssrc):0); | |
| 166 | + rtpServerPort = zlmrtpServerFactory.createRTPServer(mediaServerItem, streamId, ssrcCheck?Integer.parseInt(ssrc):0, port); | |
| 152 | 167 | } |
| 153 | 168 | redisUtil.set(key, mediaServerItem); |
| 154 | 169 | return new SSRCInfo(rtpServerPort, ssrc, streamId); |
| ... | ... | @@ -156,6 +171,11 @@ public class MediaServerServiceImpl implements IMediaServerService { |
| 156 | 171 | } |
| 157 | 172 | |
| 158 | 173 | @Override |
| 174 | + public SSRCInfo openRTPServer(MediaServerItem mediaServerItem, String streamId, String ssrc, boolean ssrcCheck, boolean isPlayback) { | |
| 175 | + return openRTPServer(mediaServerItem, streamId, ssrc, ssrcCheck, isPlayback, null); | |
| 176 | + } | |
| 177 | + | |
| 178 | + @Override | |
| 159 | 179 | public void closeRTPServer(String deviceId, String channelId, String stream) { |
| 160 | 180 | String mediaServerId = streamSession.getMediaServerId(deviceId, channelId, stream); |
| 161 | 181 | String ssrc = streamSession.getSSRC(deviceId, channelId, stream); |
| ... | ... | @@ -271,7 +291,13 @@ public class MediaServerServiceImpl implements IMediaServerService { |
| 271 | 291 | return null; |
| 272 | 292 | } |
| 273 | 293 | String key = VideoManagerConstants.MEDIA_SERVER_PREFIX + userSetting.getServerId() + "_" + mediaServerId; |
| 274 | - return (MediaServerItem)redisUtil.get(key); | |
| 294 | + MediaServerItem serverItem=(MediaServerItem)redisUtil.get(key); | |
| 295 | + if(null==serverItem){ | |
| 296 | + //zlm服务不在线,启动重连 | |
| 297 | + reloadZlm(); | |
| 298 | + serverItem=(MediaServerItem)redisUtil.get(key); | |
| 299 | + } | |
| 300 | + return serverItem; | |
| 275 | 301 | } |
| 276 | 302 | |
| 277 | 303 | @Override |
| ... | ... | @@ -351,14 +377,15 @@ public class MediaServerServiceImpl implements IMediaServerService { |
| 351 | 377 | */ |
| 352 | 378 | @Override |
| 353 | 379 | public void zlmServerOnline(ZLMServerConfig zlmServerConfig) { |
| 354 | - logger.info("[ZLM] 正在连接 : {} -> {}:{}", | |
| 355 | - zlmServerConfig.getGeneralMediaServerId(), zlmServerConfig.getIp(), zlmServerConfig.getHttpPort()); | |
| 356 | 380 | |
| 357 | 381 | MediaServerItem serverItem = mediaServerMapper.queryOne(zlmServerConfig.getGeneralMediaServerId()); |
| 358 | 382 | if (serverItem == null) { |
| 359 | 383 | logger.warn("[未注册的zlm] 拒接接入:{}来自{}:{}", zlmServerConfig.getGeneralMediaServerId(), zlmServerConfig.getIp(),zlmServerConfig.getHttpPort() ); |
| 360 | 384 | logger.warn("请检查ZLM的<general.mediaServerId>配置是否与WVP的<media.id>一致"); |
| 361 | 385 | return; |
| 386 | + }else { | |
| 387 | + logger.info("[ZLM] 正在连接 : {} -> {}:{}", | |
| 388 | + zlmServerConfig.getGeneralMediaServerId(), zlmServerConfig.getIp(), zlmServerConfig.getHttpPort()); | |
| 362 | 389 | } |
| 363 | 390 | serverItem.setHookAliveInterval(zlmServerConfig.getHookAliveInterval()); |
| 364 | 391 | if (serverItem.getHttpPort() == 0) { |
| ... | ... | @@ -463,8 +490,13 @@ public class MediaServerServiceImpl implements IMediaServerService { |
| 463 | 490 | String key = VideoManagerConstants.MEDIA_SERVERS_ONLINE_PREFIX + userSetting.getServerId(); |
| 464 | 491 | |
| 465 | 492 | if (redisUtil.zSize(key) == null || redisUtil.zSize(key) == 0) { |
| 466 | - logger.info("获取负载最低的节点时无在线节点"); | |
| 467 | - return null; | |
| 493 | + logger.info("获取负载最低的节点时无在线节点,启动重连机制"); | |
| 494 | + //启动重连 | |
| 495 | + reloadZlm(); | |
| 496 | + if (redisUtil.zSize(key) == null || redisUtil.zSize(key) == 0) { | |
| 497 | + logger.info("获取负载最低的节点时无在线节点"); | |
| 498 | + return null; | |
| 499 | + } | |
| 468 | 500 | } |
| 469 | 501 | |
| 470 | 502 | // 获取分数最低的,及并发最低的 |
| ... | ... | @@ -595,9 +627,6 @@ public class MediaServerServiceImpl implements IMediaServerService { |
| 595 | 627 | boolean result = false; |
| 596 | 628 | OkHttpClient client = new OkHttpClient(); |
| 597 | 629 | String url = String.format("http://%s:%s/index/api/record", ip, port); |
| 598 | - | |
| 599 | - FormBody.Builder builder = new FormBody.Builder(); | |
| 600 | - | |
| 601 | 630 | Request request = new Request.Builder() |
| 602 | 631 | .get() |
| 603 | 632 | .url(url) |
| ... | ... | @@ -629,9 +658,14 @@ public class MediaServerServiceImpl implements IMediaServerService { |
| 629 | 658 | MediaServerItem mediaServerItem = getOne(mediaServerId); |
| 630 | 659 | if (mediaServerItem == null) { |
| 631 | 660 | // zlm连接重试 |
| 632 | - | |
| 633 | - logger.warn("[更新ZLM 保活信息]失败,未找到流媒体信息"); | |
| 634 | - return; | |
| 661 | + logger.warn("[更新ZLM 保活信息]失败,未找到流媒体信息,尝试重连zlm"); | |
| 662 | + reloadZlm(); | |
| 663 | + mediaServerItem = getOne(mediaServerId); | |
| 664 | + if (mediaServerItem == null) { | |
| 665 | + // zlm连接重试 | |
| 666 | + logger.warn("[更新ZLM 保活信息]失败,未找到流媒体信息"); | |
| 667 | + return; | |
| 668 | + } | |
| 635 | 669 | } |
| 636 | 670 | String key = VideoManagerConstants.MEDIA_SERVER_KEEPALIVE_PREFIX + userSetting.getServerId() + "_" + mediaServerId; |
| 637 | 671 | int hookAliveInterval = mediaServerItem.getHookAliveInterval() + 2; |
| ... | ... | @@ -648,10 +682,18 @@ public class MediaServerServiceImpl implements IMediaServerService { |
| 648 | 682 | mediaServerItemMap.put(mediaServerItem.getId(), mediaServerItem); |
| 649 | 683 | } |
| 650 | 684 | for (MediaServerItem mediaServerItem : allInCatch) { |
| 651 | - if (mediaServerItemMap.get(mediaServerItem) == null) { | |
| 685 | + if (!mediaServerItemMap.containsKey(mediaServerItem.getId())) { | |
| 652 | 686 | delete(mediaServerItem.getId()); |
| 653 | 687 | } |
| 654 | 688 | } |
| 655 | 689 | } |
| 656 | 690 | |
| 691 | + public void reloadZlm(){ | |
| 692 | + try { | |
| 693 | + zlmRunner.run(); | |
| 694 | + Thread.sleep(500);//延迟0.5秒缓冲时间 | |
| 695 | + } catch (Exception e) { | |
| 696 | + logger.warn("尝试重连zlm失败!",e); | |
| 697 | + } | |
| 698 | + } | |
| 657 | 699 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/service/impl/MediaServiceImpl.java
| ... | ... | @@ -67,9 +67,9 @@ public class MediaServiceImpl implements IMediaService { |
| 67 | 67 | JSONObject mediaJSON = JSON.parseObject(JSON.toJSONString(data.get(0)), JSONObject.class); |
| 68 | 68 | JSONArray tracks = mediaJSON.getJSONArray("tracks"); |
| 69 | 69 | if (authority) { |
| 70 | - streamInfo = getStreamInfoByAppAndStream(mediaInfo, app, stream, tracks, null, streamAuthorityInfo.getCallId(), true); | |
| 70 | + streamInfo = getStreamInfoByAppAndStream(mediaInfo, app, stream, tracks, addr,streamAuthorityInfo.getCallId(), true); | |
| 71 | 71 | }else { |
| 72 | - streamInfo = getStreamInfoByAppAndStream(mediaInfo, app, stream, tracks, null); | |
| 72 | + streamInfo = getStreamInfoByAppAndStream(mediaInfo, app, stream, tracks, addr,null); | |
| 73 | 73 | } |
| 74 | 74 | |
| 75 | 75 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/service/impl/PlatformChannelServiceImpl.java
0 → 100644
| 1 | +package com.genersoft.iot.vmp.service.impl; | |
| 2 | + | |
| 3 | +import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; | |
| 4 | +import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; | |
| 5 | +import com.genersoft.iot.vmp.gb28181.bean.PlatformCatalog; | |
| 6 | +import com.genersoft.iot.vmp.gb28181.bean.TreeType; | |
| 7 | +import com.genersoft.iot.vmp.gb28181.event.EventPublisher; | |
| 8 | +import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent; | |
| 9 | +import com.genersoft.iot.vmp.service.IPlatformChannelService; | |
| 10 | +import com.genersoft.iot.vmp.storager.dao.DeviceChannelMapper; | |
| 11 | +import com.genersoft.iot.vmp.storager.dao.ParentPlatformMapper; | |
| 12 | +import com.genersoft.iot.vmp.storager.dao.PlatformCatalogMapper; | |
| 13 | +import com.genersoft.iot.vmp.storager.dao.PlatformChannelMapper; | |
| 14 | +import com.genersoft.iot.vmp.vmanager.gb28181.platform.bean.ChannelReduce; | |
| 15 | +import org.slf4j.Logger; | |
| 16 | +import org.slf4j.LoggerFactory; | |
| 17 | +import org.springframework.beans.factory.annotation.Autowired; | |
| 18 | +import org.springframework.stereotype.Service; | |
| 19 | + | |
| 20 | +import java.util.ArrayList; | |
| 21 | +import java.util.HashMap; | |
| 22 | +import java.util.List; | |
| 23 | +import java.util.Map; | |
| 24 | + | |
| 25 | +/** | |
| 26 | + * @author lin | |
| 27 | + */ | |
| 28 | +@Service | |
| 29 | +public class PlatformChannelServiceImpl implements IPlatformChannelService { | |
| 30 | + | |
| 31 | + private final static Logger logger = LoggerFactory.getLogger(PlatformChannelServiceImpl.class); | |
| 32 | + | |
| 33 | + @Autowired | |
| 34 | + private PlatformChannelMapper platformChannelMapper; | |
| 35 | + | |
| 36 | + @Autowired | |
| 37 | + private DeviceChannelMapper deviceChannelMapper; | |
| 38 | + | |
| 39 | + @Autowired | |
| 40 | + private PlatformCatalogMapper catalogManager; | |
| 41 | + | |
| 42 | + @Autowired | |
| 43 | + private ParentPlatformMapper platformMapper; | |
| 44 | + | |
| 45 | + @Autowired | |
| 46 | + EventPublisher eventPublisher; | |
| 47 | + | |
| 48 | + @Override | |
| 49 | + public int updateChannelForGB(String platformId, List<ChannelReduce> channelReduces, String catalogId) { | |
| 50 | + ParentPlatform platform = platformMapper.getParentPlatByServerGBId(platformId); | |
| 51 | + if (platform == null) { | |
| 52 | + logger.warn("更新级联通道信息时未找到平台{}的信息", platformId); | |
| 53 | + return 0; | |
| 54 | + } | |
| 55 | + Map<Integer, ChannelReduce> deviceAndChannels = new HashMap<>(); | |
| 56 | + for (ChannelReduce channelReduce : channelReduces) { | |
| 57 | + channelReduce.setCatalogId(catalogId); | |
| 58 | + deviceAndChannels.put(channelReduce.getId(), channelReduce); | |
| 59 | + } | |
| 60 | + List<Integer> deviceAndChannelList = new ArrayList<>(deviceAndChannels.keySet()); | |
| 61 | + // 查询当前已经存在的 | |
| 62 | + List<Integer> channelIds = platformChannelMapper.findChannelRelatedPlatform(platformId, channelReduces); | |
| 63 | + if (deviceAndChannelList != null) { | |
| 64 | + deviceAndChannelList.removeAll(channelIds); | |
| 65 | + } | |
| 66 | + for (Integer channelId : channelIds) { | |
| 67 | + deviceAndChannels.remove(channelId); | |
| 68 | + } | |
| 69 | + List<ChannelReduce> channelReducesToAdd = new ArrayList<>(deviceAndChannels.values()); | |
| 70 | + // 对剩下的数据进行存储 | |
| 71 | + int result = 0; | |
| 72 | + if (channelReducesToAdd.size() > 0) { | |
| 73 | + result = platformChannelMapper.addChannels(platformId, channelReducesToAdd); | |
| 74 | + // TODO 后续给平台增加控制开关以控制是否响应目录订阅 | |
| 75 | + List<DeviceChannel> deviceChannelList = getDeviceChannelListByChannelReduceList(channelReducesToAdd, catalogId, platform); | |
| 76 | + eventPublisher.catalogEventPublish(platformId, deviceChannelList, CatalogEvent.ADD); | |
| 77 | + } | |
| 78 | + | |
| 79 | + return result; | |
| 80 | + } | |
| 81 | + | |
| 82 | + private List<DeviceChannel> getDeviceChannelListByChannelReduceList(List<ChannelReduce> channelReduces, String catalogId, ParentPlatform platform) { | |
| 83 | + List<DeviceChannel> deviceChannelList = new ArrayList<>(); | |
| 84 | + if (channelReduces.size() > 0){ | |
| 85 | + PlatformCatalog catalog = catalogManager.select(catalogId); | |
| 86 | + if (catalog == null && !catalogId.equals(platform.getServerGBId())) { | |
| 87 | + logger.warn("未查询到目录{}的信息", catalogId); | |
| 88 | + return null; | |
| 89 | + } | |
| 90 | + for (ChannelReduce channelReduce : channelReduces) { | |
| 91 | + DeviceChannel deviceChannel = deviceChannelMapper.queryChannel(channelReduce.getDeviceId(), channelReduce.getChannelId()); | |
| 92 | + deviceChannel.setParental(0); | |
| 93 | + deviceChannelList.add(deviceChannel); | |
| 94 | + if (platform.getTreeType().equals(TreeType.CIVIL_CODE)){ | |
| 95 | + deviceChannel.setCivilCode(catalogId); | |
| 96 | + }else if (platform.getTreeType().equals(TreeType.BUSINESS_GROUP)){ | |
| 97 | + deviceChannel.setParentId(catalogId); | |
| 98 | + if (catalog != null) { | |
| 99 | + deviceChannel.setBusinessGroupId(catalog.getBusinessGroupId()); | |
| 100 | + } | |
| 101 | + } | |
| 102 | + } | |
| 103 | + } | |
| 104 | + return deviceChannelList; | |
| 105 | + } | |
| 106 | +} | ... | ... |
src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java
| 1 | 1 | package com.genersoft.iot.vmp.service.impl; |
| 2 | 2 | |
| 3 | +import java.math.BigDecimal; | |
| 4 | +import java.math.RoundingMode; | |
| 5 | +import java.util.List; | |
| 6 | +import java.util.Objects; | |
| 7 | +import java.util.UUID; | |
| 8 | + | |
| 9 | +import javax.sip.ResponseEvent; | |
| 10 | + | |
| 11 | +import org.slf4j.Logger; | |
| 12 | +import org.slf4j.LoggerFactory; | |
| 13 | +import org.springframework.beans.factory.annotation.Autowired; | |
| 14 | +import org.springframework.http.HttpStatus; | |
| 15 | +import org.springframework.http.ResponseEntity; | |
| 16 | +import org.springframework.stereotype.Service; | |
| 17 | +import org.springframework.web.context.request.async.DeferredResult; | |
| 18 | + | |
| 3 | 19 | import com.alibaba.fastjson.JSON; |
| 4 | 20 | import com.alibaba.fastjson.JSONArray; |
| 5 | 21 | import com.alibaba.fastjson.JSONObject; |
| ... | ... | @@ -7,7 +23,13 @@ import com.genersoft.iot.vmp.common.StreamInfo; |
| 7 | 23 | import com.genersoft.iot.vmp.conf.DynamicTask; |
| 8 | 24 | import com.genersoft.iot.vmp.conf.SipConfig; |
| 9 | 25 | import com.genersoft.iot.vmp.conf.UserSetting; |
| 10 | -import com.genersoft.iot.vmp.gb28181.bean.*; | |
| 26 | +import com.genersoft.iot.vmp.gb28181.bean.Device; | |
| 27 | +import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; | |
| 28 | +import com.genersoft.iot.vmp.gb28181.bean.InviteStreamCallback; | |
| 29 | +import com.genersoft.iot.vmp.gb28181.bean.InviteStreamInfo; | |
| 30 | +import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; | |
| 31 | +import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem; | |
| 32 | +import com.genersoft.iot.vmp.gb28181.bean.SsrcTransaction; | |
| 11 | 33 | import com.genersoft.iot.vmp.gb28181.event.SipSubscribe; |
| 12 | 34 | import com.genersoft.iot.vmp.gb28181.session.AudioBroadcastManager; |
| 13 | 35 | import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager; |
| ... | ... | @@ -16,6 +38,9 @@ import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage; |
| 16 | 38 | import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; |
| 17 | 39 | import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform; |
| 18 | 40 | import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory; |
| 41 | +import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeFactory; | |
| 42 | +import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForStreamChange; | |
| 43 | +import com.genersoft.iot.vmp.media.zlm.dto.HookType; | |
| 19 | 44 | import com.genersoft.iot.vmp.utils.DateUtil; |
| 20 | 45 | import com.genersoft.iot.vmp.media.zlm.AssistRESTfulUtils; |
| 21 | 46 | import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe; |
| ... | ... | @@ -32,9 +57,11 @@ import com.genersoft.iot.vmp.storager.IRedisCatchStorage; |
| 32 | 57 | import com.genersoft.iot.vmp.storager.IVideoManagerStorage; |
| 33 | 58 | import com.genersoft.iot.vmp.utils.redis.RedisUtil; |
| 34 | 59 | import com.genersoft.iot.vmp.vmanager.bean.AudioBroadcastResult; |
| 60 | +import com.genersoft.iot.vmp.utils.DateUtil; | |
| 35 | 61 | import com.genersoft.iot.vmp.vmanager.bean.WVPResult; |
| 36 | 62 | import com.genersoft.iot.vmp.vmanager.gb28181.play.bean.AudioBroadcastEvent; |
| 37 | 63 | import com.genersoft.iot.vmp.vmanager.gb28181.play.bean.PlayResult; |
| 64 | + | |
| 38 | 65 | import gov.nist.javax.sip.stack.SIPDialog; |
| 39 | 66 | import org.slf4j.Logger; |
| 40 | 67 | import org.slf4j.LoggerFactory; |
| ... | ... | @@ -313,16 +340,10 @@ public class PlayServiceImpl implements IPlayService { |
| 313 | 340 | // 单端口模式streamId也有变化,需要重新设置监听 |
| 314 | 341 | if (!mediaServerItem.isRtpEnable()) { |
| 315 | 342 | // 添加订阅 |
| 316 | - JSONObject subscribeKey = new JSONObject(); | |
| 317 | - subscribeKey.put("app", "rtp"); | |
| 318 | - subscribeKey.put("stream", stream); | |
| 319 | - subscribeKey.put("regist", true); | |
| 320 | - subscribeKey.put("schema", "rtmp"); | |
| 321 | - subscribeKey.put("mediaServerId", mediaServerItem.getId()); | |
| 322 | - subscribe.removeSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed,subscribeKey); | |
| 323 | - subscribeKey.put("stream", String.format("%08x", Integer.parseInt(ssrcInResponse)).toUpperCase()); | |
| 324 | - subscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey, | |
| 325 | - (MediaServerItem mediaServerItemInUse, JSONObject response)->{ | |
| 343 | + HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", stream, true, "rtmp", mediaServerItem.getId()); | |
| 344 | + subscribe.removeSubscribe(hookSubscribe); | |
| 345 | + hookSubscribe.getContent().put("stream", String.format("%08x", Integer.parseInt(ssrcInResponse)).toUpperCase()); | |
| 346 | + subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, JSONObject response)->{ | |
| 326 | 347 | logger.info("[ZLM HOOK] ssrc修正后收到订阅消息: " + response.toJSONString()); |
| 327 | 348 | dynamicTask.stop(timeOutTaskKey); |
| 328 | 349 | // hook响应 |
| ... | ... | @@ -333,7 +354,7 @@ public class PlayServiceImpl implements IPlayService { |
| 333 | 354 | // 关闭rtp server |
| 334 | 355 | mediaServerService.closeRTPServer(device.getDeviceId(), channelId, finalSsrcInfo.getStream()); |
| 335 | 356 | // 重新开启ssrc server |
| 336 | - mediaServerService.openRTPServer(mediaServerItem, finalSsrcInfo.getStream(), ssrcInResponse, device.isSsrcCheck(), false); | |
| 357 | + mediaServerService.openRTPServer(mediaServerItem, finalSsrcInfo.getStream(), ssrcInResponse, device.isSsrcCheck(), false, finalSsrcInfo.getPort()); | |
| 337 | 358 | |
| 338 | 359 | } |
| 339 | 360 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/service/impl/RedisGbPlayMsgListener.java
| ... | ... | @@ -8,6 +8,9 @@ import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem; |
| 8 | 8 | import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe; |
| 9 | 9 | import com.genersoft.iot.vmp.media.zlm.ZLMMediaListManager; |
| 10 | 10 | import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory; |
| 11 | +import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeFactory; | |
| 12 | +import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForStreamChange; | |
| 13 | +import com.genersoft.iot.vmp.media.zlm.dto.HookType; | |
| 11 | 14 | import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; |
| 12 | 15 | import com.genersoft.iot.vmp.service.IMediaServerService; |
| 13 | 16 | import com.genersoft.iot.vmp.service.bean.*; |
| ... | ... | @@ -270,14 +273,9 @@ public class RedisGbPlayMsgListener implements MessageListener { |
| 270 | 273 | }, userSetting.getPlatformPlayTimeout()); |
| 271 | 274 | |
| 272 | 275 | // 添加订阅 |
| 273 | - JSONObject subscribeKey = new JSONObject(); | |
| 274 | - subscribeKey.put("app", content.getApp()); | |
| 275 | - subscribeKey.put("stream", content.getStream()); | |
| 276 | - subscribeKey.put("regist", true); | |
| 277 | - subscribeKey.put("schema", "rtmp"); | |
| 278 | - subscribeKey.put("mediaServerId", mediaServerItem.getId()); | |
| 279 | - subscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey, | |
| 280 | - (MediaServerItem mediaServerItemInUse, JSONObject json)->{ | |
| 276 | + HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed(content.getApp(), content.getStream(), true, "rtmp", mediaServerItem.getId()); | |
| 277 | + | |
| 278 | + subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, JSONObject json)->{ | |
| 281 | 279 | dynamicTask.stop(taskKey); |
| 282 | 280 | responseSendItem(mediaServerItem, content, toId, serial); |
| 283 | 281 | }); | ... | ... |
src/main/java/com/genersoft/iot/vmp/service/impl/RedisGpsMsgListener.java
| 1 | 1 | package com.genersoft.iot.vmp.service.impl; |
| 2 | 2 | |
| 3 | 3 | import com.alibaba.fastjson.JSON; |
| 4 | +import com.genersoft.iot.vmp.gb28181.bean.HandlerCatchData; | |
| 4 | 5 | import com.genersoft.iot.vmp.service.bean.GPSMsgInfo; |
| 5 | 6 | import com.genersoft.iot.vmp.storager.IRedisCatchStorage; |
| 7 | +import com.genersoft.iot.vmp.storager.IVideoManagerStorage; | |
| 6 | 8 | import org.jetbrains.annotations.NotNull; |
| 7 | 9 | import org.slf4j.Logger; |
| 8 | 10 | import org.slf4j.LoggerFactory; |
| 9 | 11 | import org.springframework.beans.factory.annotation.Autowired; |
| 12 | +import org.springframework.beans.factory.annotation.Qualifier; | |
| 10 | 13 | import org.springframework.data.redis.connection.Message; |
| 11 | 14 | import org.springframework.data.redis.connection.MessageListener; |
| 15 | +import org.springframework.scheduling.annotation.Scheduled; | |
| 16 | +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; | |
| 12 | 17 | import org.springframework.stereotype.Component; |
| 13 | 18 | |
| 19 | +import java.util.List; | |
| 20 | +import java.util.concurrent.ConcurrentLinkedQueue; | |
| 21 | + | |
| 14 | 22 | /** |
| 15 | 23 | * 接收来自redis的GPS更新通知 |
| 16 | 24 | * @author lin |
| ... | ... | @@ -20,12 +28,50 @@ public class RedisGpsMsgListener implements MessageListener { |
| 20 | 28 | |
| 21 | 29 | private final static Logger logger = LoggerFactory.getLogger(RedisGpsMsgListener.class); |
| 22 | 30 | |
| 31 | + private boolean taskQueueHandlerRun = false; | |
| 32 | + | |
| 23 | 33 | @Autowired |
| 24 | 34 | private IRedisCatchStorage redisCatchStorage; |
| 25 | 35 | |
| 36 | + @Autowired | |
| 37 | + private IVideoManagerStorage storager; | |
| 38 | + | |
| 39 | + private final ConcurrentLinkedQueue<Message> taskQueue = new ConcurrentLinkedQueue<>(); | |
| 40 | + | |
| 41 | + @Qualifier("taskExecutor") | |
| 42 | + @Autowired | |
| 43 | + private ThreadPoolTaskExecutor taskExecutor; | |
| 44 | + | |
| 45 | + | |
| 26 | 46 | @Override |
| 27 | 47 | public void onMessage(@NotNull Message message, byte[] bytes) { |
| 28 | - GPSMsgInfo gpsMsgInfo = JSON.parseObject(message.getBody(), GPSMsgInfo.class); | |
| 29 | - redisCatchStorage.updateGpsMsgInfo(gpsMsgInfo); | |
| 48 | + taskQueue.offer(message); | |
| 49 | + if (!taskQueueHandlerRun) { | |
| 50 | + taskQueueHandlerRun = true; | |
| 51 | + taskExecutor.execute(() -> { | |
| 52 | + while (!taskQueue.isEmpty()) { | |
| 53 | + Message msg = taskQueue.poll(); | |
| 54 | + GPSMsgInfo gpsMsgInfo = JSON.parseObject(msg.getBody(), GPSMsgInfo.class); | |
| 55 | + // 只是放入redis缓存起来 | |
| 56 | + redisCatchStorage.updateGpsMsgInfo(gpsMsgInfo); | |
| 57 | + } | |
| 58 | + taskQueueHandlerRun = false; | |
| 59 | + }); | |
| 60 | + } | |
| 61 | + } | |
| 62 | + | |
| 63 | + /** | |
| 64 | + * 定时将经纬度更新到数据库 | |
| 65 | + */ | |
| 66 | + @Scheduled(fixedRate = 2 * 1000) //每2秒执行一次 | |
| 67 | + public void execute(){ | |
| 68 | + List<GPSMsgInfo> gpsMsgInfo = redisCatchStorage.getAllGpsMsgInfo(); | |
| 69 | + if (gpsMsgInfo.size() > 0) { | |
| 70 | + storager.updateStreamGPS(gpsMsgInfo); | |
| 71 | + for (GPSMsgInfo msgInfo : gpsMsgInfo) { | |
| 72 | + msgInfo.setStored(true); | |
| 73 | + redisCatchStorage.updateGpsMsgInfo(msgInfo); | |
| 74 | + } | |
| 75 | + } | |
| 30 | 76 | } |
| 31 | 77 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/service/impl/RedisPushStreamStatusMsgListener.java
0 → 100644
| 1 | +package com.genersoft.iot.vmp.service.impl; | |
| 2 | + | |
| 3 | +import com.alibaba.fastjson.JSON; | |
| 4 | +import com.alibaba.fastjson.JSONObject; | |
| 5 | +import com.genersoft.iot.vmp.common.VideoManagerConstants; | |
| 6 | +import com.genersoft.iot.vmp.conf.DynamicTask; | |
| 7 | +import com.genersoft.iot.vmp.conf.UserSetting; | |
| 8 | +import com.genersoft.iot.vmp.gb28181.bean.GbStream; | |
| 9 | +import com.genersoft.iot.vmp.gb28181.event.EventPublisher; | |
| 10 | +import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent; | |
| 11 | +import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander; | |
| 12 | +import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform; | |
| 13 | +import com.genersoft.iot.vmp.media.zlm.ZLMMediaListManager; | |
| 14 | +import com.genersoft.iot.vmp.media.zlm.dto.MediaItem; | |
| 15 | +import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem; | |
| 16 | +import com.genersoft.iot.vmp.service.IStreamPushService; | |
| 17 | +import com.genersoft.iot.vmp.service.bean.GPSMsgInfo; | |
| 18 | +import com.genersoft.iot.vmp.service.bean.PushStreamStatusChangeFromRedisDto; | |
| 19 | +import com.genersoft.iot.vmp.service.bean.StreamPushItemFromRedis; | |
| 20 | +import com.genersoft.iot.vmp.storager.IRedisCatchStorage; | |
| 21 | +import com.genersoft.iot.vmp.storager.IVideoManagerStorage; | |
| 22 | +import org.slf4j.Logger; | |
| 23 | +import org.slf4j.LoggerFactory; | |
| 24 | +import org.springframework.beans.factory.annotation.Autowired; | |
| 25 | +import org.springframework.beans.factory.annotation.Qualifier; | |
| 26 | +import org.springframework.boot.ApplicationArguments; | |
| 27 | +import org.springframework.boot.ApplicationRunner; | |
| 28 | +import org.springframework.data.redis.connection.Message; | |
| 29 | +import org.springframework.data.redis.connection.MessageListener; | |
| 30 | +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; | |
| 31 | +import org.springframework.stereotype.Component; | |
| 32 | + | |
| 33 | +import java.util.ArrayList; | |
| 34 | +import java.util.List; | |
| 35 | +import java.util.concurrent.ConcurrentLinkedQueue; | |
| 36 | + | |
| 37 | + | |
| 38 | +/** | |
| 39 | + * 接收redis发送的推流设备上线下线通知 | |
| 40 | + * @author lin | |
| 41 | + */ | |
| 42 | +@Component | |
| 43 | +public class RedisPushStreamStatusMsgListener implements MessageListener, ApplicationRunner { | |
| 44 | + | |
| 45 | + private final static Logger logger = LoggerFactory.getLogger(RedisPushStreamStatusMsgListener.class); | |
| 46 | + | |
| 47 | + private boolean taskQueueHandlerRun = false; | |
| 48 | + | |
| 49 | + @Autowired | |
| 50 | + private IRedisCatchStorage redisCatchStorage; | |
| 51 | + | |
| 52 | + @Autowired | |
| 53 | + private IStreamPushService streamPushService; | |
| 54 | + | |
| 55 | + @Autowired | |
| 56 | + private DynamicTask dynamicTask; | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + private final ConcurrentLinkedQueue<Message> taskQueue = new ConcurrentLinkedQueue<>(); | |
| 61 | + | |
| 62 | + @Qualifier("taskExecutor") | |
| 63 | + @Autowired | |
| 64 | + private ThreadPoolTaskExecutor taskExecutor; | |
| 65 | + | |
| 66 | + @Override | |
| 67 | + public void onMessage(Message message, byte[] bytes) { | |
| 68 | + // TODO 增加队列 | |
| 69 | + logger.warn("[REDIS消息-推流设备状态变化]: {}", new String(message.getBody())); | |
| 70 | + taskQueue.offer(message); | |
| 71 | + | |
| 72 | + if (!taskQueueHandlerRun) { | |
| 73 | + taskQueueHandlerRun = true; | |
| 74 | + taskExecutor.execute(() -> { | |
| 75 | + while (!taskQueue.isEmpty()) { | |
| 76 | + Message msg = taskQueue.poll(); | |
| 77 | + PushStreamStatusChangeFromRedisDto statusChangeFromPushStream = JSON.parseObject(msg.getBody(), PushStreamStatusChangeFromRedisDto.class); | |
| 78 | + if (statusChangeFromPushStream == null) { | |
| 79 | + logger.warn("[REDIS消息]推流设备状态变化消息解析失败"); | |
| 80 | + return; | |
| 81 | + } | |
| 82 | + // 取消定时任务 | |
| 83 | + dynamicTask.stop(VideoManagerConstants.VM_MSG_GET_ALL_ONLINE_REQUESTED); | |
| 84 | + if (statusChangeFromPushStream.isSetAllOffline()) { | |
| 85 | + // 所有设备离线 | |
| 86 | + streamPushService.allStreamOffline(); | |
| 87 | + } | |
| 88 | + if (statusChangeFromPushStream.getOfflineStreams() != null | |
| 89 | + && statusChangeFromPushStream.getOfflineStreams().size() > 0) { | |
| 90 | + // 更新部分设备离线 | |
| 91 | + streamPushService.offline(statusChangeFromPushStream.getOfflineStreams()); | |
| 92 | + } | |
| 93 | + if (statusChangeFromPushStream.getOnlineStreams() != null && | |
| 94 | + statusChangeFromPushStream.getOnlineStreams().size() > 0) { | |
| 95 | + // 更新部分设备上线 | |
| 96 | + streamPushService.online(statusChangeFromPushStream.getOnlineStreams()); | |
| 97 | + } | |
| 98 | + } | |
| 99 | + taskQueueHandlerRun = false; | |
| 100 | + }); | |
| 101 | + } | |
| 102 | + } | |
| 103 | + | |
| 104 | + @Override | |
| 105 | + public void run(ApplicationArguments args) throws Exception { | |
| 106 | + // 启动时设置所有推流通道离线,发起查询请求 | |
| 107 | + redisCatchStorage.sendStreamPushRequestedMsgForStatus(); | |
| 108 | + dynamicTask.startDelay(VideoManagerConstants.VM_MSG_GET_ALL_ONLINE_REQUESTED, ()->{ | |
| 109 | + logger.info("[REDIS消息]未收到redis回复推流设备状态,执行推流设备离线"); | |
| 110 | + // 五秒收不到请求就设置通道离线,然后通知上级离线 | |
| 111 | + streamPushService.allStreamOffline(); | |
| 112 | + }, 5000); | |
| 113 | + } | |
| 114 | + | |
| 115 | +} | ... | ... |
src/main/java/com/genersoft/iot/vmp/service/impl/RedisStreamMsgListener.java
| ... | ... | @@ -3,16 +3,12 @@ package com.genersoft.iot.vmp.service.impl; |
| 3 | 3 | import com.alibaba.fastjson.JSON; |
| 4 | 4 | import com.alibaba.fastjson.JSONObject; |
| 5 | 5 | import com.genersoft.iot.vmp.conf.UserSetting; |
| 6 | -import com.genersoft.iot.vmp.gb28181.bean.AlarmChannelMessage; | |
| 7 | -import com.genersoft.iot.vmp.gb28181.bean.Device; | |
| 8 | -import com.genersoft.iot.vmp.gb28181.bean.DeviceAlarm; | |
| 9 | -import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; | |
| 6 | + | |
| 10 | 7 | import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander; |
| 11 | 8 | import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform; |
| 12 | 9 | import com.genersoft.iot.vmp.media.zlm.ZLMMediaListManager; |
| 13 | 10 | import com.genersoft.iot.vmp.media.zlm.dto.MediaItem; |
| 14 | 11 | import com.genersoft.iot.vmp.storager.IVideoManagerStorage; |
| 15 | -import com.genersoft.iot.vmp.utils.DateUtil; | |
| 16 | 12 | import org.slf4j.Logger; |
| 17 | 13 | import org.slf4j.LoggerFactory; |
| 18 | 14 | import org.springframework.beans.factory.annotation.Autowired; |
| ... | ... | @@ -22,6 +18,7 @@ import org.springframework.stereotype.Component; |
| 22 | 18 | |
| 23 | 19 | |
| 24 | 20 | /** |
| 21 | + * 接收其他wvp发送流变化通知 | |
| 25 | 22 | * @author lin |
| 26 | 23 | */ |
| 27 | 24 | @Component |
| ... | ... | @@ -49,7 +46,7 @@ public class RedisStreamMsgListener implements MessageListener { |
| 49 | 46 | |
| 50 | 47 | JSONObject steamMsgJson = JSON.parseObject(message.getBody(), JSONObject.class); |
| 51 | 48 | if (steamMsgJson == null) { |
| 52 | - logger.warn("[REDIS的ALARM通知]消息解析失败"); | |
| 49 | + logger.warn("[收到redis 流变化]消息解析失败"); | |
| 53 | 50 | return; |
| 54 | 51 | } |
| 55 | 52 | String serverId = steamMsgJson.getString("serverId"); |
| ... | ... | @@ -58,7 +55,7 @@ public class RedisStreamMsgListener implements MessageListener { |
| 58 | 55 | // 自己发送的消息忽略即可 |
| 59 | 56 | return; |
| 60 | 57 | } |
| 61 | - logger.info("[REDIS通知] 流变化: {}", new String(message.getBody())); | |
| 58 | + logger.info("[收到redis 流变化]: {}", new String(message.getBody())); | |
| 62 | 59 | String app = steamMsgJson.getString("app"); |
| 63 | 60 | String stream = steamMsgJson.getString("stream"); |
| 64 | 61 | boolean register = steamMsgJson.getBoolean("register"); |
| ... | ... | @@ -75,9 +72,10 @@ public class RedisStreamMsgListener implements MessageListener { |
| 75 | 72 | mediaItem.setOriginType(0); |
| 76 | 73 | mediaItem.setOriginTypeStr("0"); |
| 77 | 74 | mediaItem.setOriginTypeStr("unknown"); |
| 78 | - | |
| 79 | - zlmMediaListManager.addPush(mediaItem); | |
| 80 | - | |
| 81 | - | |
| 75 | + if (register) { | |
| 76 | + zlmMediaListManager.addPush(mediaItem); | |
| 77 | + }else { | |
| 78 | + zlmMediaListManager.removeMedia(app, stream); | |
| 79 | + } | |
| 82 | 80 | } |
| 83 | 81 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/service/impl/StreamProxyServiceImpl.java
| ... | ... | @@ -3,10 +3,10 @@ package com.genersoft.iot.vmp.service.impl; |
| 3 | 3 | import com.alibaba.fastjson.JSONArray; |
| 4 | 4 | import com.alibaba.fastjson.JSONObject; |
| 5 | 5 | import com.genersoft.iot.vmp.common.StreamInfo; |
| 6 | -import com.genersoft.iot.vmp.conf.SipConfig; | |
| 7 | 6 | import com.genersoft.iot.vmp.conf.UserSetting; |
| 8 | 7 | import com.genersoft.iot.vmp.gb28181.bean.GbStream; |
| 9 | 8 | import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; |
| 9 | +import com.genersoft.iot.vmp.gb28181.bean.TreeType; | |
| 10 | 10 | import com.genersoft.iot.vmp.gb28181.event.EventPublisher; |
| 11 | 11 | import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent; |
| 12 | 12 | import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils; |
| ... | ... | @@ -23,14 +23,19 @@ import com.genersoft.iot.vmp.storager.dao.ParentPlatformMapper; |
| 23 | 23 | import com.genersoft.iot.vmp.storager.dao.PlatformGbStreamMapper; |
| 24 | 24 | import com.genersoft.iot.vmp.storager.dao.StreamProxyMapper; |
| 25 | 25 | import com.genersoft.iot.vmp.service.IStreamProxyService; |
| 26 | +import com.genersoft.iot.vmp.utils.DateUtil; | |
| 26 | 27 | import com.genersoft.iot.vmp.vmanager.bean.WVPResult; |
| 27 | 28 | import com.github.pagehelper.PageInfo; |
| 28 | 29 | import org.slf4j.Logger; |
| 29 | 30 | import org.slf4j.LoggerFactory; |
| 30 | 31 | import org.springframework.beans.factory.annotation.Autowired; |
| 32 | +import org.springframework.jdbc.datasource.DataSourceTransactionManager; | |
| 31 | 33 | import org.springframework.stereotype.Service; |
| 34 | +import org.springframework.transaction.TransactionDefinition; | |
| 35 | +import org.springframework.transaction.TransactionStatus; | |
| 32 | 36 | import org.springframework.util.StringUtils; |
| 33 | 37 | |
| 38 | +import java.net.InetAddress; | |
| 34 | 39 | import java.util.*; |
| 35 | 40 | |
| 36 | 41 | /** |
| ... | ... | @@ -48,7 +53,7 @@ public class StreamProxyServiceImpl implements IStreamProxyService { |
| 48 | 53 | private IMediaService mediaService; |
| 49 | 54 | |
| 50 | 55 | @Autowired |
| 51 | - private ZLMRESTfulUtils zlmresTfulUtils;; | |
| 56 | + private ZLMRESTfulUtils zlmresTfulUtils; | |
| 52 | 57 | |
| 53 | 58 | @Autowired |
| 54 | 59 | private StreamProxyMapper streamProxyMapper; |
| ... | ... | @@ -63,9 +68,6 @@ public class StreamProxyServiceImpl implements IStreamProxyService { |
| 63 | 68 | private UserSetting userSetting; |
| 64 | 69 | |
| 65 | 70 | @Autowired |
| 66 | - private SipConfig sipConfig; | |
| 67 | - | |
| 68 | - @Autowired | |
| 69 | 71 | private GbStreamMapper gbStreamMapper; |
| 70 | 72 | |
| 71 | 73 | @Autowired |
| ... | ... | @@ -83,6 +85,12 @@ public class StreamProxyServiceImpl implements IStreamProxyService { |
| 83 | 85 | @Autowired |
| 84 | 86 | private IMediaServerService mediaServerService; |
| 85 | 87 | |
| 88 | + @Autowired | |
| 89 | + DataSourceTransactionManager dataSourceTransactionManager; | |
| 90 | + | |
| 91 | + @Autowired | |
| 92 | + TransactionDefinition transactionDefinition; | |
| 93 | + | |
| 86 | 94 | |
| 87 | 95 | @Override |
| 88 | 96 | public WVPResult<StreamInfo> save(StreamProxyItem param) { |
| ... | ... | @@ -99,6 +107,7 @@ public class StreamProxyServiceImpl implements IStreamProxyService { |
| 99 | 107 | wvpResult.setMsg("保存失败"); |
| 100 | 108 | return wvpResult; |
| 101 | 109 | } |
| 110 | + | |
| 102 | 111 | String dstUrl = String.format("rtmp://%s:%s/%s/%s", "127.0.0.1", mediaInfo.getRtmpPort(), param.getApp(), |
| 103 | 112 | param.getStream() ); |
| 104 | 113 | param.setDst_url(dstUrl); |
| ... | ... | @@ -108,9 +117,9 @@ public class StreamProxyServiceImpl implements IStreamProxyService { |
| 108 | 117 | boolean saveResult; |
| 109 | 118 | // 更新 |
| 110 | 119 | if (videoManagerStorager.queryStreamProxy(param.getApp(), param.getStream()) != null) { |
| 111 | - saveResult = videoManagerStorager.updateStreamProxy(param); | |
| 120 | + saveResult = updateStreamProxy(param); | |
| 112 | 121 | }else { // 新增 |
| 113 | - saveResult = videoManagerStorager.addStreamProxy(param); | |
| 122 | + saveResult = addStreamProxy(param); | |
| 114 | 123 | } |
| 115 | 124 | if (saveResult) { |
| 116 | 125 | result.append("保存成功"); |
| ... | ... | @@ -124,7 +133,7 @@ public class StreamProxyServiceImpl implements IStreamProxyService { |
| 124 | 133 | if (param.isEnable_remove_none_reader()) { |
| 125 | 134 | del(param.getApp(), param.getStream()); |
| 126 | 135 | }else { |
| 127 | - videoManagerStorager.updateStreamProxy(param); | |
| 136 | + updateStreamProxy(param); | |
| 128 | 137 | } |
| 129 | 138 | |
| 130 | 139 | }else { |
| ... | ... | @@ -147,25 +156,79 @@ public class StreamProxyServiceImpl implements IStreamProxyService { |
| 147 | 156 | result.append(", 关联国标平台[ " + param.getPlatformGbId() + " ]失败"); |
| 148 | 157 | } |
| 149 | 158 | } |
| 150 | - if (!StringUtils.isEmpty(param.getGbId())) { | |
| 151 | - // 查找开启了全部直播流共享的上级平台 | |
| 152 | - List<ParentPlatform> parentPlatforms = parentPlatformMapper.selectAllAhareAllLiveStream(); | |
| 153 | - if (parentPlatforms.size() > 0) { | |
| 154 | - for (ParentPlatform parentPlatform : parentPlatforms) { | |
| 155 | - param.setPlatformId(parentPlatform.getServerGBId()); | |
| 156 | - param.setCatalogId(parentPlatform.getCatalogId()); | |
| 157 | - String stream = param.getStream(); | |
| 158 | - StreamProxyItem streamProxyItems = platformGbStreamMapper.selectOne(param.getApp(), stream, parentPlatform.getServerGBId()); | |
| 159 | - if (streamProxyItems == null) { | |
| 160 | - platformGbStreamMapper.add(param); | |
| 161 | - eventPublisher.catalogEventPublishForStream(parentPlatform.getServerGBId(), param, CatalogEvent.ADD); | |
| 159 | + wvpResult.setMsg(result.toString()); | |
| 160 | + return wvpResult; | |
| 161 | + } | |
| 162 | + | |
| 163 | + /** | |
| 164 | + * 新增代理流 | |
| 165 | + * @param streamProxyItem | |
| 166 | + * @return | |
| 167 | + */ | |
| 168 | + private boolean addStreamProxy(StreamProxyItem streamProxyItem) { | |
| 169 | + TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition); | |
| 170 | + boolean result = false; | |
| 171 | + streamProxyItem.setStreamType("proxy"); | |
| 172 | + streamProxyItem.setStatus(true); | |
| 173 | + String now = DateUtil.getNow(); | |
| 174 | + streamProxyItem.setCreateTime(now); | |
| 175 | + try { | |
| 176 | + if (streamProxyMapper.add(streamProxyItem) > 0) { | |
| 177 | + if (!StringUtils.isEmpty(streamProxyItem.getGbId())) { | |
| 178 | + if (gbStreamMapper.add(streamProxyItem) < 0) { | |
| 179 | + //事务回滚 | |
| 180 | + dataSourceTransactionManager.rollback(transactionStatus); | |
| 181 | + return false; | |
| 162 | 182 | } |
| 163 | 183 | } |
| 184 | + }else { | |
| 185 | + //事务回滚 | |
| 186 | + dataSourceTransactionManager.rollback(transactionStatus); | |
| 187 | + return false; | |
| 164 | 188 | } |
| 189 | + result = true; | |
| 190 | + dataSourceTransactionManager.commit(transactionStatus); //手动提交 | |
| 191 | + }catch (Exception e) { | |
| 192 | + logger.error("向数据库添加流代理失败:", e); | |
| 193 | + dataSourceTransactionManager.rollback(transactionStatus); | |
| 165 | 194 | } |
| 166 | 195 | |
| 167 | - wvpResult.setMsg(result.toString()); | |
| 168 | - return wvpResult; | |
| 196 | + | |
| 197 | + return result; | |
| 198 | + } | |
| 199 | + | |
| 200 | + /** | |
| 201 | + * 更新代理流 | |
| 202 | + * @param streamProxyItem | |
| 203 | + * @return | |
| 204 | + */ | |
| 205 | + @Override | |
| 206 | + public boolean updateStreamProxy(StreamProxyItem streamProxyItem) { | |
| 207 | + TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition); | |
| 208 | + boolean result = false; | |
| 209 | + streamProxyItem.setStreamType("proxy"); | |
| 210 | + try { | |
| 211 | + if (streamProxyMapper.update(streamProxyItem) > 0) { | |
| 212 | + if (!StringUtils.isEmpty(streamProxyItem.getGbId())) { | |
| 213 | + if (gbStreamMapper.updateByAppAndStream(streamProxyItem) == 0) { | |
| 214 | + //事务回滚 | |
| 215 | + dataSourceTransactionManager.rollback(transactionStatus); | |
| 216 | + return false; | |
| 217 | + } | |
| 218 | + } | |
| 219 | + } else { | |
| 220 | + //事务回滚 | |
| 221 | + dataSourceTransactionManager.rollback(transactionStatus); | |
| 222 | + return false; | |
| 223 | + } | |
| 224 | + | |
| 225 | + dataSourceTransactionManager.commit(transactionStatus); //手动提交 | |
| 226 | + result = true; | |
| 227 | + }catch (Exception e) { | |
| 228 | + e.printStackTrace(); | |
| 229 | + dataSourceTransactionManager.rollback(transactionStatus); | |
| 230 | + } | |
| 231 | + return result; | |
| 169 | 232 | } |
| 170 | 233 | |
| 171 | 234 | @Override |
| ... | ... | @@ -239,7 +302,7 @@ public class StreamProxyServiceImpl implements IStreamProxyService { |
| 239 | 302 | if (jsonObject.getInteger("code") == 0) { |
| 240 | 303 | result = true; |
| 241 | 304 | streamProxy.setEnable(true); |
| 242 | - videoManagerStorager.updateStreamProxy(streamProxy); | |
| 305 | + updateStreamProxy(streamProxy); | |
| 243 | 306 | } |
| 244 | 307 | } |
| 245 | 308 | return result; |
| ... | ... | @@ -253,7 +316,7 @@ public class StreamProxyServiceImpl implements IStreamProxyService { |
| 253 | 316 | JSONObject jsonObject = removeStreamProxyFromZlm(streamProxyDto); |
| 254 | 317 | if (jsonObject != null && jsonObject.getInteger("code") == 0) { |
| 255 | 318 | streamProxyDto.setEnable(false); |
| 256 | - result = videoManagerStorager.updateStreamProxy(streamProxyDto); | |
| 319 | + result = updateStreamProxy(streamProxyDto); | |
| 257 | 320 | } |
| 258 | 321 | } |
| 259 | 322 | return result; | ... | ... |
src/main/java/com/genersoft/iot/vmp/service/impl/StreamPushServiceImpl.java
| ... | ... | @@ -4,6 +4,7 @@ import com.alibaba.fastjson.JSON; |
| 4 | 4 | import com.alibaba.fastjson.JSONArray; |
| 5 | 5 | import com.alibaba.fastjson.JSONObject; |
| 6 | 6 | import com.alibaba.fastjson.TypeReference; |
| 7 | +import com.genersoft.iot.vmp.conf.MediaConfig; | |
| 7 | 8 | import com.genersoft.iot.vmp.conf.UserSetting; |
| 8 | 9 | import com.genersoft.iot.vmp.gb28181.bean.*; |
| 9 | 10 | import com.genersoft.iot.vmp.gb28181.event.EventPublisher; |
| ... | ... | @@ -13,6 +14,7 @@ import com.genersoft.iot.vmp.media.zlm.dto.*; |
| 13 | 14 | import com.genersoft.iot.vmp.service.IGbStreamService; |
| 14 | 15 | import com.genersoft.iot.vmp.service.IMediaServerService; |
| 15 | 16 | import com.genersoft.iot.vmp.service.IStreamPushService; |
| 17 | +import com.genersoft.iot.vmp.service.bean.StreamPushItemFromRedis; | |
| 16 | 18 | import com.genersoft.iot.vmp.storager.IRedisCatchStorage; |
| 17 | 19 | import com.genersoft.iot.vmp.storager.dao.*; |
| 18 | 20 | import com.genersoft.iot.vmp.utils.DateUtil; |
| ... | ... | @@ -21,7 +23,10 @@ import com.github.pagehelper.PageInfo; |
| 21 | 23 | import org.slf4j.Logger; |
| 22 | 24 | import org.slf4j.LoggerFactory; |
| 23 | 25 | import org.springframework.beans.factory.annotation.Autowired; |
| 26 | +import org.springframework.jdbc.datasource.DataSourceTransactionManager; | |
| 24 | 27 | import org.springframework.stereotype.Service; |
| 28 | +import org.springframework.transaction.TransactionDefinition; | |
| 29 | +import org.springframework.transaction.TransactionStatus; | |
| 25 | 30 | import org.springframework.util.StringUtils; |
| 26 | 31 | |
| 27 | 32 | import java.util.*; |
| ... | ... | @@ -68,6 +73,16 @@ public class StreamPushServiceImpl implements IStreamPushService { |
| 68 | 73 | @Autowired |
| 69 | 74 | private IMediaServerService mediaServerService; |
| 70 | 75 | |
| 76 | + @Autowired | |
| 77 | + DataSourceTransactionManager dataSourceTransactionManager; | |
| 78 | + | |
| 79 | + @Autowired | |
| 80 | + TransactionDefinition transactionDefinition; | |
| 81 | + | |
| 82 | + @Autowired | |
| 83 | + private MediaConfig mediaConfig; | |
| 84 | + | |
| 85 | + | |
| 71 | 86 | @Override |
| 72 | 87 | public List<StreamPushItem> handleJSON(String jsonData, MediaServerItem mediaServerItem) { |
| 73 | 88 | if (jsonData == null) { |
| ... | ... | @@ -132,30 +147,9 @@ public class StreamPushServiceImpl implements IStreamPushService { |
| 132 | 147 | stream.setStreamType("push"); |
| 133 | 148 | stream.setStatus(true); |
| 134 | 149 | stream.setCreateTime(DateUtil.getNow()); |
| 150 | + stream.setStreamType("push"); | |
| 151 | + stream.setMediaServerId(mediaConfig.getId()); | |
| 135 | 152 | int add = gbStreamMapper.add(stream); |
| 136 | - | |
| 137 | - // 查找开启了全部直播流共享的上级平台 | |
| 138 | - List<ParentPlatform> parentPlatforms = parentPlatformMapper.selectAllAhareAllLiveStream(); | |
| 139 | - if (parentPlatforms.size() > 0) { | |
| 140 | - for (ParentPlatform parentPlatform : parentPlatforms) { | |
| 141 | - stream.setCatalogId(parentPlatform.getCatalogId()); | |
| 142 | - stream.setPlatformId(parentPlatform.getServerGBId()); | |
| 143 | - String streamId = stream.getStream(); | |
| 144 | - StreamProxyItem streamProxyItem = platformGbStreamMapper.selectOne(stream.getApp(), streamId, parentPlatform.getServerGBId()); | |
| 145 | - if (streamProxyItem == null) { | |
| 146 | - platformGbStreamMapper.add(stream); | |
| 147 | - eventPublisher.catalogEventPublishForStream(parentPlatform.getServerGBId(), stream, CatalogEvent.ADD); | |
| 148 | - }else { | |
| 149 | - if (!streamProxyItem.getGbId().equals(stream.getGbId())) { | |
| 150 | - // 此流使用另一个国标Id已经与该平台关联,移除此记录 | |
| 151 | - platformGbStreamMapper.delByAppAndStreamAndPlatform(stream.getApp(), streamId, parentPlatform.getServerGBId()); | |
| 152 | - platformGbStreamMapper.add(stream); | |
| 153 | - eventPublisher.catalogEventPublishForStream(parentPlatform.getServerGBId(), stream, CatalogEvent.ADD); | |
| 154 | - } | |
| 155 | - } | |
| 156 | - } | |
| 157 | - } | |
| 158 | - | |
| 159 | 153 | return add > 0; |
| 160 | 154 | } |
| 161 | 155 | |
| ... | ... | @@ -181,7 +175,6 @@ public class StreamPushServiceImpl implements IStreamPushService { |
| 181 | 175 | |
| 182 | 176 | @Override |
| 183 | 177 | public StreamPushItem getPush(String app, String streamId) { |
| 184 | - | |
| 185 | 178 | return streamPushMapper.selectOne(app, streamId); |
| 186 | 179 | } |
| 187 | 180 | |
| ... | ... | @@ -345,31 +338,6 @@ public class StreamPushServiceImpl implements IStreamPushService { |
| 345 | 338 | public void batchAdd(List<StreamPushItem> streamPushItems) { |
| 346 | 339 | streamPushMapper.addAll(streamPushItems); |
| 347 | 340 | gbStreamMapper.batchAdd(streamPushItems); |
| 348 | - // 查找开启了全部直播流共享的上级平台 | |
| 349 | - List<ParentPlatform> parentPlatforms = parentPlatformMapper.selectAllAhareAllLiveStream(); | |
| 350 | - if (parentPlatforms.size() > 0) { | |
| 351 | - for (StreamPushItem stream : streamPushItems) { | |
| 352 | - for (ParentPlatform parentPlatform : parentPlatforms) { | |
| 353 | - stream.setCatalogId(parentPlatform.getCatalogId()); | |
| 354 | - stream.setPlatformId(parentPlatform.getServerGBId()); | |
| 355 | - String streamId = stream.getStream(); | |
| 356 | - StreamProxyItem streamProxyItem = platformGbStreamMapper.selectOne(stream.getApp(), streamId, parentPlatform.getServerGBId()); | |
| 357 | - if (streamProxyItem == null) { | |
| 358 | - platformGbStreamMapper.add(stream); | |
| 359 | - eventPublisher.catalogEventPublishForStream(parentPlatform.getServerGBId(), stream, CatalogEvent.ADD); | |
| 360 | - }else { | |
| 361 | - if (!streamProxyItem.getGbId().equals(stream.getGbId())) { | |
| 362 | - // 此流使用另一个国标Id已经与该平台关联,移除此记录 | |
| 363 | - platformGbStreamMapper.delByAppAndStreamAndPlatform(stream.getApp(), streamId, parentPlatform.getServerGBId()); | |
| 364 | - platformGbStreamMapper.add(stream); | |
| 365 | - eventPublisher.catalogEventPublishForStream(parentPlatform.getServerGBId(), stream, CatalogEvent.ADD); | |
| 366 | - stream.setGbId(streamProxyItem.getGbId()); | |
| 367 | - eventPublisher.catalogEventPublishForStream(parentPlatform.getServerGBId(), stream, CatalogEvent.DEL); | |
| 368 | - } | |
| 369 | - } | |
| 370 | - } | |
| 371 | - } | |
| 372 | - } | |
| 373 | 341 | } |
| 374 | 342 | |
| 375 | 343 | @Override |
| ... | ... | @@ -481,4 +449,58 @@ public class StreamPushServiceImpl implements IStreamPushService { |
| 481 | 449 | } |
| 482 | 450 | return true; |
| 483 | 451 | } |
| 452 | + | |
| 453 | + @Override | |
| 454 | + public void allStreamOffline() { | |
| 455 | + List<GbStream> onlinePushers = streamPushMapper.getOnlinePusherForGb(); | |
| 456 | + if (onlinePushers.size() == 0) { | |
| 457 | + return; | |
| 458 | + } | |
| 459 | + streamPushMapper.setAllStreamOffline(); | |
| 460 | + | |
| 461 | + // 发送通知 | |
| 462 | + eventPublisher.catalogEventPublishForStream(null, onlinePushers, CatalogEvent.OFF); | |
| 463 | + } | |
| 464 | + | |
| 465 | + @Override | |
| 466 | + public void offline(List<StreamPushItemFromRedis> offlineStreams) { | |
| 467 | + // 更新部分设备离线 | |
| 468 | + List<GbStream> onlinePushers = streamPushMapper.getOnlinePusherForGbInList(offlineStreams); | |
| 469 | + streamPushMapper.offline(offlineStreams); | |
| 470 | + // 发送通知 | |
| 471 | + eventPublisher.catalogEventPublishForStream(null, onlinePushers, CatalogEvent.OFF); | |
| 472 | + } | |
| 473 | + | |
| 474 | + @Override | |
| 475 | + public void online(List<StreamPushItemFromRedis> onlineStreams) { | |
| 476 | + // 更新部分设备上线streamPushService | |
| 477 | + List<GbStream> onlinePushers = streamPushMapper.getOfflinePusherForGbInList(onlineStreams); | |
| 478 | + streamPushMapper.online(onlineStreams); | |
| 479 | + // 发送通知 | |
| 480 | + eventPublisher.catalogEventPublishForStream(null, onlinePushers, CatalogEvent.ON); | |
| 481 | + } | |
| 482 | + | |
| 483 | + @Override | |
| 484 | + public boolean add(StreamPushItem stream) { | |
| 485 | + stream.setUpdateTime(DateUtil.getNow()); | |
| 486 | + stream.setCreateTime(DateUtil.getNow()); | |
| 487 | + stream.setServerId(userSetting.getServerId()); | |
| 488 | + | |
| 489 | + // 放在事务内执行 | |
| 490 | + boolean result = false; | |
| 491 | + TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition); | |
| 492 | + try { | |
| 493 | + int addStreamResult = streamPushMapper.add(stream); | |
| 494 | + if (!StringUtils.isEmpty(stream.getGbId())) { | |
| 495 | + stream.setStreamType("push"); | |
| 496 | + gbStreamMapper.add(stream); | |
| 497 | + } | |
| 498 | + dataSourceTransactionManager.commit(transactionStatus); | |
| 499 | + result = true; | |
| 500 | + }catch (Exception e) { | |
| 501 | + logger.error("批量移除流与平台的关系时错误", e); | |
| 502 | + dataSourceTransactionManager.rollback(transactionStatus); | |
| 503 | + } | |
| 504 | + return result; | |
| 505 | + } | |
| 484 | 506 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/service/impl/StreamPushUploadFileHandler.java
| ... | ... | @@ -14,38 +14,60 @@ import java.util.*; |
| 14 | 14 | |
| 15 | 15 | public class StreamPushUploadFileHandler extends AnalysisEventListener<StreamPushExcelDto> { |
| 16 | 16 | |
| 17 | - // 错误数据的回调,用于将错误数据发送给页面 | |
| 17 | + /** | |
| 18 | + * 错误数据的回调,用于将错误数据发送给页面 | |
| 19 | + */ | |
| 18 | 20 | private ErrorDataHandler errorDataHandler; |
| 19 | 21 | |
| 20 | - // 推流的业务类用于存储数据 | |
| 22 | + /** | |
| 23 | + * 推流的业务类用于存储数据 | |
| 24 | + */ | |
| 21 | 25 | private IStreamPushService pushService; |
| 22 | 26 | |
| 23 | - // 默认流媒体节点ID | |
| 27 | + /** | |
| 28 | + * 默认流媒体节点ID | |
| 29 | + */ | |
| 24 | 30 | private String defaultMediaServerId; |
| 25 | 31 | |
| 26 | - // 用于存储不加过滤的所有数据 | |
| 32 | + /** | |
| 33 | + * 用于存储不加过滤的所有数据 | |
| 34 | + */ | |
| 27 | 35 | private List<StreamPushItem> streamPushItems = new ArrayList<>(); |
| 28 | 36 | |
| 29 | - // 用于存储更具APP+Stream过滤后的数据,可以直接存入stream_push表与gb_stream表 | |
| 37 | + /** | |
| 38 | + * 用于存储更具APP+Stream过滤后的数据,可以直接存入stream_push表与gb_stream表 | |
| 39 | + */ | |
| 30 | 40 | private Map<String,StreamPushItem> streamPushItemForSave = new HashMap<>(); |
| 31 | 41 | |
| 32 | - // 用于存储按照APP+Stream为KEY, 平台ID+目录Id 为value的数据,用于存储到gb_stream表后获取app+Stream对应的平台与目录信息,然后存入关联表 | |
| 42 | + /** | |
| 43 | + * 用于存储按照APP+Stream为KEY, 平台ID+目录Id 为value的数据,用于存储到gb_stream表后获取app+Stream对应的平台与目录信息,然后存入关联表 | |
| 44 | + */ | |
| 33 | 45 | private Map<String, List<String[]>> streamPushItemsForPlatform = new HashMap<>(); |
| 34 | 46 | |
| 35 | - // 用于判断文件是否存在重复的app+Stream+平台ID | |
| 47 | + /** | |
| 48 | + * 用于判断文件是否存在重复的app+Stream+平台ID | |
| 49 | + */ | |
| 36 | 50 | private Set<String> streamPushStreamSet = new HashSet<>(); |
| 37 | 51 | |
| 38 | - // 用于存储APP+Stream->国标ID 的数据结构, 数据一一对应,全局判断APP+Stream->国标ID是否存在不对应 | |
| 52 | + /** | |
| 53 | + * 用于存储APP+Stream->国标ID 的数据结构, 数据一一对应,全局判断APP+Stream->国标ID是否存在不对应 | |
| 54 | + */ | |
| 39 | 55 | private BiMap<String,String> gBMap = HashBiMap.create(); |
| 40 | 56 | |
| 41 | - // 记录错误的APP+Stream | |
| 57 | + /** | |
| 58 | + * 记录错误的APP+Stream | |
| 59 | + */ | |
| 42 | 60 | private List<String> errorStreamList = new ArrayList<>(); |
| 43 | 61 | |
| 44 | 62 | |
| 45 | - // 记录错误的国标ID | |
| 63 | + /** | |
| 64 | + * 记录错误的国标ID | |
| 65 | + */ | |
| 46 | 66 | private List<String> errorGBList = new ArrayList<>(); |
| 47 | 67 | |
| 48 | - // 读取数量计数器 | |
| 68 | + /** | |
| 69 | + * 读取数量计数器 | |
| 70 | + */ | |
| 49 | 71 | private int loadedSize = 0; |
| 50 | 72 | |
| 51 | 73 | public StreamPushUploadFileHandler(IStreamPushService pushService, String defaultMediaServerId, ErrorDataHandler errorDataHandler) { | ... | ... |
src/main/java/com/genersoft/iot/vmp/service/impl/UserServiceImpl.java
| ... | ... | @@ -3,6 +3,8 @@ package com.genersoft.iot.vmp.service.impl; |
| 3 | 3 | import com.genersoft.iot.vmp.service.IUserService; |
| 4 | 4 | import com.genersoft.iot.vmp.storager.dao.UserMapper; |
| 5 | 5 | import com.genersoft.iot.vmp.storager.dao.dto.User; |
| 6 | +import com.github.pagehelper.PageHelper; | |
| 7 | +import com.github.pagehelper.PageInfo; | |
| 6 | 8 | import org.springframework.beans.factory.annotation.Autowired; |
| 7 | 9 | import org.springframework.stereotype.Service; |
| 8 | 10 | import org.springframework.util.StringUtils; |
| ... | ... | @@ -11,7 +13,7 @@ import java.util.List; |
| 11 | 13 | |
| 12 | 14 | @Service |
| 13 | 15 | public class UserServiceImpl implements IUserService { |
| 14 | - | |
| 16 | + | |
| 15 | 17 | @Autowired |
| 16 | 18 | private UserMapper userMapper; |
| 17 | 19 | |
| ... | ... | @@ -64,4 +66,16 @@ public class UserServiceImpl implements IUserService { |
| 64 | 66 | return userMapper.checkPushAuthorityByCallIdAndSign(callId, sign).size() > 0; |
| 65 | 67 | } |
| 66 | 68 | } |
| 69 | + | |
| 70 | + @Override | |
| 71 | + public PageInfo<User> getUsers(int page, int count) { | |
| 72 | + PageHelper.startPage(page, count); | |
| 73 | + List<User> users = userMapper.getUsers(); | |
| 74 | + return new PageInfo<>(users); | |
| 75 | + } | |
| 76 | + | |
| 77 | + @Override | |
| 78 | + public int changePushKey(int id, String pushKey) { | |
| 79 | + return userMapper.changePushKey(id,pushKey); | |
| 80 | + } | |
| 67 | 81 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java
src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorage.java
| ... | ... | @@ -27,22 +27,6 @@ public interface IVideoManagerStorage { |
| 27 | 27 | public boolean exists(String deviceId); |
| 28 | 28 | |
| 29 | 29 | /** |
| 30 | - * 添加设备通道 | |
| 31 | - * | |
| 32 | - * @param deviceId 设备id | |
| 33 | - * @param channel 通道 | |
| 34 | - */ | |
| 35 | - public void updateChannel(String deviceId, DeviceChannel channel); | |
| 36 | - | |
| 37 | - /** | |
| 38 | - * 批量添加设备通道 | |
| 39 | - * | |
| 40 | - * @param deviceId 设备id | |
| 41 | - * @param channels 多个通道 | |
| 42 | - */ | |
| 43 | - public int updateChannels(String deviceId, List<DeviceChannel> channels); | |
| 44 | - | |
| 45 | - /** | |
| 46 | 30 | * 开始播放 |
| 47 | 31 | * @param deviceId 设备id |
| 48 | 32 | * @param channelId 通道ID |
| ... | ... | @@ -224,13 +208,6 @@ public interface IVideoManagerStorage { |
| 224 | 208 | List<DeviceChannelInPlatform> queryChannelListInParentPlatform(String platformId); |
| 225 | 209 | |
| 226 | 210 | |
| 227 | - /** | |
| 228 | - * 更新上级平台的通道信息 | |
| 229 | - * @param platformId | |
| 230 | - * @param channelReduces | |
| 231 | - * @return | |
| 232 | - */ | |
| 233 | - int updateChannelForGB(String platformId, List<ChannelReduce> channelReduces, String catalogId); | |
| 234 | 211 | |
| 235 | 212 | /** |
| 236 | 213 | * 移除上级平台的通道信息 |
| ... | ... | @@ -277,20 +254,6 @@ public interface IVideoManagerStorage { |
| 277 | 254 | public int clearMobilePositionsByDeviceId(String deviceId); |
| 278 | 255 | |
| 279 | 256 | /** |
| 280 | - * 新增代理流 | |
| 281 | - * @param streamProxyDto | |
| 282 | - * @return | |
| 283 | - */ | |
| 284 | - public boolean addStreamProxy(StreamProxyItem streamProxyDto); | |
| 285 | - | |
| 286 | - /** | |
| 287 | - * 更新代理流 | |
| 288 | - * @param streamProxyDto | |
| 289 | - * @return | |
| 290 | - */ | |
| 291 | - public boolean updateStreamProxy(StreamProxyItem streamProxyDto); | |
| 292 | - | |
| 293 | - /** | |
| 294 | 257 | * 移除代理流 |
| 295 | 258 | * @param app |
| 296 | 259 | * @param stream |
| ... | ... | @@ -334,19 +297,7 @@ public interface IVideoManagerStorage { |
| 334 | 297 | * @param platformId |
| 335 | 298 | * @return |
| 336 | 299 | */ |
| 337 | - List<GbStream> queryGbStreamListInPlatform(String platformId); | |
| 338 | - | |
| 339 | - /** | |
| 340 | - * 批量更新推流列表 | |
| 341 | - * @param streamPushItems | |
| 342 | - */ | |
| 343 | - void updateMediaList(List<StreamPushItem> streamPushItems); | |
| 344 | - | |
| 345 | - /** | |
| 346 | - * 更新单个推流 | |
| 347 | - * @param streamPushItem | |
| 348 | - */ | |
| 349 | - void updateMedia(StreamPushItem streamPushItem); | |
| 300 | + List<DeviceChannel> queryGbStreamListInPlatform(String platformId); | |
| 350 | 301 | |
| 351 | 302 | /** |
| 352 | 303 | * 移除单个推流 |
| ... | ... | @@ -355,21 +306,6 @@ public interface IVideoManagerStorage { |
| 355 | 306 | */ |
| 356 | 307 | int removeMedia(String app, String stream); |
| 357 | 308 | |
| 358 | - | |
| 359 | - /** | |
| 360 | - * 获取但个推流 | |
| 361 | - * @param app | |
| 362 | - * @param stream | |
| 363 | - * @return | |
| 364 | - */ | |
| 365 | - StreamPushItem getMedia(String app, String stream); | |
| 366 | - | |
| 367 | - | |
| 368 | - /** | |
| 369 | - * 清空推流列表 | |
| 370 | - */ | |
| 371 | - void clearMediaList(); | |
| 372 | - | |
| 373 | 309 | /** |
| 374 | 310 | * 设置流离线 |
| 375 | 311 | */ |
| ... | ... | @@ -445,7 +381,7 @@ public interface IVideoManagerStorage { |
| 445 | 381 | |
| 446 | 382 | int setDefaultCatalog(String platformId, String catalogId); |
| 447 | 383 | |
| 448 | - List<PlatformCatalog> queryCatalogInPlatform(String serverGBId); | |
| 384 | + List<DeviceChannel> queryCatalogInPlatform(String serverGBId); | |
| 449 | 385 | |
| 450 | 386 | int delRelation(PlatformCatalog platformCatalog); |
| 451 | 387 | |
| ... | ... | @@ -466,4 +402,8 @@ public interface IVideoManagerStorage { |
| 466 | 402 | List<ChannelSourceInfo> getChannelSource(String platformId, String gbId); |
| 467 | 403 | |
| 468 | 404 | void updateChannelPosition(DeviceChannel deviceChannel); |
| 405 | + | |
| 406 | + void cleanContentForPlatform(String serverGBId); | |
| 407 | + | |
| 408 | + List<DeviceChannel> queryChannelWithCatalog(String serverGBId); | |
| 469 | 409 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceChannelMapper.java
| ... | ... | @@ -140,6 +140,9 @@ public interface DeviceChannelMapper { |
| 140 | 140 | @Update(value = {"UPDATE device_channel SET status=0 WHERE deviceId=#{deviceId} AND channelId=#{channelId}"}) |
| 141 | 141 | void offline(String deviceId, String channelId); |
| 142 | 142 | |
| 143 | + @Update(value = {"UPDATE device_channel SET status=0 WHERE deviceId=#{deviceId}"}) | |
| 144 | + void offlineByDeviceId(String deviceId); | |
| 145 | + | |
| 143 | 146 | @Update(value = {"UPDATE device_channel SET status=1 WHERE deviceId=#{deviceId} AND channelId=#{channelId}"}) |
| 144 | 147 | void online(String deviceId, String channelId); |
| 145 | 148 | |
| ... | ... | @@ -329,5 +332,13 @@ public interface DeviceChannelMapper { |
| 329 | 332 | @Select("select * from device_channel where deviceId=#{deviceId} and SUBSTRING(channelId, 11, 3)=#{typeCode}") |
| 330 | 333 | List<DeviceChannel> getBusinessGroups(String deviceId, String typeCode); |
| 331 | 334 | |
| 332 | - | |
| 335 | + @Select("select dc.id, dc.channelId, dc.deviceId, dc.name, dc.manufacture,dc.model,dc.owner, pc.civilCode,dc.block, " + | |
| 336 | + " dc.address, '0' as parental,'0' as channelType, pc.id as parentId, dc.safetyWay, dc.registerWay,dc.certNum, dc.certifiable, " + | |
| 337 | + " dc.errCode,dc.endTime, dc.secrecy, dc.ipAddress, dc.port, dc.PTZType, dc.password, dc.status, " + | |
| 338 | + " dc.longitudeWgs84 as longitude, dc.latitudeWgs84 as latitude, pc.businessGroupId " + | |
| 339 | + " from device_channel dc" + | |
| 340 | + " left join platform_gb_channel pgc on dc.id = pgc.deviceChannelId" + | |
| 341 | + " left join platform_catalog pc on pgc.catalogId = pc.id and pgc.platformId = pc.platformId" + | |
| 342 | + " where pgc.platformId=#{serverGBId}") | |
| 343 | + List<DeviceChannel> queryChannelWithCatalog(String serverGBId); | |
| 333 | 344 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/storager/dao/GbStreamMapper.java
| 1 | 1 | package com.genersoft.iot.vmp.storager.dao; |
| 2 | 2 | |
| 3 | +import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; | |
| 3 | 4 | import com.genersoft.iot.vmp.gb28181.bean.GbStream; |
| 4 | 5 | import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem; |
| 5 | 6 | import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem; |
| ... | ... | @@ -15,10 +16,10 @@ import java.util.List; |
| 15 | 16 | public interface GbStreamMapper { |
| 16 | 17 | |
| 17 | 18 | @Insert("REPLACE INTO gb_stream (app, stream, gbId, name, " + |
| 18 | - "longitude, latitude, streamType, mediaServerId, status, createTime) VALUES" + | |
| 19 | + "longitude, latitude, streamType, mediaServerId, createTime) VALUES" + | |
| 19 | 20 | "('${app}', '${stream}', '${gbId}', '${name}', " + |
| 20 | 21 | "'${longitude}', '${latitude}', '${streamType}', " + |
| 21 | - "'${mediaServerId}', ${status}, '${createTime}')") | |
| 22 | + "'${mediaServerId}', '${createTime}')") | |
| 22 | 23 | @Options(useGeneratedKeys = true, keyProperty = "gbStreamId", keyColumn = "gbStreamId") |
| 23 | 24 | int add(GbStream gbStream); |
| 24 | 25 | |
| ... | ... | @@ -30,8 +31,7 @@ public interface GbStreamMapper { |
| 30 | 31 | "streamType=#{streamType}," + |
| 31 | 32 | "longitude=#{longitude}, " + |
| 32 | 33 | "latitude=#{latitude}," + |
| 33 | - "mediaServerId=#{mediaServerId}," + | |
| 34 | - "status=${status} " + | |
| 34 | + "mediaServerId=#{mediaServerId}" + | |
| 35 | 35 | "WHERE app=#{app} AND stream=#{stream}") |
| 36 | 36 | int updateByAppAndStream(GbStream gbStream); |
| 37 | 37 | |
| ... | ... | @@ -43,8 +43,7 @@ public interface GbStreamMapper { |
| 43 | 43 | "streamType=#{streamType}," + |
| 44 | 44 | "longitude=#{longitude}, " + |
| 45 | 45 | "latitude=#{latitude}," + |
| 46 | - "mediaServerId=#{mediaServerId}," + | |
| 47 | - "status=${status} " + | |
| 46 | + "mediaServerId=#{mediaServerId}" + | |
| 48 | 47 | "WHERE gbStreamId=#{gbStreamId}") |
| 49 | 48 | int update(GbStream gbStream); |
| 50 | 49 | |
| ... | ... | @@ -60,12 +59,10 @@ public interface GbStreamMapper { |
| 60 | 59 | " <if test='catalogId == null'> AND gs.gbStreamId not in" + |
| 61 | 60 | "(select pgs.gbStreamId from platform_gb_stream pgs where pgs.platformId = #{platformId}) </if> " + |
| 62 | 61 | " <if test='query != null'> AND (gs.app LIKE '%${query}%' OR gs.stream LIKE '%${query}%' OR gs.gbId LIKE '%${query}%' OR gs.name LIKE '%${query}%')</if> " + |
| 63 | - " <if test='pushing == true' > AND gs.status=1</if>" + | |
| 64 | - " <if test='pushing == false' > AND gs.status=0</if>" + | |
| 65 | 62 | " <if test='mediaServerId != null' > AND gs.mediaServerId=#{mediaServerId} </if>" + |
| 66 | 63 | " order by gs.gbStreamId asc " + |
| 67 | 64 | "</script>") |
| 68 | - List<GbStream> selectAll(String platformId, String catalogId, String query, Boolean pushing, String mediaServerId); | |
| 65 | + List<GbStream> selectAll(String platformId, String catalogId, String query, String mediaServerId); | |
| 69 | 66 | |
| 70 | 67 | @Select("SELECT * FROM gb_stream WHERE app=#{app} AND stream=#{stream}") |
| 71 | 68 | GbStream selectOne(String app, String stream); |
| ... | ... | @@ -78,10 +75,18 @@ public interface GbStreamMapper { |
| 78 | 75 | "WHERE gs.gbId = '${gbId}' AND pgs.platformId = '${platformId}'") |
| 79 | 76 | GbStream queryStreamInPlatform(String platformId, String gbId); |
| 80 | 77 | |
| 81 | - @Select("SELECT gs.*, pgs.platformId as platformId, pgs.catalogId as catalogId FROM gb_stream gs " + | |
| 82 | - "LEFT JOIN platform_gb_stream pgs ON gs.gbStreamId = pgs.gbStreamId " + | |
| 83 | - "WHERE pgs.platformId = #{platformId}") | |
| 84 | - List<GbStream> queryGbStreamListInPlatform(String platformId); | |
| 78 | + @Select("select gt.gbId as channelId, gt.name, 'wvp-pro' as manufacture, st.status, gt.longitude, gt.latitude, pc.id as parentId," + | |
| 79 | + " '1' as registerWay, pc.civilCode, 'live' as model, 'wvp-pro' as owner, '0' as parental,'0' as secrecy" + | |
| 80 | + " from gb_stream gt " + | |
| 81 | + " left join (" + | |
| 82 | + " select sp.status, sp.app, sp.stream from stream_push sp" + | |
| 83 | + " union all" + | |
| 84 | + " select spxy.status, spxy.app, spxy.stream from stream_proxy spxy" + | |
| 85 | + " ) st on st.app = gt.app and st.stream = gt.stream" + | |
| 86 | + " left join platform_gb_stream pgs on gt.gbStreamId = pgs.gbStreamId" + | |
| 87 | + " left join platform_catalog pc on pgs.catalogId = pc.id and pgs.platformId = pc.platformId" + | |
| 88 | + " where pgs.platformId=#{platformId}") | |
| 89 | + List<DeviceChannel> queryGbStreamListInPlatform(String platformId); | |
| 85 | 90 | |
| 86 | 91 | |
| 87 | 92 | @Select("SELECT gs.* FROM gb_stream gs LEFT JOIN platform_gb_stream pgs " + |
| ... | ... | @@ -110,12 +115,12 @@ public interface GbStreamMapper { |
| 110 | 115 | @Insert("<script> " + |
| 111 | 116 | "INSERT IGNORE into gb_stream " + |
| 112 | 117 | "(app, stream, gbId, name, " + |
| 113 | - "longitude, latitude, streamType, mediaServerId, status, createTime)" + | |
| 118 | + "longitude, latitude, streamType, mediaServerId, createTime)" + | |
| 114 | 119 | "values " + |
| 115 | 120 | "<foreach collection='subList' index='index' item='item' separator=','> " + |
| 116 | 121 | "('${item.app}', '${item.stream}', '${item.gbId}', '${item.name}', " + |
| 117 | 122 | "'${item.longitude}', '${item.latitude}', '${item.streamType}', " + |
| 118 | - "'${item.mediaServerId}', ${item.status}, '${item.createTime}') "+ | |
| 123 | + "'${item.mediaServerId}', '${item.createTime}') "+ | |
| 119 | 124 | "</foreach> " + |
| 120 | 125 | "</script>") |
| 121 | 126 | @Options(useGeneratedKeys = true, keyProperty = "gbStreamId", keyColumn = "gbStreamId") |
| ... | ... | @@ -138,4 +143,9 @@ public interface GbStreamMapper { |
| 138 | 143 | "</foreach>" + |
| 139 | 144 | "</script>") |
| 140 | 145 | List<GbStream> selectAllForAppAndStream(List<StreamPushItem> streamPushItems); |
| 146 | + | |
| 147 | + @Update("UPDATE gb_stream " + | |
| 148 | + "SET mediaServerId=#{mediaServerId}" + | |
| 149 | + "WHERE app=#{app} AND stream=#{stream}") | |
| 150 | + void updateMediaServer(String app, String stream, String mediaServerId); | |
| 141 | 151 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/storager/dao/ParentPlatformMapper.java
| ... | ... | @@ -16,10 +16,10 @@ public interface ParentPlatformMapper { |
| 16 | 16 | |
| 17 | 17 | @Insert("INSERT INTO parent_platform (enable, name, serverGBId, serverGBDomain, serverIP, serverPort, deviceGBId, deviceIp, " + |
| 18 | 18 | " devicePort, username, password, expires, keepTimeout, transport, characterSet, ptz, rtcp, " + |
| 19 | - " status, shareAllLiveStream, startOfflinePush, catalogId, administrativeDivision, catalogGroup, createTime, updateTime) " + | |
| 19 | + " status, startOfflinePush, catalogId, administrativeDivision, catalogGroup, createTime, updateTime, treeType) " + | |
| 20 | 20 | " VALUES (${enable}, '${name}', '${serverGBId}', '${serverGBDomain}', '${serverIP}', ${serverPort}, '${deviceGBId}', '${deviceIp}', " + |
| 21 | 21 | " '${devicePort}', '${username}', '${password}', '${expires}', '${keepTimeout}', '${transport}', '${characterSet}', ${ptz}, ${rtcp}, " + |
| 22 | - " ${status}, ${shareAllLiveStream}, ${startOfflinePush}, #{catalogId}, #{administrativeDivision}, #{catalogGroup}, #{createTime}, #{updateTime})") | |
| 22 | + " ${status}, ${startOfflinePush}, #{catalogId}, #{administrativeDivision}, #{catalogGroup}, #{createTime}, #{updateTime}, #{treeType})") | |
| 23 | 23 | int addParentPlatform(ParentPlatform parentPlatform); |
| 24 | 24 | |
| 25 | 25 | @Update("UPDATE parent_platform " + |
| ... | ... | @@ -41,12 +41,12 @@ public interface ParentPlatformMapper { |
| 41 | 41 | "ptz=#{ptz}, " + |
| 42 | 42 | "rtcp=#{rtcp}, " + |
| 43 | 43 | "status=#{status}, " + |
| 44 | - "shareAllLiveStream=#{shareAllLiveStream}, " + | |
| 45 | 44 | "startOfflinePush=${startOfflinePush}, " + |
| 46 | 45 | "catalogGroup=#{catalogGroup}, " + |
| 47 | 46 | "administrativeDivision=#{administrativeDivision}, " + |
| 48 | 47 | "createTime=#{createTime}, " + |
| 49 | 48 | "updateTime=#{updateTime}, " + |
| 49 | + "treeType=#{treeType}, " + | |
| 50 | 50 | "catalogId=#{catalogId} " + |
| 51 | 51 | "WHERE id=#{id}") |
| 52 | 52 | int updateParentPlatform(ParentPlatform parentPlatform); |
| ... | ... | @@ -83,9 +83,6 @@ public interface ParentPlatformMapper { |
| 83 | 83 | @Update("UPDATE parent_platform SET status=#{online} WHERE serverGBId=#{platformGbID}" ) |
| 84 | 84 | int updateParentPlatformStatus(String platformGbID, boolean online); |
| 85 | 85 | |
| 86 | - @Select("SELECT * FROM parent_platform WHERE shareAllLiveStream=true") | |
| 87 | - List<ParentPlatform> selectAllAhareAllLiveStream(); | |
| 88 | - | |
| 89 | 86 | @Update(value = {" <script>" + |
| 90 | 87 | "UPDATE parent_platform " + |
| 91 | 88 | "SET catalogId=#{catalogId}, updateTime=#{updateTime}" + | ... | ... |
src/main/java/com/genersoft/iot/vmp/storager/dao/PlatformCatalogMapper.java
| 1 | 1 | package com.genersoft.iot.vmp.storager.dao; |
| 2 | 2 | |
| 3 | +import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; | |
| 3 | 4 | import com.genersoft.iot.vmp.gb28181.bean.GbStream; |
| 4 | 5 | import com.genersoft.iot.vmp.gb28181.bean.PlatformCatalog; |
| 5 | 6 | import com.genersoft.iot.vmp.gb28181.bean.PlatformGbStream; |
| ... | ... | @@ -14,8 +15,8 @@ import java.util.List; |
| 14 | 15 | @Repository |
| 15 | 16 | public interface PlatformCatalogMapper { |
| 16 | 17 | |
| 17 | - @Insert("INSERT INTO platform_catalog (id, name, platformId, parentId) VALUES" + | |
| 18 | - "(#{id}, #{name}, #{platformId}, #{parentId})") | |
| 18 | + @Insert("INSERT INTO platform_catalog (id, name, platformId, parentId, civilCode, businessGroupId) VALUES" + | |
| 19 | + "(#{id}, #{name}, #{platformId}, #{parentId}, #{civilCode}, #{businessGroupId})") | |
| 19 | 20 | int add(PlatformCatalog platformCatalog); |
| 20 | 21 | |
| 21 | 22 | @Delete("DELETE FROM platform_catalog WHERE id=#{id}") |
| ... | ... | @@ -44,4 +45,12 @@ public interface PlatformCatalogMapper { |
| 44 | 45 | |
| 45 | 46 | @Select("SELECT pc.* FROM platform_catalog pc WHERE pc.id = (SELECT pp.catalogId from parent_platform pp WHERE pp.serverGBId=#{platformId})") |
| 46 | 47 | PlatformCatalog selectDefaultByPlatFormId(String platformId); |
| 48 | + | |
| 49 | + | |
| 50 | + @Select("SELECT pc.* FROM platform_catalog pc WHERE pc.id = #{id}") | |
| 51 | + PlatformCatalog selectParentCatalog(String id); | |
| 52 | + | |
| 53 | + @Select("SELECT pc.id as channelId, pc.name, pc.civilCode, pc.businessGroupId,'1' as parental, pc.parentId " + | |
| 54 | + " FROM platform_catalog pc WHERE pc.platformId=#{platformId}") | |
| 55 | + List<DeviceChannel> queryCatalogInPlatform(String platformId); | |
| 47 | 56 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/storager/dao/StreamPushMapper.java
| ... | ... | @@ -2,6 +2,7 @@ package com.genersoft.iot.vmp.storager.dao; |
| 2 | 2 | |
| 3 | 3 | import com.genersoft.iot.vmp.gb28181.bean.GbStream; |
| 4 | 4 | import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem; |
| 5 | +import com.genersoft.iot.vmp.service.bean.StreamPushItemFromRedis; | |
| 5 | 6 | import org.apache.ibatis.annotations.*; |
| 6 | 7 | // import org.omg.PortableInterceptor.INACTIVE; |
| 7 | 8 | import org.springframework.stereotype.Repository; |
| ... | ... | @@ -14,9 +15,10 @@ import java.util.List; |
| 14 | 15 | public interface StreamPushMapper { |
| 15 | 16 | |
| 16 | 17 | @Insert("INSERT INTO stream_push (app, stream, totalReaderCount, originType, originTypeStr, " + |
| 17 | - "pushTime, aliveSecond, mediaServerId, serverId, updateTime, createTime) VALUES" + | |
| 18 | + "pushTime, aliveSecond, mediaServerId, serverId, updateTime, createTime, pushIng, self) VALUES" + | |
| 18 | 19 | "('${app}', '${stream}', '${totalReaderCount}', '${originType}', '${originTypeStr}', " + |
| 19 | - "'${pushTime}', '${aliveSecond}', '${mediaServerId}' , '${serverId}' , '${updateTime}' , '${createTime}' )") | |
| 20 | + "'${pushTime}', '${aliveSecond}', '${mediaServerId}' , '${serverId}' , '${updateTime}' , '${createTime}', " + | |
| 21 | + "${pushIng}, ${self} )") | |
| 20 | 22 | int add(StreamPushItem streamPushItem); |
| 21 | 23 | |
| 22 | 24 | |
| ... | ... | @@ -29,6 +31,8 @@ public interface StreamPushMapper { |
| 29 | 31 | "<if test=\"originTypeStr != null\">, originTypeStr='${originTypeStr}'</if>" + |
| 30 | 32 | "<if test=\"pushTime != null\">, pushTime='${pushTime}'</if>" + |
| 31 | 33 | "<if test=\"aliveSecond != null\">, aliveSecond='${aliveSecond}'</if>" + |
| 34 | + "<if test=\"pushIng != null\">, pushIng=${pushIng}</if>" + | |
| 35 | + "<if test=\"self != null\">, self=${self}</if>" + | |
| 32 | 36 | "WHERE app=#{app} AND stream=#{stream}"+ |
| 33 | 37 | " </script>"}) |
| 34 | 38 | int update(StreamPushItem streamPushItem); |
| ... | ... | @@ -87,10 +91,11 @@ public interface StreamPushMapper { |
| 87 | 91 | |
| 88 | 92 | @Insert("<script>" + |
| 89 | 93 | "Insert IGNORE INTO stream_push (app, stream, totalReaderCount, originType, originTypeStr, " + |
| 90 | - "createTime, aliveSecond, mediaServerId) " + | |
| 94 | + "createTime, aliveSecond, mediaServerId, status, pushIng) " + | |
| 91 | 95 | "VALUES <foreach collection='streamPushItems' item='item' index='index' separator=','>" + |
| 92 | 96 | "( '${item.app}', '${item.stream}', '${item.totalReaderCount}', #{item.originType}, " + |
| 93 | - "'${item.originTypeStr}',#{item.createTime}, #{item.aliveSecond}, '${item.mediaServerId}' )" + | |
| 97 | + "'${item.originTypeStr}',#{item.createTime}, #{item.aliveSecond}, '${item.mediaServerId}', ${item.status} ," + | |
| 98 | + " ${item.pushIng} )" + | |
| 94 | 99 | " </foreach>" + |
| 95 | 100 | "</script>") |
| 96 | 101 | @Options(useGeneratedKeys = true, keyProperty = "id", keyColumn = "id") |
| ... | ... | @@ -114,7 +119,53 @@ public interface StreamPushMapper { |
| 114 | 119 | int updateStatus(String app, String stream, boolean status); |
| 115 | 120 | |
| 116 | 121 | @Update("UPDATE stream_push " + |
| 122 | + "SET pushIng=${pushIng} " + | |
| 123 | + "WHERE app=#{app} AND stream=#{stream}") | |
| 124 | + int updatePushStatus(String app, String stream, boolean pushIng); | |
| 125 | + | |
| 126 | + @Update("UPDATE stream_push " + | |
| 117 | 127 | "SET status=#{status} " + |
| 118 | 128 | "WHERE mediaServerId=#{mediaServerId}") |
| 119 | 129 | void updateStatusByMediaServerId(String mediaServerId, boolean status); |
| 130 | + | |
| 131 | + | |
| 132 | + @Select("<script> "+ | |
| 133 | + "SELECT gs.* FROM stream_push sp left join gb_stream gs on sp.app = gs.app AND sp.stream = gs.stream " + | |
| 134 | + "where sp.status = 1 and (gs.app, gs.stream) in (" + | |
| 135 | + "<foreach collection='offlineStreams' item='item' separator=','>" + | |
| 136 | + "(#{item.app}, #{item.stream}) " + | |
| 137 | + "</foreach>" + | |
| 138 | + ")</script>") | |
| 139 | + List<GbStream> getOnlinePusherForGbInList(List<StreamPushItemFromRedis> offlineStreams); | |
| 140 | + | |
| 141 | + @Update("<script> "+ | |
| 142 | + "UPDATE stream_push SET status=0 where (app, stream) in (" + | |
| 143 | + "<foreach collection='offlineStreams' item='item' separator=','>" + | |
| 144 | + "(#{item.app}, #{item.stream}) " + | |
| 145 | + "</foreach>" + | |
| 146 | + ")</script>") | |
| 147 | + void offline(List<StreamPushItemFromRedis> offlineStreams); | |
| 148 | + | |
| 149 | + @Select("<script> "+ | |
| 150 | + "SELECT * FROM stream_push sp left join gb_stream gs on sp.app = gs.app AND sp.stream = gs.stream " + | |
| 151 | + "where sp.status = 0 and (gs.app, gs.stream) in (" + | |
| 152 | + "<foreach collection='onlineStreams' item='item' separator=','>" + | |
| 153 | + "(#{item.app}, #{item.stream}) " + | |
| 154 | + "</foreach>" + | |
| 155 | + ") </script>") | |
| 156 | + List<GbStream> getOfflinePusherForGbInList(List<StreamPushItemFromRedis> onlineStreams); | |
| 157 | + | |
| 158 | + @Update("<script> "+ | |
| 159 | + "UPDATE stream_push SET status=1 where (app, stream) in (" + | |
| 160 | + "<foreach collection='onlineStreams' item='item' separator=','>" + | |
| 161 | + "(#{item.app}, #{item.stream}) " + | |
| 162 | + "</foreach>" + | |
| 163 | + ")</script>") | |
| 164 | + void online(List<StreamPushItemFromRedis> onlineStreams); | |
| 165 | + | |
| 166 | + @Select("SELECT gs.* FROM stream_push sp left join gb_stream gs on sp.app = gs.app AND sp.stream = gs.stream where sp.status = 1") | |
| 167 | + List<GbStream> getOnlinePusherForGb(); | |
| 168 | + | |
| 169 | + @Update("UPDATE stream_push SET status=0") | |
| 170 | + void setAllStreamOffline(); | |
| 120 | 171 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/storager/dao/UserMapper.java
| ... | ... | @@ -55,4 +55,11 @@ public interface UserMapper { |
| 55 | 55 | |
| 56 | 56 | @Select("select * from user where md5(pushKey) = '${sign}'") |
| 57 | 57 | List<User> checkPushAuthorityByCallId(String sign); |
| 58 | + | |
| 59 | + @Select("select u.id, u.username,u.pushKey,u.roleId, r.id as roleID, r.name as roleName, r.authority as roleAuthority , r.createTime as roleCreateTime , r.updateTime as roleUpdateTime FROM user u join user_role r on u.roleId=r.id") | |
| 60 | + @ResultMap(value="roleMap") | |
| 61 | + List<User> getUsers(); | |
| 62 | + | |
| 63 | + @Update("update user set pushKey=#{pushKey} where id=#{id}") | |
| 64 | + int changePushKey(int id, String pushKey); | |
| 58 | 65 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java
| ... | ... | @@ -479,13 +479,18 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage { |
| 479 | 479 | @Override |
| 480 | 480 | public void sendStreamChangeMsg(String type, JSONObject jsonObject) { |
| 481 | 481 | String key = VideoManagerConstants.WVP_MSG_STREAM_CHANGE_PREFIX + type; |
| 482 | - logger.debug("[redis 流变化事件] {}: {}", key, jsonObject.toString()); | |
| 482 | + logger.info("[redis 流变化事件] {}: {}", key, jsonObject.toString()); | |
| 483 | 483 | redis.convertAndSend(key, jsonObject); |
| 484 | 484 | } |
| 485 | 485 | |
| 486 | 486 | @Override |
| 487 | 487 | public void addStream(MediaServerItem mediaServerItem, String type, String app, String streamId, MediaItem mediaItem) { |
| 488 | + // 查找是否使用了callID | |
| 489 | + StreamAuthorityInfo streamAuthorityInfo = getStreamAuthorityInfo(app, streamId); | |
| 488 | 490 | String key = VideoManagerConstants.WVP_SERVER_STREAM_PREFIX + userSetting.getServerId() + "_" + type + "_" + app + "_" + streamId + "_" + mediaServerItem.getId(); |
| 491 | + if (streamAuthorityInfo != null) { | |
| 492 | + mediaItem.setCallId(streamAuthorityInfo.getCallId()); | |
| 493 | + } | |
| 489 | 494 | redis.set(key, mediaItem); |
| 490 | 495 | } |
| 491 | 496 | |
| ... | ... | @@ -683,21 +688,21 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage { |
| 683 | 688 | @Override |
| 684 | 689 | public void sendMobilePositionMsg(JSONObject jsonObject) { |
| 685 | 690 | String key = VideoManagerConstants.VM_MSG_SUBSCRIBE_MOBILE_POSITION; |
| 686 | - logger.info("[redis 移动位置订阅通知] {}: {}", key, jsonObject.toString()); | |
| 691 | + logger.info("[redis发送通知]移动位置 {}: {}", key, jsonObject.toString()); | |
| 687 | 692 | redis.convertAndSend(key, jsonObject); |
| 688 | 693 | } |
| 689 | 694 | |
| 690 | 695 | @Override |
| 691 | 696 | public void sendStreamPushRequestedMsg(MessageForPushChannel msg) { |
| 692 | 697 | String key = VideoManagerConstants.VM_MSG_STREAM_PUSH_REQUESTED; |
| 693 | - logger.info("[redis 推流被请求通知] {}: {}/{}", key, msg.getApp(), msg.getStream()); | |
| 698 | + logger.info("[redis发送通知]推流被请求 {}: {}/{}", key, msg.getApp(), msg.getStream()); | |
| 694 | 699 | redis.convertAndSend(key, (JSONObject)JSON.toJSON(msg)); |
| 695 | 700 | } |
| 696 | 701 | |
| 697 | 702 | @Override |
| 698 | 703 | public void sendAlarmMsg(AlarmChannelMessage msg) { |
| 699 | 704 | String key = VideoManagerConstants.VM_MSG_SUBSCRIBE_ALARM; |
| 700 | - logger.info("[redis 报警通知] {}: {}", key, JSON.toJSON(msg)); | |
| 705 | + logger.info("[redis发送通知] 报警{}: {}", key, JSON.toJSON(msg)); | |
| 701 | 706 | redis.convertAndSend(key, (JSONObject)JSON.toJSON(msg)); |
| 702 | 707 | } |
| 703 | 708 | |
| ... | ... | @@ -707,4 +712,12 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage { |
| 707 | 712 | } |
| 708 | 713 | |
| 709 | 714 | |
| 715 | + @Override | |
| 716 | + public void sendStreamPushRequestedMsgForStatus() { | |
| 717 | + String key = VideoManagerConstants.VM_MSG_GET_ALL_ONLINE_REQUESTED; | |
| 718 | + logger.info("[redis通知]获取所有推流设备的状态"); | |
| 719 | + JSONObject jsonObject = new JSONObject(); | |
| 720 | + jsonObject.put(key, key); | |
| 721 | + redis.convertAndSend(key, jsonObject); | |
| 722 | + } | |
| 710 | 723 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStorageImpl.java
| ... | ... | @@ -48,13 +48,14 @@ public class VideoManagerStorageImpl implements IVideoManagerStorage { |
| 48 | 48 | @Autowired |
| 49 | 49 | SipConfig sipConfig; |
| 50 | 50 | |
| 51 | - @Autowired | |
| 52 | - DataSourceTransactionManager dataSourceTransactionManager; | |
| 53 | 51 | |
| 54 | 52 | @Autowired |
| 55 | 53 | TransactionDefinition transactionDefinition; |
| 56 | 54 | |
| 57 | 55 | @Autowired |
| 56 | + DataSourceTransactionManager dataSourceTransactionManager; | |
| 57 | + | |
| 58 | + @Autowired | |
| 58 | 59 | private DeviceMapper deviceMapper; |
| 59 | 60 | |
| 60 | 61 | @Autowired |
| ... | ... | @@ -105,96 +106,6 @@ public class VideoManagerStorageImpl implements IVideoManagerStorage { |
| 105 | 106 | } |
| 106 | 107 | |
| 107 | 108 | @Override |
| 108 | - public synchronized void updateChannel(String deviceId, DeviceChannel channel) { | |
| 109 | - String channelId = channel.getChannelId(); | |
| 110 | - channel.setDeviceId(deviceId); | |
| 111 | - StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(deviceId, channelId); | |
| 112 | - if (streamInfo != null) { | |
| 113 | - channel.setStreamId(streamInfo.getStream()); | |
| 114 | - } | |
| 115 | - String now = DateUtil.getNow(); | |
| 116 | - channel.setUpdateTime(now); | |
| 117 | - DeviceChannel deviceChannel = deviceChannelMapper.queryChannel(deviceId, channelId); | |
| 118 | - if (deviceChannel == null) { | |
| 119 | - channel.setCreateTime(now); | |
| 120 | - deviceChannelMapper.add(channel); | |
| 121 | - }else { | |
| 122 | - deviceChannelMapper.update(channel); | |
| 123 | - } | |
| 124 | - deviceChannelMapper.updateChannelSubCount(deviceId,channel.getParentId()); | |
| 125 | - } | |
| 126 | - | |
| 127 | - @Override | |
| 128 | - public int updateChannels(String deviceId, List<DeviceChannel> channels) { | |
| 129 | - List<DeviceChannel> addChannels = new ArrayList<>(); | |
| 130 | - List<DeviceChannel> updateChannels = new ArrayList<>(); | |
| 131 | - HashMap<String, DeviceChannel> channelsInStore = new HashMap<>(); | |
| 132 | - if (channels != null && channels.size() > 0) { | |
| 133 | - List<DeviceChannel> channelList = deviceChannelMapper.queryChannels(deviceId, null, null, null, null); | |
| 134 | - if (channelList.size() == 0) { | |
| 135 | - for (DeviceChannel channel : channels) { | |
| 136 | - channel.setDeviceId(deviceId); | |
| 137 | - StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(deviceId, channel.getChannelId()); | |
| 138 | - if (streamInfo != null) { | |
| 139 | - channel.setStreamId(streamInfo.getStream()); | |
| 140 | - } | |
| 141 | - String now = DateUtil.getNow(); | |
| 142 | - channel.setUpdateTime(now); | |
| 143 | - channel.setCreateTime(now); | |
| 144 | - addChannels.add(channel); | |
| 145 | - } | |
| 146 | - }else { | |
| 147 | - for (DeviceChannel deviceChannel : channelList) { | |
| 148 | - channelsInStore.put(deviceChannel.getChannelId(), deviceChannel); | |
| 149 | - } | |
| 150 | - for (DeviceChannel channel : channels) { | |
| 151 | - channel.setDeviceId(deviceId); | |
| 152 | - StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(deviceId, channel.getChannelId()); | |
| 153 | - if (streamInfo != null) { | |
| 154 | - channel.setStreamId(streamInfo.getStream()); | |
| 155 | - } | |
| 156 | - String now = DateUtil.getNow(); | |
| 157 | - channel.setUpdateTime(now); | |
| 158 | - if (channelsInStore.get(channel.getChannelId()) != null) { | |
| 159 | - updateChannels.add(channel); | |
| 160 | - }else { | |
| 161 | - addChannels.add(channel); | |
| 162 | - channel.setCreateTime(now); | |
| 163 | - } | |
| 164 | - } | |
| 165 | - } | |
| 166 | - int limitCount = 300; | |
| 167 | - if (addChannels.size() > 0) { | |
| 168 | - if (addChannels.size() > limitCount) { | |
| 169 | - for (int i = 0; i < addChannels.size(); i += limitCount) { | |
| 170 | - int toIndex = i + limitCount; | |
| 171 | - if (i + limitCount > addChannels.size()) { | |
| 172 | - toIndex = addChannels.size(); | |
| 173 | - } | |
| 174 | - deviceChannelMapper.batchAdd(addChannels.subList(i, toIndex)); | |
| 175 | - } | |
| 176 | - }else { | |
| 177 | - deviceChannelMapper.batchAdd(addChannels); | |
| 178 | - } | |
| 179 | - } | |
| 180 | - if (updateChannels.size() > 0) { | |
| 181 | - if (updateChannels.size() > limitCount) { | |
| 182 | - for (int i = 0; i < updateChannels.size(); i += limitCount) { | |
| 183 | - int toIndex = i + limitCount; | |
| 184 | - if (i + limitCount > updateChannels.size()) { | |
| 185 | - toIndex = updateChannels.size(); | |
| 186 | - } | |
| 187 | - deviceChannelMapper.batchUpdate(updateChannels.subList(i, toIndex)); | |
| 188 | - } | |
| 189 | - }else { | |
| 190 | - deviceChannelMapper.batchUpdate(updateChannels); | |
| 191 | - } | |
| 192 | - } | |
| 193 | - } | |
| 194 | - return addChannels.size() + updateChannels.size(); | |
| 195 | - } | |
| 196 | - | |
| 197 | - @Override | |
| 198 | 109 | public boolean resetChannels(String deviceId, List<DeviceChannel> deviceChannelList) { |
| 199 | 110 | if (CollectionUtils.isEmpty(deviceChannelList)) { |
| 200 | 111 | return false; |
| ... | ... | @@ -532,20 +443,6 @@ public class VideoManagerStorageImpl implements IVideoManagerStorage { |
| 532 | 443 | // 更新缓存 |
| 533 | 444 | parentPlatformCatch.setParentPlatform(parentPlatform); |
| 534 | 445 | redisCatchStorage.updatePlatformCatchInfo(parentPlatformCatch); |
| 535 | - if (parentPlatform.isEnable()) { | |
| 536 | - // 共享所有视频流,需要将现有视频流添加到此平台 | |
| 537 | - List<GbStream> gbStreams = gbStreamMapper.queryStreamNotInPlatform(); | |
| 538 | - if (gbStreams.size() > 0) { | |
| 539 | - for (GbStream gbStream : gbStreams) { | |
| 540 | - gbStream.setCatalogId(parentPlatform.getCatalogId()); | |
| 541 | - } | |
| 542 | - if (parentPlatform.isShareAllLiveStream()) { | |
| 543 | - gbStreamService.addPlatformInfo(gbStreams, parentPlatform.getServerGBId(), parentPlatform.getCatalogId()); | |
| 544 | - }else { | |
| 545 | - gbStreamService.delPlatformInfo(parentPlatform.getServerGBId(), gbStreams); | |
| 546 | - } | |
| 547 | - } | |
| 548 | - } | |
| 549 | 446 | |
| 550 | 447 | return result > 0; |
| 551 | 448 | } |
| ... | ... | @@ -596,36 +493,6 @@ public class VideoManagerStorageImpl implements IVideoManagerStorage { |
| 596 | 493 | return deviceChannelMapper.queryChannelByPlatformId(platformId); |
| 597 | 494 | } |
| 598 | 495 | |
| 599 | - @Override | |
| 600 | - public int updateChannelForGB(String platformId, List<ChannelReduce> channelReduces, String catalogId) { | |
| 601 | - | |
| 602 | - Map<Integer, ChannelReduce> deviceAndChannels = new HashMap<>(); | |
| 603 | - for (ChannelReduce channelReduce : channelReduces) { | |
| 604 | - channelReduce.setCatalogId(catalogId); | |
| 605 | - deviceAndChannels.put(channelReduce.getId(), channelReduce); | |
| 606 | - } | |
| 607 | - List<Integer> deviceAndChannelList = new ArrayList<>(deviceAndChannels.keySet()); | |
| 608 | - // 查询当前已经存在的 | |
| 609 | - List<Integer> channelIds = platformChannelMapper.findChannelRelatedPlatform(platformId, channelReduces); | |
| 610 | - if (deviceAndChannelList != null) { | |
| 611 | - deviceAndChannelList.removeAll(channelIds); | |
| 612 | - } | |
| 613 | - for (Integer channelId : channelIds) { | |
| 614 | - deviceAndChannels.remove(channelId); | |
| 615 | - } | |
| 616 | - List<ChannelReduce> channelReducesToAdd = new ArrayList<>(deviceAndChannels.values()); | |
| 617 | - // 对剩下的数据进行存储 | |
| 618 | - int result = 0; | |
| 619 | - if (channelReducesToAdd.size() > 0) { | |
| 620 | - result = platformChannelMapper.addChannels(platformId, channelReducesToAdd); | |
| 621 | - // TODO 后续给平台增加控制开关以控制是否响应目录订阅 | |
| 622 | - List<DeviceChannel> deviceChannelList = getDeviceChannelListByChannelReduceList(channelReducesToAdd, catalogId); | |
| 623 | - eventPublisher.catalogEventPublish(platformId, deviceChannelList, CatalogEvent.ADD); | |
| 624 | - } | |
| 625 | - | |
| 626 | - return result; | |
| 627 | - } | |
| 628 | - | |
| 629 | 496 | |
| 630 | 497 | @Override |
| 631 | 498 | public int delChannelForGB(String platformId, List<ChannelReduce> channelReduces) { |
| ... | ... | @@ -701,77 +568,6 @@ public class VideoManagerStorageImpl implements IVideoManagerStorage { |
| 701 | 568 | return deviceMobilePositionMapper.clearMobilePositionsByDeviceId(deviceId); |
| 702 | 569 | } |
| 703 | 570 | |
| 704 | - /** | |
| 705 | - * 新增代理流 | |
| 706 | - * @param streamProxyItem | |
| 707 | - * @return | |
| 708 | - */ | |
| 709 | - @Override | |
| 710 | - public boolean addStreamProxy(StreamProxyItem streamProxyItem) { | |
| 711 | - TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition); | |
| 712 | - boolean result = false; | |
| 713 | - streamProxyItem.setStreamType("proxy"); | |
| 714 | - streamProxyItem.setStatus(true); | |
| 715 | - String now = DateUtil.getNow(); | |
| 716 | - streamProxyItem.setCreateTime(now); | |
| 717 | - try { | |
| 718 | - if (streamProxyMapper.add(streamProxyItem) > 0) { | |
| 719 | - if (!StringUtils.isEmpty(streamProxyItem.getGbId())) { | |
| 720 | - if (gbStreamMapper.add(streamProxyItem) < 0) { | |
| 721 | - //事务回滚 | |
| 722 | - dataSourceTransactionManager.rollback(transactionStatus); | |
| 723 | - return false; | |
| 724 | - } | |
| 725 | - } | |
| 726 | - }else { | |
| 727 | - //事务回滚 | |
| 728 | - dataSourceTransactionManager.rollback(transactionStatus); | |
| 729 | - return false; | |
| 730 | - } | |
| 731 | - result = true; | |
| 732 | - dataSourceTransactionManager.commit(transactionStatus); //手动提交 | |
| 733 | - }catch (Exception e) { | |
| 734 | - logger.error("向数据库添加流代理失败:", e); | |
| 735 | - dataSourceTransactionManager.rollback(transactionStatus); | |
| 736 | - } | |
| 737 | - | |
| 738 | - | |
| 739 | - return result; | |
| 740 | - } | |
| 741 | - | |
| 742 | - /** | |
| 743 | - * 更新代理流 | |
| 744 | - * @param streamProxyItem | |
| 745 | - * @return | |
| 746 | - */ | |
| 747 | - @Override | |
| 748 | - public boolean updateStreamProxy(StreamProxyItem streamProxyItem) { | |
| 749 | - TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition); | |
| 750 | - boolean result = false; | |
| 751 | - streamProxyItem.setStreamType("proxy"); | |
| 752 | - try { | |
| 753 | - if (streamProxyMapper.update(streamProxyItem) > 0) { | |
| 754 | - if (!StringUtils.isEmpty(streamProxyItem.getGbId())) { | |
| 755 | - if (gbStreamMapper.updateByAppAndStream(streamProxyItem) == 0) { | |
| 756 | - //事务回滚 | |
| 757 | - dataSourceTransactionManager.rollback(transactionStatus); | |
| 758 | - return false; | |
| 759 | - } | |
| 760 | - } | |
| 761 | - } else { | |
| 762 | - //事务回滚 | |
| 763 | - dataSourceTransactionManager.rollback(transactionStatus); | |
| 764 | - return false; | |
| 765 | - } | |
| 766 | - | |
| 767 | - dataSourceTransactionManager.commit(transactionStatus); //手动提交 | |
| 768 | - result = true; | |
| 769 | - }catch (Exception e) { | |
| 770 | - e.printStackTrace(); | |
| 771 | - dataSourceTransactionManager.rollback(transactionStatus); | |
| 772 | - } | |
| 773 | - return result; | |
| 774 | - } | |
| 775 | 571 | |
| 776 | 572 | /** |
| 777 | 573 | * 移除代理流 |
| ... | ... | @@ -824,7 +620,7 @@ public class VideoManagerStorageImpl implements IVideoManagerStorage { |
| 824 | 620 | * @return |
| 825 | 621 | */ |
| 826 | 622 | @Override |
| 827 | - public List<GbStream> queryGbStreamListInPlatform(String platformId) { | |
| 623 | + public List<DeviceChannel> queryGbStreamListInPlatform(String platformId) { | |
| 828 | 624 | return gbStreamMapper.queryGbStreamListInPlatform(platformId); |
| 829 | 625 | } |
| 830 | 626 | |
| ... | ... | @@ -840,83 +636,30 @@ public class VideoManagerStorageImpl implements IVideoManagerStorage { |
| 840 | 636 | } |
| 841 | 637 | |
| 842 | 638 | @Override |
| 843 | - public void updateMediaList(List<StreamPushItem> streamPushItems) { | |
| 844 | - if (streamPushItems == null || streamPushItems.size() == 0) { | |
| 845 | - return; | |
| 846 | - } | |
| 847 | - logger.info("updateMediaList: " + streamPushItems.size()); | |
| 848 | - streamPushMapper.addAll(streamPushItems); | |
| 849 | - // TODO 待优化 | |
| 850 | - for (int i = 0; i < streamPushItems.size(); i++) { | |
| 851 | - int onlineResult = mediaOnline(streamPushItems.get(i).getApp(), streamPushItems.get(i).getStream()); | |
| 852 | - if (onlineResult > 0) { | |
| 853 | - // 发送上线通知 | |
| 854 | - eventPublisher.catalogEventPublishForStream(null, streamPushItems.get(i), CatalogEvent.ON); | |
| 855 | - } | |
| 856 | - } | |
| 857 | - } | |
| 858 | - | |
| 859 | - | |
| 860 | - | |
| 861 | - @Override | |
| 862 | - public void updateMedia(StreamPushItem streamPushItem) { | |
| 863 | - streamPushMapper.del(streamPushItem.getApp(), streamPushItem.getStream()); | |
| 864 | - streamPushMapper.add(streamPushItem); | |
| 865 | - mediaOffline(streamPushItem.getApp(), streamPushItem.getStream()); | |
| 866 | - | |
| 867 | - if(!StringUtils.isEmpty(streamPushItem.getGbId() )){ | |
| 868 | - // 查找开启了全部直播流共享的上级平台 | |
| 869 | - List<ParentPlatform> parentPlatforms = parentPlatformMapper.selectAllAhareAllLiveStream(); | |
| 870 | - if (parentPlatforms.size() > 0) { | |
| 871 | - for (ParentPlatform parentPlatform : parentPlatforms) { | |
| 872 | - StreamProxyItem streamProxyItem = platformGbStreamMapper.selectOne(streamPushItem.getApp(), streamPushItem.getStream(), | |
| 873 | - parentPlatform.getServerGBId()); | |
| 874 | - if (streamProxyItem == null) { | |
| 875 | - streamPushItem.setCatalogId(parentPlatform.getCatalogId()); | |
| 876 | - streamPushItem.setPlatformId(parentPlatform.getServerGBId()); | |
| 877 | - platformGbStreamMapper.add(streamPushItem); | |
| 878 | - eventPublisher.catalogEventPublishForStream(parentPlatform.getServerGBId(), streamPushItem, CatalogEvent.ADD); | |
| 879 | - } | |
| 880 | - } | |
| 881 | - } | |
| 882 | - } | |
| 883 | - | |
| 884 | - } | |
| 885 | - | |
| 886 | - @Override | |
| 887 | 639 | public int removeMedia(String app, String stream) { |
| 888 | 640 | return streamPushMapper.del(app, stream); |
| 889 | 641 | } |
| 890 | 642 | |
| 891 | 643 | @Override |
| 892 | - public StreamPushItem getMedia(String app, String stream) { | |
| 893 | - return streamPushMapper.selectOne(app, stream); | |
| 894 | - } | |
| 895 | - | |
| 896 | - @Override | |
| 897 | - public void clearMediaList() { | |
| 898 | - streamPushMapper.clear(); | |
| 899 | - } | |
| 900 | - | |
| 901 | - @Override | |
| 902 | 644 | public int mediaOffline(String app, String stream) { |
| 903 | 645 | GbStream gbStream = gbStreamMapper.selectOne(app, stream); |
| 904 | 646 | int result; |
| 905 | 647 | if ("proxy".equals(gbStream.getStreamType())) { |
| 906 | 648 | result = streamProxyMapper.updateStatus(app, stream, false); |
| 907 | 649 | }else { |
| 908 | - result = streamPushMapper.updateStatus(app, stream, false); | |
| 650 | + result = streamPushMapper.updatePushStatus(app, stream, false); | |
| 909 | 651 | } |
| 910 | 652 | return result; |
| 911 | 653 | } |
| 912 | 654 | |
| 655 | + @Override | |
| 913 | 656 | public int mediaOnline(String app, String stream) { |
| 914 | 657 | GbStream gbStream = gbStreamMapper.selectOne(app, stream); |
| 915 | 658 | int result; |
| 916 | 659 | if ("proxy".equals(gbStream.getStreamType())) { |
| 917 | 660 | result = streamProxyMapper.updateStatus(app, stream, true); |
| 918 | 661 | }else { |
| 919 | - result = streamPushMapper.updateStatus(app, stream, true); | |
| 662 | + result = streamPushMapper.updatePushStatus(app, stream, true); | |
| 920 | 663 | } |
| 921 | 664 | return result; |
| 922 | 665 | } |
| ... | ... | @@ -954,6 +697,29 @@ public class VideoManagerStorageImpl implements IVideoManagerStorage { |
| 954 | 697 | |
| 955 | 698 | @Override |
| 956 | 699 | public int addCatalog(PlatformCatalog platformCatalog) { |
| 700 | + ParentPlatform platform = platformMapper.getParentPlatByServerGBId(platformCatalog.getPlatformId()); | |
| 701 | + if (platform == null) { | |
| 702 | + return 0; | |
| 703 | + } | |
| 704 | + if (platform.getTreeType().equals(TreeType.BUSINESS_GROUP)) { | |
| 705 | + if (platformCatalog.getPlatformId().equals(platformCatalog.getParentId())) { | |
| 706 | + // 第一层节点 | |
| 707 | + platformCatalog.setBusinessGroupId(platformCatalog.getId()); | |
| 708 | + platformCatalog.setParentId(platform.getDeviceGBId()); | |
| 709 | + }else { | |
| 710 | + // 获取顶层的 | |
| 711 | + PlatformCatalog topCatalog = getTopCatalog(platformCatalog.getParentId(), platform.getDeviceGBId()); | |
| 712 | + platformCatalog.setBusinessGroupId(topCatalog.getId()); | |
| 713 | + } | |
| 714 | + } | |
| 715 | + if (platform.getTreeType().equals(TreeType.CIVIL_CODE)) { | |
| 716 | + platformCatalog.setCivilCode(platformCatalog.getId()); | |
| 717 | + if (platformCatalog.getPlatformId().equals(platformCatalog.getParentId())) { | |
| 718 | + // 第一层节点 | |
| 719 | + platformCatalog.setParentId(platform.getDeviceGBId()); | |
| 720 | + } | |
| 721 | + } | |
| 722 | + | |
| 957 | 723 | int result = catalogMapper.add(platformCatalog); |
| 958 | 724 | if (result > 0) { |
| 959 | 725 | DeviceChannel deviceChannel = getDeviceChannelByCatalog(platformCatalog); |
| ... | ... | @@ -962,6 +728,15 @@ public class VideoManagerStorageImpl implements IVideoManagerStorage { |
| 962 | 728 | return result; |
| 963 | 729 | } |
| 964 | 730 | |
| 731 | + private PlatformCatalog getTopCatalog(String id, String platformId) { | |
| 732 | + PlatformCatalog catalog = catalogMapper.selectParentCatalog(id); | |
| 733 | + if (catalog.getParentId().equals(platformId)) { | |
| 734 | + return catalog; | |
| 735 | + }else { | |
| 736 | + return getTopCatalog(catalog.getParentId(), platformId); | |
| 737 | + } | |
| 738 | + } | |
| 739 | + | |
| 965 | 740 | @Override |
| 966 | 741 | public PlatformCatalog getCatalog(String id) { |
| 967 | 742 | return catalogMapper.select(id); |
| ... | ... | @@ -1032,8 +807,8 @@ public class VideoManagerStorageImpl implements IVideoManagerStorage { |
| 1032 | 807 | } |
| 1033 | 808 | |
| 1034 | 809 | @Override |
| 1035 | - public List<PlatformCatalog> queryCatalogInPlatform(String platformId) { | |
| 1036 | - return catalogMapper.selectByPlatForm(platformId); | |
| 810 | + public List<DeviceChannel> queryCatalogInPlatform(String platformId) { | |
| 811 | + return catalogMapper.queryCatalogInPlatform(platformId); | |
| 1037 | 812 | } |
| 1038 | 813 | |
| 1039 | 814 | @Override |
| ... | ... | @@ -1076,20 +851,24 @@ public class VideoManagerStorageImpl implements IVideoManagerStorage { |
| 1076 | 851 | } |
| 1077 | 852 | |
| 1078 | 853 | private DeviceChannel getDeviceChannelByCatalog(PlatformCatalog catalog) { |
| 1079 | - ParentPlatform parentPlatByServerGBId = platformMapper.getParentPlatByServerGBId(catalog.getPlatformId()); | |
| 854 | + ParentPlatform platform = platformMapper.getParentPlatByServerGBId(catalog.getPlatformId()); | |
| 1080 | 855 | DeviceChannel deviceChannel = new DeviceChannel(); |
| 1081 | 856 | deviceChannel.setChannelId(catalog.getId()); |
| 1082 | 857 | deviceChannel.setName(catalog.getName()); |
| 1083 | 858 | deviceChannel.setLongitude(0.0); |
| 1084 | 859 | deviceChannel.setLatitude(0.0); |
| 1085 | - deviceChannel.setDeviceId(parentPlatByServerGBId.getDeviceGBId()); | |
| 860 | + deviceChannel.setDeviceId(platform.getDeviceGBId()); | |
| 1086 | 861 | deviceChannel.setManufacture("wvp-pro"); |
| 1087 | 862 | deviceChannel.setStatus(1); |
| 1088 | 863 | deviceChannel.setParental(1); |
| 1089 | - deviceChannel.setParentId(catalog.getParentId()); | |
| 864 | + | |
| 1090 | 865 | deviceChannel.setRegisterWay(1); |
| 1091 | 866 | // 行政区划应该是Domain的前八位 |
| 1092 | - deviceChannel.setCivilCode(parentPlatByServerGBId.getAdministrativeDivision()); | |
| 867 | + if (platform.getTreeType().equals(TreeType.BUSINESS_GROUP)) { | |
| 868 | + deviceChannel.setParentId(catalog.getParentId()); | |
| 869 | + deviceChannel.setBusinessGroupId(catalog.getBusinessGroupId()); | |
| 870 | + } | |
| 871 | + | |
| 1093 | 872 | deviceChannel.setModel("live"); |
| 1094 | 873 | deviceChannel.setOwner("wvp-pro"); |
| 1095 | 874 | deviceChannel.setSecrecy("0"); |
| ... | ... | @@ -1151,4 +930,27 @@ public class VideoManagerStorageImpl implements IVideoManagerStorage { |
| 1151 | 930 | |
| 1152 | 931 | deviceChannelMapper.updatePosition(deviceChannel); |
| 1153 | 932 | } |
| 933 | + | |
| 934 | + @Override | |
| 935 | + public void cleanContentForPlatform(String serverGBId) { | |
| 936 | +// List<PlatformCatalog> catalogList = catalogMapper.selectByPlatForm(serverGBId); | |
| 937 | +// if (catalogList.size() > 0) { | |
| 938 | +// int result = catalogMapper.delByPlatformId(serverGBId); | |
| 939 | +// if (result > 0) { | |
| 940 | +// List<DeviceChannel> deviceChannels = new ArrayList<>(); | |
| 941 | +// for (PlatformCatalog catalog : catalogList) { | |
| 942 | +// deviceChannels.add(getDeviceChannelByCatalog(catalog)); | |
| 943 | +// } | |
| 944 | +// eventPublisher.catalogEventPublish(serverGBId, deviceChannels, CatalogEvent.DEL); | |
| 945 | +// } | |
| 946 | +// } | |
| 947 | + catalogMapper.delByPlatformId(serverGBId); | |
| 948 | + platformChannelMapper.delByPlatformId(serverGBId); | |
| 949 | + platformGbStreamMapper.delByPlatformId(serverGBId); | |
| 950 | + } | |
| 951 | + | |
| 952 | + @Override | |
| 953 | + public List<DeviceChannel> queryChannelWithCatalog(String serverGBId) { | |
| 954 | + return deviceChannelMapper.queryChannelWithCatalog(serverGBId); | |
| 955 | + } | |
| 1154 | 956 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/vmanager/bean/WVPResult.java
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceQuery.java
| ... | ... | @@ -12,6 +12,7 @@ import com.genersoft.iot.vmp.gb28181.task.impl.MobilePositionSubscribeTask; |
| 12 | 12 | import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; |
| 13 | 13 | import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage; |
| 14 | 14 | import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; |
| 15 | +import com.genersoft.iot.vmp.service.IDeviceChannelService; | |
| 15 | 16 | import com.genersoft.iot.vmp.service.IDeviceService; |
| 16 | 17 | import com.genersoft.iot.vmp.storager.IRedisCatchStorage; |
| 17 | 18 | import com.genersoft.iot.vmp.storager.IVideoManagerStorage; |
| ... | ... | @@ -53,6 +54,9 @@ public class DeviceQuery { |
| 53 | 54 | private IVideoManagerStorage storager; |
| 54 | 55 | |
| 55 | 56 | @Autowired |
| 57 | + private IDeviceChannelService deviceChannelService; | |
| 58 | + | |
| 59 | + @Autowired | |
| 56 | 60 | private IRedisCatchStorage redisCatchStorage; |
| 57 | 61 | |
| 58 | 62 | @Autowired |
| ... | ... | @@ -280,7 +284,7 @@ public class DeviceQuery { |
| 280 | 284 | }) |
| 281 | 285 | @PostMapping("/channel/update/{deviceId}") |
| 282 | 286 | public ResponseEntity<PageInfo> updateChannel(@PathVariable String deviceId,DeviceChannel channel){ |
| 283 | - storager.updateChannel(deviceId, channel); | |
| 287 | + deviceChannelService.updateChannel(deviceId, channel); | |
| 284 | 288 | return new ResponseEntity<>(null,HttpStatus.OK); |
| 285 | 289 | } |
| 286 | 290 | ... | ... |
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/gbStream/GbStreamController.java
| ... | ... | @@ -44,7 +44,6 @@ public class GbStreamController { |
| 44 | 44 | @ApiImplicitParam(name = "platformId", value = "平台ID", required = true , dataTypeClass = String.class), |
| 45 | 45 | @ApiImplicitParam(name = "catalogId", value = "目录ID", required = false , dataTypeClass = String.class), |
| 46 | 46 | @ApiImplicitParam(name="query", value = "查询内容", required = false , dataTypeClass = String.class), |
| 47 | - @ApiImplicitParam(name="pushing", value = "是否正在推流", required = false , dataTypeClass = Boolean.class), | |
| 48 | 47 | @ApiImplicitParam(name="mediaServerId", value = "流媒体ID", required = false , dataTypeClass = String.class), |
| 49 | 48 | |
| 50 | 49 | }) |
| ... | ... | @@ -55,7 +54,6 @@ public class GbStreamController { |
| 55 | 54 | @RequestParam(required = true)String platformId, |
| 56 | 55 | @RequestParam(required = false)String catalogId, |
| 57 | 56 | @RequestParam(required = false)String query, |
| 58 | - @RequestParam(required = false)Boolean pushing, | |
| 59 | 57 | @RequestParam(required = false)String mediaServerId){ |
| 60 | 58 | if (StringUtils.isEmpty(catalogId)) { |
| 61 | 59 | catalogId = null; |
| ... | ... | @@ -69,7 +67,7 @@ public class GbStreamController { |
| 69 | 67 | |
| 70 | 68 | // catalogId 为null 查询未在平台下分配的数据 |
| 71 | 69 | // catalogId 不为null 查询平台下这个,目录下的通道 |
| 72 | - return gbStreamService.getAll(page, count, platformId, catalogId, query, pushing, mediaServerId); | |
| 70 | + return gbStreamService.getAll(page, count, platformId, catalogId, query, mediaServerId); | |
| 73 | 71 | } |
| 74 | 72 | |
| 75 | 73 | ... | ... |
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/media/MediaController.java
| ... | ... | @@ -6,6 +6,7 @@ import com.genersoft.iot.vmp.conf.security.dto.LoginUser; |
| 6 | 6 | import com.genersoft.iot.vmp.media.zlm.dto.OnPublishHookParam; |
| 7 | 7 | import com.genersoft.iot.vmp.media.zlm.dto.StreamAuthorityInfo; |
| 8 | 8 | import com.genersoft.iot.vmp.service.IMediaServerService; |
| 9 | +import com.genersoft.iot.vmp.service.IStreamProxyService; | |
| 9 | 10 | import com.genersoft.iot.vmp.service.IStreamPushService; |
| 10 | 11 | import com.genersoft.iot.vmp.service.IMediaService; |
| 11 | 12 | import com.genersoft.iot.vmp.storager.IRedisCatchStorage; |
| ... | ... | @@ -37,6 +38,8 @@ public class MediaController { |
| 37 | 38 | |
| 38 | 39 | @Autowired |
| 39 | 40 | private IMediaService mediaService; |
| 41 | + @Autowired | |
| 42 | + private IStreamProxyService streamProxyService; | |
| 40 | 43 | |
| 41 | 44 | |
| 42 | 45 | /** |
| ... | ... | @@ -95,8 +98,30 @@ public class MediaController { |
| 95 | 98 | result.setMsg("scccess"); |
| 96 | 99 | result.setData(streamInfo); |
| 97 | 100 | }else { |
| 98 | - result.setCode(-1); | |
| 99 | - result.setMsg("fail"); | |
| 101 | + //获取流失败,重启拉流后重试一次 | |
| 102 | + streamProxyService.stop(app,stream); | |
| 103 | + boolean start = streamProxyService.start(app, stream); | |
| 104 | + try { | |
| 105 | + Thread.sleep(1000); | |
| 106 | + } catch (InterruptedException e) { | |
| 107 | + e.printStackTrace(); | |
| 108 | + } | |
| 109 | + if (useSourceIpAsStreamIp != null && useSourceIpAsStreamIp) { | |
| 110 | + String host = request.getHeader("Host"); | |
| 111 | + String localAddr = host.split(":")[0]; | |
| 112 | + logger.info("使用{}作为返回流的ip", localAddr); | |
| 113 | + streamInfo = mediaService.getStreamInfoByAppAndStreamWithCheck(app, stream, mediaServerId, localAddr, authority); | |
| 114 | + }else { | |
| 115 | + streamInfo = mediaService.getStreamInfoByAppAndStreamWithCheck(app, stream, mediaServerId, authority); | |
| 116 | + } | |
| 117 | + if (streamInfo != null){ | |
| 118 | + result.setCode(0); | |
| 119 | + result.setMsg("scccess"); | |
| 120 | + result.setData(streamInfo); | |
| 121 | + }else { | |
| 122 | + result.setCode(-1); | |
| 123 | + result.setMsg("fail"); | |
| 124 | + } | |
| 100 | 125 | } |
| 101 | 126 | return result; |
| 102 | 127 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/platform/PlatformController.java
| ... | ... | @@ -8,7 +8,9 @@ import com.genersoft.iot.vmp.conf.UserSetting; |
| 8 | 8 | import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; |
| 9 | 9 | import com.genersoft.iot.vmp.gb28181.bean.PlatformCatalog; |
| 10 | 10 | import com.genersoft.iot.vmp.gb28181.bean.SubscribeHolder; |
| 11 | +import com.genersoft.iot.vmp.gb28181.bean.TreeType; | |
| 11 | 12 | import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform; |
| 13 | +import com.genersoft.iot.vmp.service.IPlatformChannelService; | |
| 12 | 14 | import com.genersoft.iot.vmp.storager.IRedisCatchStorage; |
| 13 | 15 | import com.genersoft.iot.vmp.storager.IVideoManagerStorage; |
| 14 | 16 | import com.genersoft.iot.vmp.utils.DateUtil; |
| ... | ... | @@ -49,6 +51,9 @@ public class PlatformController { |
| 49 | 51 | private IVideoManagerStorage storager; |
| 50 | 52 | |
| 51 | 53 | @Autowired |
| 54 | + private IPlatformChannelService platformChannelService; | |
| 55 | + | |
| 56 | + @Autowired | |
| 52 | 57 | private IRedisCatchStorage redisCatchStorage; |
| 53 | 58 | |
| 54 | 59 | @Autowired |
| ... | ... | @@ -236,6 +241,12 @@ public class PlatformController { |
| 236 | 241 | parentPlatform.setCharacterSet(parentPlatform.getCharacterSet().toUpperCase()); |
| 237 | 242 | ParentPlatform parentPlatformOld = storager.queryParentPlatByServerGBId(parentPlatform.getServerGBId()); |
| 238 | 243 | parentPlatform.setUpdateTime(DateUtil.getNow()); |
| 244 | + if (!parentPlatformOld.getTreeType().equals(parentPlatform.getTreeType())) { | |
| 245 | + // 目录结构发生变化,清空之前的关联关系 | |
| 246 | + logger.info("保存平台{}时发现目录结构变化,清空关联关系", parentPlatform.getDeviceGBId()); | |
| 247 | + storager.cleanContentForPlatform(parentPlatform.getServerGBId()); | |
| 248 | + | |
| 249 | + } | |
| 239 | 250 | boolean updateResult = storager.updateParentPlatform(parentPlatform); |
| 240 | 251 | |
| 241 | 252 | if (updateResult) { |
| ... | ... | @@ -256,6 +267,8 @@ public class PlatformController { |
| 256 | 267 | } |
| 257 | 268 | } else if (parentPlatformOld != null && parentPlatformOld.isEnable() && !parentPlatform.isEnable()) { // 关闭启用时注销 |
| 258 | 269 | commanderForPlatform.unregister(parentPlatformOld, null, null); |
| 270 | + // 停止订阅相关的定时任务 | |
| 271 | + subscribeHolder.removeAllSubscribe(parentPlatform.getServerGBId()); | |
| 259 | 272 | } |
| 260 | 273 | wvpResult.setCode(0); |
| 261 | 274 | wvpResult.setMsg("success"); |
| ... | ... | @@ -405,7 +418,7 @@ public class PlatformController { |
| 405 | 418 | if (logger.isDebugEnabled()) { |
| 406 | 419 | logger.debug("给上级平台添加国标通道API调用"); |
| 407 | 420 | } |
| 408 | - int result = storager.updateChannelForGB(param.getPlatformId(), param.getChannelReduces(), param.getCatalogId()); | |
| 421 | + int result = platformChannelService.updateChannelForGB(param.getPlatformId(), param.getChannelReduces(), param.getCatalogId()); | |
| 409 | 422 | |
| 410 | 423 | return new ResponseEntity<>(String.valueOf(result > 0), HttpStatus.OK); |
| 411 | 424 | } |
| ... | ... | @@ -451,13 +464,20 @@ public class PlatformController { |
| 451 | 464 | if (logger.isDebugEnabled()) { |
| 452 | 465 | logger.debug("查询目录,platformId: {}, parentId: {}", platformId, parentId); |
| 453 | 466 | } |
| 467 | + ParentPlatform platform = storager.queryParentPlatByServerGBId(platformId); | |
| 468 | + if (platform == null) { | |
| 469 | + return new ResponseEntity<>(new WVPResult<>(400, "平台未找到", null), HttpStatus.OK); | |
| 470 | + } | |
| 471 | + if (platformId.equals(parentId)) { | |
| 472 | + parentId = platform.getDeviceGBId(); | |
| 473 | + } | |
| 454 | 474 | List<PlatformCatalog> platformCatalogList = storager.getChildrenCatalogByPlatform(platformId, parentId); |
| 455 | - // 查询下属的国标通道 | |
| 456 | -// List<PlatformCatalog> catalogsForChannel = storager.queryChannelInParentPlatformAndCatalog(platformId, parentId); | |
| 457 | - // 查询下属的直播流通道 | |
| 458 | -// List<PlatformCatalog> catalogsForStream = storager.queryStreamInParentPlatformAndCatalog(platformId, parentId); | |
| 459 | -// platformCatalogList.addAll(catalogsForChannel); | |
| 460 | -// platformCatalogList.addAll(catalogsForStream); | |
| 475 | +// if (platform.getTreeType().equals(TreeType.BUSINESS_GROUP)) { | |
| 476 | +// platformCatalogList = storager.getChildrenCatalogByPlatform(platformId, parentId); | |
| 477 | +// }else { | |
| 478 | +// | |
| 479 | +// } | |
| 480 | + | |
| 461 | 481 | WVPResult<List<PlatformCatalog>> result = new WVPResult<>(); |
| 462 | 482 | result.setCode(0); |
| 463 | 483 | result.setMsg("success"); |
| ... | ... | @@ -485,7 +505,6 @@ public class PlatformController { |
| 485 | 505 | PlatformCatalog platformCatalogInStore = storager.getCatalog(platformCatalog.getId()); |
| 486 | 506 | WVPResult<List<PlatformCatalog>> result = new WVPResult<>(); |
| 487 | 507 | |
| 488 | - | |
| 489 | 508 | if (platformCatalogInStore != null) { |
| 490 | 509 | result.setCode(-1); |
| 491 | 510 | result.setMsg(platformCatalog.getId() + " already exists"); | ... | ... |
src/main/java/com/genersoft/iot/vmp/vmanager/server/ServerController.java
| ... | ... | @@ -8,6 +8,8 @@ import com.genersoft.iot.vmp.conf.DynamicTask; |
| 8 | 8 | import com.genersoft.iot.vmp.conf.SipConfig; |
| 9 | 9 | import com.genersoft.iot.vmp.conf.UserSetting; |
| 10 | 10 | import com.genersoft.iot.vmp.conf.VersionInfo; |
| 11 | +import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe; | |
| 12 | +import com.genersoft.iot.vmp.media.zlm.dto.IHookSubscribe; | |
| 11 | 13 | import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; |
| 12 | 14 | import com.genersoft.iot.vmp.service.IMediaServerService; |
| 13 | 15 | import com.genersoft.iot.vmp.utils.SpringBeanFactory; |
| ... | ... | @@ -38,7 +40,7 @@ import java.util.Set; |
| 38 | 40 | public class ServerController { |
| 39 | 41 | |
| 40 | 42 | @Autowired |
| 41 | - private ConfigurableApplicationContext context; | |
| 43 | + private ZLMHttpHookSubscribe zlmHttpHookSubscribe; | |
| 42 | 44 | |
| 43 | 45 | @Autowired |
| 44 | 46 | private IMediaServerService mediaServerService; |
| ... | ... | @@ -254,6 +256,18 @@ public class ServerController { |
| 254 | 256 | return result; |
| 255 | 257 | } |
| 256 | 258 | |
| 259 | + @ApiOperation("获取当前所有hook") | |
| 260 | + @GetMapping(value = "/hooks") | |
| 261 | + @ResponseBody | |
| 262 | + public WVPResult<List<IHookSubscribe>> getHooks(){ | |
| 263 | + WVPResult<List<IHookSubscribe>> result = new WVPResult<>(); | |
| 264 | + result.setCode(0); | |
| 265 | + result.setMsg("success"); | |
| 266 | + List<IHookSubscribe> all = zlmHttpHookSubscribe.getAll(); | |
| 267 | + result.setData(all); | |
| 268 | + return result; | |
| 269 | + } | |
| 270 | + | |
| 257 | 271 | // @ApiOperation("当前进行中的动态任务") |
| 258 | 272 | // @GetMapping(value = "/dynamicTask") |
| 259 | 273 | // @ResponseBody | ... | ... |
src/main/java/com/genersoft/iot/vmp/vmanager/streamPush/StreamPushController.java
| ... | ... | @@ -4,6 +4,7 @@ import com.alibaba.excel.EasyExcel; |
| 4 | 4 | import com.alibaba.excel.ExcelReader; |
| 5 | 5 | import com.alibaba.excel.read.metadata.ReadSheet; |
| 6 | 6 | import com.genersoft.iot.vmp.common.StreamInfo; |
| 7 | +import com.genersoft.iot.vmp.conf.UserSetting; | |
| 7 | 8 | import com.genersoft.iot.vmp.conf.security.SecurityUtils; |
| 8 | 9 | import com.genersoft.iot.vmp.conf.security.dto.LoginUser; |
| 9 | 10 | import com.genersoft.iot.vmp.gb28181.bean.GbStream; |
| ... | ... | @@ -63,6 +64,9 @@ public class StreamPushController { |
| 63 | 64 | @Autowired |
| 64 | 65 | private IMediaService mediaService; |
| 65 | 66 | |
| 67 | + @Autowired | |
| 68 | + private UserSetting userSetting; | |
| 69 | + | |
| 66 | 70 | @ApiOperation("推流列表查询") |
| 67 | 71 | @ApiImplicitParams({ |
| 68 | 72 | @ApiImplicitParam(name="page", value = "当前页", required = true, dataTypeClass = Integer.class), |
| ... | ... | @@ -260,29 +264,63 @@ public class StreamPushController { |
| 260 | 264 | }) |
| 261 | 265 | @GetMapping(value = "/getPlayUrl") |
| 262 | 266 | @ResponseBody |
| 263 | - public WVPResult<StreamInfo> getPlayUrl(HttpServletRequest request, @RequestParam String app, | |
| 264 | - @RequestParam String stream, | |
| 265 | - @RequestParam(required = false) String mediaServerId){ | |
| 267 | + public WVPResult<StreamInfo> getPlayUrl(@RequestParam String app,@RequestParam String stream, | |
| 268 | + @RequestParam(required = false) String mediaServerId){ | |
| 266 | 269 | boolean authority = false; |
| 267 | 270 | // 是否登陆用户, 登陆用户返回完整信息 |
| 268 | 271 | LoginUser userInfo = SecurityUtils.getUserInfo(); |
| 269 | 272 | if (userInfo!= null) { |
| 270 | 273 | authority = true; |
| 271 | 274 | } |
| 272 | - | |
| 273 | - StreamInfo streamInfo = mediaService.getStreamInfoByAppAndStreamWithCheck(app, stream, mediaServerId, authority); | |
| 274 | - | |
| 275 | 275 | WVPResult<StreamInfo> result = new WVPResult<>(); |
| 276 | + StreamPushItem push = streamPushService.getPush(app, stream); | |
| 277 | + if (push != null && !push.isSelf()) { | |
| 278 | + result.setCode(-1); | |
| 279 | + result.setMsg("来自其他平台的推流信息"); | |
| 280 | + return result; | |
| 281 | + } | |
| 282 | + StreamInfo streamInfo = mediaService.getStreamInfoByAppAndStreamWithCheck(app, stream, mediaServerId, authority); | |
| 276 | 283 | if (streamInfo != null){ |
| 277 | 284 | result.setCode(0); |
| 278 | - result.setMsg("scccess"); | |
| 285 | + result.setMsg("success"); | |
| 279 | 286 | result.setData(streamInfo); |
| 280 | 287 | }else { |
| 281 | 288 | result.setCode(-1); |
| 282 | - result.setMsg("fail"); | |
| 289 | + result.setMsg("获取播放地址失败"); | |
| 283 | 290 | } |
| 291 | + | |
| 284 | 292 | return result; |
| 285 | 293 | } |
| 286 | 294 | |
| 295 | + /** | |
| 296 | + * 获取推流播放地址 | |
| 297 | + * @param stream 推流信息 | |
| 298 | + * @return | |
| 299 | + */ | |
| 300 | + @ApiOperation("获取推流播放地址") | |
| 301 | + @ApiImplicitParams({ | |
| 302 | + @ApiImplicitParam(name = "stream", value = "推流信息", dataTypeClass = StreamPushItem.class), | |
| 303 | + }) | |
| 304 | + @PostMapping(value = "/add") | |
| 305 | + @ResponseBody | |
| 306 | + public WVPResult<StreamInfo> add(@RequestBody StreamPushItem stream){ | |
| 307 | + if (StringUtils.isEmpty(stream.getGbId())) { | |
| 308 | + | |
| 309 | + return new WVPResult<>(400, "国标ID不可为空", null); | |
| 310 | + } | |
| 311 | + if (StringUtils.isEmpty(stream.getApp()) && StringUtils.isEmpty(stream.getStream())) { | |
| 312 | + return new WVPResult<>(400, "app或stream不可为空", null); | |
| 313 | + } | |
| 314 | + stream.setStatus(false); | |
| 315 | + stream.setPushIng(false); | |
| 316 | + stream.setAliveSecond(0L); | |
| 317 | + stream.setTotalReaderCount("0"); | |
| 318 | + boolean result = streamPushService.add(stream); | |
| 287 | 319 | |
| 320 | + if (result) { | |
| 321 | + return new WVPResult<>(0, "success", null); | |
| 322 | + }else { | |
| 323 | + return new WVPResult<>(-1, "fail", null); | |
| 324 | + } | |
| 325 | + } | |
| 288 | 326 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/vmanager/user/UserController.java
| ... | ... | @@ -8,6 +8,7 @@ import com.genersoft.iot.vmp.storager.dao.dto.Role; |
| 8 | 8 | import com.genersoft.iot.vmp.storager.dao.dto.User; |
| 9 | 9 | import com.genersoft.iot.vmp.utils.DateUtil; |
| 10 | 10 | import com.genersoft.iot.vmp.vmanager.bean.WVPResult; |
| 11 | +import com.github.pagehelper.PageInfo; | |
| 11 | 12 | import io.swagger.annotations.Api; |
| 12 | 13 | import io.swagger.annotations.ApiImplicitParam; |
| 13 | 14 | import io.swagger.annotations.ApiImplicitParams; |
| ... | ... | @@ -123,7 +124,8 @@ public class UserController { |
| 123 | 124 | User user = new User(); |
| 124 | 125 | user.setUsername(username); |
| 125 | 126 | user.setPassword(DigestUtils.md5DigestAsHex(password.getBytes())); |
| 126 | - | |
| 127 | + //新增用户的pushKey的生成规则为md5(时间戳+用户名) | |
| 128 | + user.setPushKey(DigestUtils.md5DigestAsHex((System.currentTimeMillis()+password).getBytes())); | |
| 127 | 129 | Role role = roleService.getRoleById(roleId); |
| 128 | 130 | |
| 129 | 131 | if (role == null) { |
| ... | ... | @@ -137,6 +139,7 @@ public class UserController { |
| 137 | 139 | user.setUpdateTime(DateUtil.getNow()); |
| 138 | 140 | int addResult = userService.addUser(user); |
| 139 | 141 | |
| 142 | + | |
| 140 | 143 | result.setCode(addResult > 0 ? 0 : -1); |
| 141 | 144 | result.setMsg(addResult > 0 ? "success" : "fail"); |
| 142 | 145 | result.setData(addResult); |
| ... | ... | @@ -177,4 +180,68 @@ public class UserController { |
| 177 | 180 | result.setData(allUsers); |
| 178 | 181 | return new ResponseEntity<>(result, HttpStatus.OK); |
| 179 | 182 | } |
| 183 | + | |
| 184 | + /** | |
| 185 | + * 分页查询用户 | |
| 186 | + * | |
| 187 | + * @param page 当前页 | |
| 188 | + * @param count 每页查询数量 | |
| 189 | + * @return 分页用户列表 | |
| 190 | + */ | |
| 191 | + @ApiOperation("分页查询用户") | |
| 192 | + @ApiImplicitParams({ | |
| 193 | + @ApiImplicitParam(name = "page", value = "当前页", required = true, dataTypeClass = Integer.class), | |
| 194 | + @ApiImplicitParam(name = "count", value = "每页查询数量", required = true, dataTypeClass = Integer.class), | |
| 195 | + }) | |
| 196 | + @GetMapping("/users") | |
| 197 | + public PageInfo<User> users(int page, int count) { | |
| 198 | + return userService.getUsers(page, count); | |
| 199 | + } | |
| 200 | + | |
| 201 | + @ApiOperation("修改pushkey") | |
| 202 | + @ApiImplicitParams({ | |
| 203 | + @ApiImplicitParam(name = "userId", required = true, value = "用户Id", dataTypeClass = Integer.class), | |
| 204 | + @ApiImplicitParam(name = "pushKey", required = true, value = "新的pushKey", dataTypeClass = String.class), | |
| 205 | + }) | |
| 206 | + @RequestMapping("/changePushKey") | |
| 207 | + public ResponseEntity<WVPResult<String>> changePushKey(@RequestParam Integer userId,@RequestParam String pushKey) { | |
| 208 | + // 获取当前登录用户id | |
| 209 | + int currenRoleId = SecurityUtils.getUserInfo().getRole().getId(); | |
| 210 | + WVPResult<String> result = new WVPResult<>(); | |
| 211 | + if (currenRoleId != 1) { | |
| 212 | + // 只用角色id为0才可以删除和添加用户 | |
| 213 | + result.setCode(-1); | |
| 214 | + result.setMsg("用户无权限"); | |
| 215 | + return new ResponseEntity<>(result, HttpStatus.FORBIDDEN); | |
| 216 | + } | |
| 217 | + int resetPushKeyResult = userService.changePushKey(userId,pushKey); | |
| 218 | + | |
| 219 | + result.setCode(resetPushKeyResult > 0 ? 0 : -1); | |
| 220 | + result.setMsg(resetPushKeyResult > 0 ? "success" : "fail"); | |
| 221 | + return new ResponseEntity<>(result, HttpStatus.OK); | |
| 222 | + } | |
| 223 | + | |
| 224 | + @ApiOperation("管理员修改普通用户密码") | |
| 225 | + @ApiImplicitParams({ | |
| 226 | + @ApiImplicitParam(name = "adminId", required = true, value = "管理员id", dataTypeClass = String.class), | |
| 227 | + @ApiImplicitParam(name = "userId", required = true, value = "用户id", dataTypeClass = String.class), | |
| 228 | + @ApiImplicitParam(name = "password", required = true, value = "新密码(未md5加密的密码)", dataTypeClass = String.class), | |
| 229 | + }) | |
| 230 | + @PostMapping("/changePasswordForAdmin") | |
| 231 | + public String changePasswordForAdmin(@RequestParam int userId, @RequestParam String password) { | |
| 232 | + // 获取当前登录用户id | |
| 233 | + LoginUser userInfo = SecurityUtils.getUserInfo(); | |
| 234 | + if (userInfo == null) { | |
| 235 | + return "fail"; | |
| 236 | + } | |
| 237 | + Role role = userInfo.getRole(); | |
| 238 | + if (role != null && role.getId() == 1) { | |
| 239 | + boolean result = userService.changePassword(userId, DigestUtils.md5DigestAsHex(password.getBytes())); | |
| 240 | + if (result) { | |
| 241 | + return "success"; | |
| 242 | + } | |
| 243 | + } | |
| 244 | + | |
| 245 | + return "fail"; | |
| 246 | + } | |
| 180 | 247 | } | ... | ... |
src/main/resources/all-application.yml
| ... | ... | @@ -149,7 +149,7 @@ media: |
| 149 | 149 | enable: true |
| 150 | 150 | # [可选] 在此范围内选择端口用于媒体流传输, 必须提前在zlm上配置该属性,不然自动配置此属性可能不成功 |
| 151 | 151 | port-range: 30000,30500 # 端口范围 |
| 152 | - # [可选] 国标级联在此范围内选择端口发送媒体流, | |
| 152 | + # [可选] 国标级联在此范围内选择端口发送媒体流 | |
| 153 | 153 | send-port-range: 30000,30500 # 端口范围 |
| 154 | 154 | # 录像辅助服务, 部署此服务可以实现zlm录像的管理与下载, 0 表示不使用 |
| 155 | 155 | record-assist-port: 0 | ... | ... |
web_src/src/components/Login.vue
| ... | ... | @@ -86,7 +86,7 @@ export default { |
| 86 | 86 | }).then(function (res) { |
| 87 | 87 | console.log(JSON.stringify(res)); |
| 88 | 88 | if (res.data.code == 0 && res.data.msg == "success") { |
| 89 | - that.$cookies.set("session", {"username": that.username}) ; | |
| 89 | + that.$cookies.set("session", {"username": that.username,"roleId":res.data.data.role.id}) ; | |
| 90 | 90 | //登录成功后 |
| 91 | 91 | that.cancelEnterkeyDefaultAction(); |
| 92 | 92 | that.$router.push('/'); | ... | ... |
web_src/src/components/ParentPlatformList.vue
| ... | ... | @@ -143,7 +143,7 @@ export default { |
| 143 | 143 | }); |
| 144 | 144 | }, |
| 145 | 145 | chooseChannel: function(platform) { |
| 146 | - this.$refs.chooseChannelDialog.openDialog(platform.serverGBId, platform.name, platform.catalogId, this.initData) | |
| 146 | + this.$refs.chooseChannelDialog.openDialog(platform.serverGBId, platform.name, platform.catalogId, platform.treeType, this.initData) | |
| 147 | 147 | }, |
| 148 | 148 | initData: function() { |
| 149 | 149 | this.getPlatformList(); | ... | ... |
web_src/src/components/PushVideoList.vue
| ... | ... | @@ -34,6 +34,8 @@ |
| 34 | 34 | <el-button icon="el-icon-delete" size="mini" style="margin-right: 1rem;" |
| 35 | 35 | :disabled="multipleSelection.length === 0" type="danger" @click="batchDel">批量移除 |
| 36 | 36 | </el-button> |
| 37 | + <el-button icon="el-icon-plus" size="mini" style="margin-right: 1rem;" type="primary" @click="addStream">添加通道 | |
| 38 | + </el-button> | |
| 37 | 39 | <el-button icon="el-icon-refresh-right" circle size="mini" @click="refresh()"></el-button> |
| 38 | 40 | </div> |
| 39 | 41 | </div> |
| ... | ... | @@ -56,20 +58,25 @@ |
| 56 | 58 | <el-table-column label="开始时间" min-width="200"> |
| 57 | 59 | <template slot-scope="scope"> |
| 58 | 60 | <el-button-group> |
| 59 | - {{ dateFormat(parseInt(scope.row.createStamp)) }} | |
| 61 | + {{ scope.row.pushTime == null? "-":scope.row.pushTime }} | |
| 60 | 62 | </el-button-group> |
| 61 | 63 | </template> |
| 62 | 64 | </el-table-column> |
| 63 | 65 | <el-table-column label="正在推流" min-width="100"> |
| 64 | 66 | <template slot-scope="scope"> |
| 65 | - {{ (scope.row.status == false && scope.row.gbId == null) || scope.row.status ? '是' : '否' }} | |
| 67 | + {{scope.row.pushIng ? '是' : '否' }} | |
| 68 | + </template> | |
| 69 | + </el-table-column> | |
| 70 | + <el-table-column label="本平台推流" min-width="100"> | |
| 71 | + <template slot-scope="scope"> | |
| 72 | + {{scope.row.pushIng && !!scope.row.self ? '是' : '否' }} | |
| 66 | 73 | </template> |
| 67 | 74 | </el-table-column> |
| 68 | 75 | |
| 69 | 76 | <el-table-column label="操作" min-width="360" fixed="right"> |
| 70 | 77 | <template slot-scope="scope"> |
| 71 | 78 | <el-button size="medium" icon="el-icon-video-play" |
| 72 | - v-if="(scope.row.status == false && scope.row.gbId == null) || scope.row.status" | |
| 79 | + v-if="scope.row.pushIng === true" | |
| 73 | 80 | @click="playPush(scope.row)" type="text">播放 |
| 74 | 81 | </el-button> |
| 75 | 82 | <el-divider direction="vertical"></el-divider> |
| ... | ... | @@ -103,7 +110,7 @@ |
| 103 | 110 | <script> |
| 104 | 111 | import streamProxyEdit from './dialog/StreamProxyEdit.vue' |
| 105 | 112 | import devicePlayer from './dialog/devicePlayer.vue' |
| 106 | -import addStreamTOGB from './dialog/addStreamTOGB.vue' | |
| 113 | +import addStreamTOGB from './dialog/pushStreamEdit.vue' | |
| 107 | 114 | import uiHeader from '../layout/UiHeader.vue' |
| 108 | 115 | import importChannel from './dialog/importChannel.vue' |
| 109 | 116 | import MediaServer from './service/MediaServer' |
| ... | ... | @@ -195,10 +202,15 @@ export default { |
| 195 | 202 | } |
| 196 | 203 | }).then(function (res) { |
| 197 | 204 | that.getListLoading = false; |
| 198 | - that.$refs.devicePlayer.openDialog("streamPlay", null, null, { | |
| 199 | - streamInfo: res.data.data, | |
| 200 | - hasAudio: true | |
| 201 | - }); | |
| 205 | + if (res.data.code === 0 ) { | |
| 206 | + that.$refs.devicePlayer.openDialog("streamPlay", null, null, { | |
| 207 | + streamInfo: res.data.data, | |
| 208 | + hasAudio: true | |
| 209 | + }); | |
| 210 | + }else { | |
| 211 | + that.$message.error(res.data.msg); | |
| 212 | + } | |
| 213 | + | |
| 202 | 214 | }).catch(function (error) { |
| 203 | 215 | console.error(error); |
| 204 | 216 | that.getListLoading = false; |
| ... | ... | @@ -242,24 +254,14 @@ export default { |
| 242 | 254 | console.error(error); |
| 243 | 255 | }); |
| 244 | 256 | }, |
| 245 | - dateFormat: function (/** timestamp=0 **/) { | |
| 246 | - let ts = arguments[0] || 0; | |
| 247 | - let t, y, m, d, h, i, s; | |
| 248 | - t = ts ? new Date(ts) : new Date(); | |
| 249 | - y = t.getFullYear(); | |
| 250 | - m = t.getMonth() + 1; | |
| 251 | - d = t.getDate(); | |
| 252 | - h = t.getHours(); | |
| 253 | - i = t.getMinutes(); | |
| 254 | - s = t.getSeconds(); | |
| 255 | - // 可根据需要在这里定义时间格式 | |
| 256 | - return y + '-' + (m < 10 ? '0' + m : m) + '-' + (d < 10 ? '0' + d : d) + ' ' + (h < 10 ? '0' + h : h) + ':' + (i < 10 ? '0' + i : i) + ':' + (s < 10 ? '0' + s : s); | |
| 257 | - }, | |
| 258 | 257 | importChannel: function () { |
| 259 | 258 | this.$refs.importChannel.openDialog(() => { |
| 260 | 259 | |
| 261 | 260 | }) |
| 262 | 261 | }, |
| 262 | + addStream: function (){ | |
| 263 | + this.$refs.addStreamTOGB.openDialog(null, this.initData); | |
| 264 | + }, | |
| 263 | 265 | batchDel: function () { |
| 264 | 266 | this.$confirm(`确定删除选中的${this.multipleSelection.length}个通道?`, '提示', { |
| 265 | 267 | confirmButtonText: '确定', | ... | ... |
web_src/src/components/UserManager.vue
0 → 100644
| 1 | +<template> | |
| 2 | + | |
| 3 | + <div id="app" style="width: 100%"> | |
| 4 | + <div class="page-header"> | |
| 5 | + | |
| 6 | + <div class="page-title">用户列表</div> | |
| 7 | + <div class="page-header-btn"> | |
| 8 | + <el-button icon="el-icon-plus" size="mini" style="margin-right: 1rem;" type="primary" @click="addUser"> | |
| 9 | + 添加用户 | |
| 10 | + </el-button> | |
| 11 | + | |
| 12 | + </div> | |
| 13 | + </div> | |
| 14 | + <!--用户列表--> | |
| 15 | + <el-table :data="userList" style="width: 100%;font-size: 12px;" :height="winHeight" | |
| 16 | + header-row-class-name="table-header"> | |
| 17 | + <el-table-column prop="username" label="用户名" min-width="160"/> | |
| 18 | + <el-table-column prop="pushKey" label="pushkey" min-width="160"/> | |
| 19 | + <el-table-column prop="role.name" label="类型" min-width="160"/> | |
| 20 | + <el-table-column label="操作" min-width="450" fixed="right"> | |
| 21 | + <template slot-scope="scope"> | |
| 22 | + <el-button size="medium" icon="el-icon-edit" type="text" @click="edit(scope.row)">修改密码</el-button> | |
| 23 | + <el-divider direction="vertical"></el-divider> | |
| 24 | + <el-button size="medium" icon="el-icon-edit" type="text" @click="changePushKey(scope.row)">修改pushkey</el-button> | |
| 25 | + <el-divider direction="vertical"></el-divider> | |
| 26 | + <el-button size="medium" icon="el-icon-delete" type="text" @click="deleteUser(scope.row)" | |
| 27 | + style="color: #f56c6c">删除 | |
| 28 | + </el-button> | |
| 29 | + </template> | |
| 30 | + </el-table-column> | |
| 31 | + </el-table> | |
| 32 | + <changePasswordForAdmin ref="changePasswordForAdmin"></changePasswordForAdmin> | |
| 33 | + <changePushKey ref="changePushKey"></changePushKey> | |
| 34 | + <addUser ref="addUser"></addUser> | |
| 35 | + <el-pagination | |
| 36 | + style="float: right" | |
| 37 | + @size-change="handleSizeChange" | |
| 38 | + @current-change="currentChange" | |
| 39 | + :current-page="currentPage" | |
| 40 | + :page-size="count" | |
| 41 | + :page-sizes="[15, 25, 35, 50]" | |
| 42 | + layout="total, sizes, prev, pager, next" | |
| 43 | + :total="total"> | |
| 44 | + </el-pagination> | |
| 45 | + </div> | |
| 46 | +</template> | |
| 47 | + | |
| 48 | +<script> | |
| 49 | +import uiHeader from '../layout/UiHeader.vue' | |
| 50 | +import changePasswordForAdmin from './dialog/changePasswordForAdmin.vue' | |
| 51 | +import changePushKey from './dialog/changePushKey.vue' | |
| 52 | +import addUser from '../components/dialog/addUser.vue' | |
| 53 | + | |
| 54 | +export default { | |
| 55 | + name: 'userManager', | |
| 56 | + components: { | |
| 57 | + uiHeader, | |
| 58 | + changePasswordForAdmin, | |
| 59 | + changePushKey, | |
| 60 | + addUser | |
| 61 | + }, | |
| 62 | + data() { | |
| 63 | + return { | |
| 64 | + userList: [], //设备列表 | |
| 65 | + currentUser: {}, //当前操作设备对象 | |
| 66 | + | |
| 67 | + videoComponentList: [], | |
| 68 | + updateLooper: 0, //数据刷新轮训标志 | |
| 69 | + currentUserLenth: 0, | |
| 70 | + winHeight: window.innerHeight - 200, | |
| 71 | + currentPage: 1, | |
| 72 | + count: 15, | |
| 73 | + total: 0, | |
| 74 | + getUserListLoading: false | |
| 75 | + }; | |
| 76 | + }, | |
| 77 | + mounted() { | |
| 78 | + this.initData(); | |
| 79 | + this.updateLooper = setInterval(this.initData, 10000); | |
| 80 | + }, | |
| 81 | + destroyed() { | |
| 82 | + this.$destroy('videojs'); | |
| 83 | + clearTimeout(this.updateLooper); | |
| 84 | + }, | |
| 85 | + methods: { | |
| 86 | + initData: function () { | |
| 87 | + this.getUserList(); | |
| 88 | + }, | |
| 89 | + currentChange: function (val) { | |
| 90 | + this.currentPage = val; | |
| 91 | + this.getUserList(); | |
| 92 | + }, | |
| 93 | + handleSizeChange: function (val) { | |
| 94 | + this.count = val; | |
| 95 | + this.getUserList(); | |
| 96 | + }, | |
| 97 | + getUserList: function () { | |
| 98 | + let that = this; | |
| 99 | + this.getUserListLoading = true; | |
| 100 | + this.$axios({ | |
| 101 | + method: 'get', | |
| 102 | + url: `/api/user/users`, | |
| 103 | + params: { | |
| 104 | + page: that.currentPage, | |
| 105 | + count: that.count | |
| 106 | + } | |
| 107 | + }).then(function (res) { | |
| 108 | + that.total = res.data.total; | |
| 109 | + that.userList = res.data.list; | |
| 110 | + that.getUserListLoading = false; | |
| 111 | + }).catch(function (error) { | |
| 112 | + that.getUserListLoading = false; | |
| 113 | + }); | |
| 114 | + | |
| 115 | + }, | |
| 116 | + edit: function (row) { | |
| 117 | + this.$refs.changePasswordForAdmin.openDialog(row, () => { | |
| 118 | + this.$refs.changePasswordForAdmin.close(); | |
| 119 | + this.$message({ | |
| 120 | + showClose: true, | |
| 121 | + message: "密码修改成功", | |
| 122 | + type: "success", | |
| 123 | + }); | |
| 124 | + setTimeout(this.getUserList, 200) | |
| 125 | + | |
| 126 | + }) | |
| 127 | + }, | |
| 128 | + deleteUser: function (row) { | |
| 129 | + let msg = "确定删除此用户?" | |
| 130 | + if (row.online !== 0) { | |
| 131 | + msg = "<strong>确定删除此用户?</strong>" | |
| 132 | + } | |
| 133 | + this.$confirm(msg, '提示', { | |
| 134 | + dangerouslyUseHTMLString: true, | |
| 135 | + confirmButtonText: '确定', | |
| 136 | + cancelButtonText: '取消', | |
| 137 | + center: true, | |
| 138 | + type: 'warning' | |
| 139 | + }).then(() => { | |
| 140 | + this.$axios({ | |
| 141 | + method: 'delete', | |
| 142 | + url: `/api/user/delete?id=${row.id}` | |
| 143 | + }).then((res) => { | |
| 144 | + this.getUserList(); | |
| 145 | + }).catch((error) => { | |
| 146 | + console.error(error); | |
| 147 | + }); | |
| 148 | + }).catch(() => { | |
| 149 | + | |
| 150 | + }); | |
| 151 | + | |
| 152 | + | |
| 153 | + }, | |
| 154 | + | |
| 155 | + changePushKey: function (row) { | |
| 156 | + this.$refs.changePushKey.openDialog(row, () => { | |
| 157 | + this.$refs.changePushKey.close(); | |
| 158 | + this.$message({ | |
| 159 | + showClose: true, | |
| 160 | + message: "pushKey修改成功", | |
| 161 | + type: "success", | |
| 162 | + }); | |
| 163 | + setTimeout(this.getUserList, 200) | |
| 164 | + | |
| 165 | + }) | |
| 166 | + }, | |
| 167 | + addUser: function () { | |
| 168 | + // this.$refs.addUser.openDialog() | |
| 169 | + this.$refs.addUser.openDialog( () => { | |
| 170 | + this.$refs.addUser.close(); | |
| 171 | + this.$message({ | |
| 172 | + showClose: true, | |
| 173 | + message: "用户添加成功", | |
| 174 | + type: "success", | |
| 175 | + }); | |
| 176 | + setTimeout(this.getUserList, 200) | |
| 177 | + | |
| 178 | + }) | |
| 179 | + } | |
| 180 | + } | |
| 181 | +} | |
| 182 | +</script> | |
| 183 | +<style> | |
| 184 | +.videoList { | |
| 185 | + display: flex; | |
| 186 | + flex-wrap: wrap; | |
| 187 | + align-content: flex-start; | |
| 188 | +} | |
| 189 | + | |
| 190 | +.video-item { | |
| 191 | + position: relative; | |
| 192 | + width: 15rem; | |
| 193 | + height: 10rem; | |
| 194 | + margin-right: 1rem; | |
| 195 | + background-color: #000000; | |
| 196 | +} | |
| 197 | + | |
| 198 | +.video-item-img { | |
| 199 | + position: absolute; | |
| 200 | + top: 0; | |
| 201 | + bottom: 0; | |
| 202 | + left: 0; | |
| 203 | + right: 0; | |
| 204 | + margin: auto; | |
| 205 | + width: 100%; | |
| 206 | + height: 100%; | |
| 207 | +} | |
| 208 | + | |
| 209 | +.video-item-img:after { | |
| 210 | + content: ""; | |
| 211 | + display: inline-block; | |
| 212 | + position: absolute; | |
| 213 | + z-index: 2; | |
| 214 | + top: 0; | |
| 215 | + bottom: 0; | |
| 216 | + left: 0; | |
| 217 | + right: 0; | |
| 218 | + margin: auto; | |
| 219 | + width: 3rem; | |
| 220 | + height: 3rem; | |
| 221 | + background-image: url("../assets/loading.png"); | |
| 222 | + background-size: cover; | |
| 223 | + background-color: #000000; | |
| 224 | +} | |
| 225 | + | |
| 226 | +.video-item-title { | |
| 227 | + position: absolute; | |
| 228 | + bottom: 0; | |
| 229 | + color: #000000; | |
| 230 | + background-color: #ffffff; | |
| 231 | + line-height: 1.5rem; | |
| 232 | + padding: 0.3rem; | |
| 233 | + width: 14.4rem; | |
| 234 | +} | |
| 235 | + | |
| 236 | +</style> | ... | ... |
web_src/src/components/channelList.vue
| ... | ... | @@ -32,7 +32,7 @@ |
| 32 | 32 | <el-button v-if="!showTree" icon="iconfont icon-tree" circle size="mini" @click="switchTree()"></el-button> |
| 33 | 33 | </div> |
| 34 | 34 | </div> |
| 35 | - <devicePlayer ref="devicePlayer" v-loading="isLoging"></devicePlayer> | |
| 35 | + <devicePlayer ref="devicePlayer" ></devicePlayer> | |
| 36 | 36 | <el-container v-loading="isLoging" style="height: 82vh;"> |
| 37 | 37 | <el-aside width="auto" style="height: 82vh; background-color: #ffffff; overflow: auto" v-if="showTree" > |
| 38 | 38 | <DeviceTree ref="deviceTree" :device="device" :onlyCatalog="true" :clickEvent="treeNodeClickEvent" ></DeviceTree> |
| ... | ... | @@ -124,7 +124,6 @@ |
| 124 | 124 | import devicePlayer from './dialog/devicePlayer.vue' |
| 125 | 125 | import uiHeader from '../layout/UiHeader.vue' |
| 126 | 126 | import moment from "moment"; |
| 127 | -import DviceService from "./service/DeviceService"; | |
| 128 | 127 | import DeviceService from "./service/DeviceService"; |
| 129 | 128 | import DeviceTree from "./common/DeviceTree"; |
| 130 | 129 | |
| ... | ... | @@ -318,7 +317,7 @@ export default { |
| 318 | 317 | changeSubchannel(itemData) { |
| 319 | 318 | this.beforeUrl = this.$router.currentRoute.path; |
| 320 | 319 | |
| 321 | - var url = `/${this.$router.currentRoute.name}/${this.$router.currentRoute.params.deviceId}/${itemData.channelId}/${this.$router.currentRoute.params.count}/1` | |
| 320 | + var url = `/${this.$router.currentRoute.name}/${this.$router.currentRoute.params.deviceId}/${itemData.channelId}` | |
| 322 | 321 | this.$router.push(url).then(() => { |
| 323 | 322 | this.searchSrt = ""; |
| 324 | 323 | this.channelType = ""; | ... | ... |
web_src/src/components/common/jessibuca.vue
| ... | ... | @@ -5,8 +5,8 @@ |
| 5 | 5 | <i v-if="!playing" class="iconfont icon-play jessibuca-btn" @click="playBtnClick"></i> |
| 6 | 6 | <i v-if="playing" class="iconfont icon-pause jessibuca-btn" @click="pause"></i> |
| 7 | 7 | <i class="iconfont icon-stop jessibuca-btn" @click="destroy"></i> |
| 8 | - <i v-if="isNotMute" class="iconfont icon-audio-high jessibuca-btn" @click="jessibuca.mute()"></i> | |
| 9 | - <i v-if="!isNotMute" class="iconfont icon-audio-mute jessibuca-btn" @click="jessibuca.cancelMute()"></i> | |
| 8 | + <i v-if="isNotMute" class="iconfont icon-audio-high jessibuca-btn" @click="mute()"></i> | |
| 9 | + <i v-if="!isNotMute" class="iconfont icon-audio-mute jessibuca-btn" @click="cancelMute()"></i> | |
| 10 | 10 | </div> |
| 11 | 11 | <div class="buttons-box-right"> |
| 12 | 12 | <span class="jessibuca-btn">{{ kBps }} kb/s</span> |
| ... | ... | @@ -243,6 +243,16 @@ export default { |
| 243 | 243 | this.err = ""; |
| 244 | 244 | this.performance = ""; |
| 245 | 245 | }, |
| 246 | + mute: function () { | |
| 247 | + if (jessibucaPlayer[this._uid]) { | |
| 248 | + jessibucaPlayer[this._uid].mute(); | |
| 249 | + } | |
| 250 | + }, | |
| 251 | + cancelMute: function () { | |
| 252 | + if (jessibucaPlayer[this._uid]) { | |
| 253 | + jessibucaPlayer[this._uid].cancelMute(); | |
| 254 | + } | |
| 255 | + }, | |
| 246 | 256 | destroy: function () { |
| 247 | 257 | if (jessibucaPlayer[this._uid]) { |
| 248 | 258 | jessibucaPlayer[this._uid].destroy(); | ... | ... |
web_src/src/components/control.vue
| ... | ... | @@ -324,7 +324,7 @@ export default { |
| 324 | 324 | */ |
| 325 | 325 | getThreadsLoad: function () { |
| 326 | 326 | let that = this; |
| 327 | - if (that.mediaServerChoose != null) { | |
| 327 | + if (!!that.mediaServerChoose) { | |
| 328 | 328 | this.$axios({ |
| 329 | 329 | method: 'get', |
| 330 | 330 | url: '/zlm/' + that.mediaServerChoose + '/index/api/getThreadsLoad' |
| ... | ... | @@ -375,7 +375,7 @@ export default { |
| 375 | 375 | }, |
| 376 | 376 | getLoadCount: function () { |
| 377 | 377 | let that = this; |
| 378 | - if (that.mediaServerChoose != null) { | |
| 378 | + if (!!that.mediaServerChoose) { | |
| 379 | 379 | that.mediaServer.getMediaServer(that.mediaServerChoose, (data) => { |
| 380 | 380 | if (data.code == 0) { |
| 381 | 381 | that.loadCount = data.data.count |
| ... | ... | @@ -473,42 +473,46 @@ export default { |
| 473 | 473 | }, |
| 474 | 474 | |
| 475 | 475 | getAllSession: function () { |
| 476 | - let that = this; | |
| 477 | - that.allSessionData = []; | |
| 478 | - this.$axios({ | |
| 479 | - method: 'get', | |
| 480 | - url: '/zlm/' + that.mediaServerChoose + '/index/api/getAllSession' | |
| 481 | - }).then(function (res) { | |
| 482 | - res.data.data.forEach(item => { | |
| 483 | - let data = { | |
| 484 | - peer_ip: item.peer_ip, | |
| 485 | - local_ip: item.local_ip, | |
| 486 | - typeid: item.typeid, | |
| 487 | - id: item.id | |
| 488 | - }; | |
| 489 | - that.allSessionData.push(data); | |
| 476 | + this.allSessionData = []; | |
| 477 | + if (!!this.mediaServerChoose) { | |
| 478 | + this.$axios({ | |
| 479 | + method: 'get', | |
| 480 | + url: '/zlm/' + this.mediaServerChoose + '/index/api/getAllSession' | |
| 481 | + }).then((res)=> { | |
| 482 | + res.data.data.forEach(item => { | |
| 483 | + let data = { | |
| 484 | + peer_ip: item.peer_ip, | |
| 485 | + local_ip: item.local_ip, | |
| 486 | + typeid: item.typeid, | |
| 487 | + id: item.id | |
| 488 | + }; | |
| 489 | + this.allSessionData.push(data); | |
| 490 | + }); | |
| 490 | 491 | }); |
| 491 | - }); | |
| 492 | + } | |
| 493 | + | |
| 492 | 494 | }, |
| 493 | 495 | getServerConfig: function () { |
| 494 | - let that = this; | |
| 495 | - this.$axios({ | |
| 496 | - method: 'get', | |
| 497 | - url: '/zlm/' + that.mediaServerChoose + '/index/api/getServerConfig' | |
| 498 | - }).then(function (res) { | |
| 499 | - let info = res.data.data[0]; | |
| 500 | - let serverInfo = {} | |
| 501 | - for (let i = 0; i < Object.keys(info).length; i++) { | |
| 502 | - let key = Object.keys(info)[i]; | |
| 503 | - let group = key.substring(0, key.indexOf(".")) | |
| 504 | - let itemKey = key.substring(key.indexOf(".") + 1) | |
| 505 | - if (!serverInfo[group]) serverInfo[group] = {} | |
| 506 | - serverInfo[group][itemKey] = info[key] | |
| 507 | - } | |
| 496 | + if (!!this.mediaServerChoose) { | |
| 497 | + this.$axios({ | |
| 498 | + method: 'get', | |
| 499 | + url: '/zlm/' + this.mediaServerChoose + '/index/api/getServerConfig' | |
| 500 | + }).then((res)=> { | |
| 501 | + let info = res.data.data[0]; | |
| 502 | + let serverInfo = {} | |
| 503 | + for (let i = 0; i < Object.keys(info).length; i++) { | |
| 504 | + let key = Object.keys(info)[i]; | |
| 505 | + let group = key.substring(0, key.indexOf(".")) | |
| 506 | + let itemKey = key.substring(key.indexOf(".") + 1) | |
| 507 | + if (!serverInfo[group]) serverInfo[group] = {} | |
| 508 | + serverInfo[group][itemKey] = info[key] | |
| 509 | + } | |
| 510 | + | |
| 511 | + this.serverConfig = serverInfo; | |
| 512 | + this.visible = true; | |
| 513 | + }); | |
| 514 | + } | |
| 508 | 515 | |
| 509 | - that.serverConfig = serverInfo; | |
| 510 | - that.visible = true; | |
| 511 | - }); | |
| 512 | 516 | }, |
| 513 | 517 | getWVPServerConfig: function () { |
| 514 | 518 | let that = this; |
| ... | ... | @@ -531,6 +535,14 @@ export default { |
| 531 | 535 | }, |
| 532 | 536 | reStartServer: function () { |
| 533 | 537 | let that = this; |
| 538 | + if (!!!this.mediaServerChoose) { | |
| 539 | + this.$message({ | |
| 540 | + type: 'info', | |
| 541 | + message: '未选择节点' | |
| 542 | + }); | |
| 543 | + return; | |
| 544 | + } | |
| 545 | + | |
| 534 | 546 | this.$confirm('此操作将重启媒体服务器, 是否继续?', '提示', { |
| 535 | 547 | confirmButtonText: '确定', |
| 536 | 548 | cancelButtonText: '取消', |
| ... | ... | @@ -571,17 +583,19 @@ export default { |
| 571 | 583 | console.log(JSON.stringify(tabledata[index])); |
| 572 | 584 | }, |
| 573 | 585 | deleteSession: function (id) { |
| 574 | - let that = this; | |
| 575 | - this.$axios({ | |
| 576 | - method: 'get', | |
| 577 | - url: '/zlm/' + that.mediaServerChoose + '/index/api/kick_session?id=' + id | |
| 578 | - }).then(function (res) { | |
| 579 | - that.getAllSession(); | |
| 580 | - that.$message({ | |
| 581 | - type: 'success', | |
| 582 | - message: '删除成功!' | |
| 586 | + if (!!this.mediaServerChoose) { | |
| 587 | + this.$axios({ | |
| 588 | + method: 'get', | |
| 589 | + url: '/zlm/' + this.mediaServerChoose + '/index/api/kick_session?id=' + id | |
| 590 | + }).then((res)=>{ | |
| 591 | + this.getAllSession(); | |
| 592 | + this.$message({ | |
| 593 | + type: 'success', | |
| 594 | + message: '删除成功!' | |
| 595 | + }); | |
| 583 | 596 | }); |
| 584 | - }); | |
| 597 | + } | |
| 598 | + | |
| 585 | 599 | }, |
| 586 | 600 | getNameFromKey: function (key) { |
| 587 | 601 | let nameData = { | ... | ... |
web_src/src/components/dialog/SyncChannelProgress.vue
| ... | ... | @@ -63,34 +63,39 @@ export default { |
| 63 | 63 | } |
| 64 | 64 | |
| 65 | 65 | if (res.data.data != null) { |
| 66 | - if (res.data.data.total == 0) { | |
| 67 | - if (res.data.data.errorMsg !== null ){ | |
| 68 | - this.msg = res.data.data.errorMsg; | |
| 69 | - this.syncStatus = "exception" | |
| 70 | - }else { | |
| 71 | - this.msg = `等待同步中`; | |
| 72 | - this.timmer = setTimeout(this.getProgress, 300) | |
| 73 | - } | |
| 74 | - }else { | |
| 75 | - if (res.data.data.total == res.data.data.current) { | |
| 76 | - this.syncStatus = "success" | |
| 77 | - this.percentage = 100; | |
| 78 | - this.msg = '同步成功'; | |
| 79 | - }else { | |
| 66 | + if (res.data.syncIng) { | |
| 67 | + if (res.data.data.total == 0) { | |
| 80 | 68 | if (res.data.data.errorMsg !== null ){ |
| 81 | 69 | this.msg = res.data.data.errorMsg; |
| 82 | 70 | this.syncStatus = "exception" |
| 83 | 71 | }else { |
| 84 | - this.total = res.data.data.total; | |
| 85 | - this.current = res.data.data.current; | |
| 86 | - this.percentage = Math.floor(Number(res.data.data.current)/Number(res.data.data.total)* 10000)/100; | |
| 87 | - this.msg = `同步中...[${res.data.data.current}/${res.data.data.total}]`; | |
| 72 | + this.msg = `等待同步中`; | |
| 88 | 73 | this.timmer = setTimeout(this.getProgress, 300) |
| 89 | 74 | } |
| 75 | + }else { | |
| 76 | + if (res.data.data.total == res.data.data.current) { | |
| 77 | + this.syncStatus = "success" | |
| 78 | + this.percentage = 100; | |
| 79 | + this.msg = '同步成功'; | |
| 80 | + }else { | |
| 81 | + if (res.data.data.errorMsg !== null ){ | |
| 82 | + this.msg = res.data.data.errorMsg; | |
| 83 | + this.syncStatus = "exception" | |
| 84 | + }else { | |
| 85 | + this.total = res.data.data.total; | |
| 86 | + this.current = res.data.data.current; | |
| 87 | + this.percentage = Math.floor(Number(res.data.data.current)/Number(res.data.data.total)* 10000)/100; | |
| 88 | + this.msg = `同步中...[${res.data.data.current}/${res.data.data.total}]`; | |
| 89 | + this.timmer = setTimeout(this.getProgress, 300) | |
| 90 | + } | |
| 91 | + } | |
| 90 | 92 | } |
| 93 | + }else { | |
| 94 | + this.syncStatus = "success" | |
| 95 | + this.percentage = 100; | |
| 96 | + this.msg = '同步成功'; | |
| 91 | 97 | } |
| 92 | 98 | } |
| 93 | - | |
| 94 | 99 | }else { |
| 95 | 100 | if (this.syncFlag) { |
| 96 | 101 | this.syncStatus = "success" | ... | ... |
web_src/src/components/dialog/addUser.vue
0 → 100644
| 1 | +<template> | |
| 2 | + <div id="addUser" v-loading="isLoging"> | |
| 3 | + <el-dialog | |
| 4 | + title="添加用户" | |
| 5 | + width="40%" | |
| 6 | + top="2rem" | |
| 7 | + :close-on-click-modal="false" | |
| 8 | + :visible.sync="showDialog" | |
| 9 | + :destroy-on-close="true" | |
| 10 | + @close="close()" | |
| 11 | + > | |
| 12 | + <div id="shared" style="margin-right: 20px;"> | |
| 13 | + <el-form ref="passwordForm" :rules="rules" status-icon label-width="80px"> | |
| 14 | + <el-form-item label="用户名" prop="username"> | |
| 15 | + <el-input v-model="username" autocomplete="off"></el-input> | |
| 16 | + </el-form-item> | |
| 17 | + <el-form-item label="用户类型" prop="roleId" > | |
| 18 | + <el-select v-model="roleId" placeholder="请选择" style="width: 100%"> | |
| 19 | + <el-option | |
| 20 | + v-for="item in options" | |
| 21 | + :key="item.id" | |
| 22 | + :label="item.name" | |
| 23 | + :value="item.id"> | |
| 24 | + </el-option> | |
| 25 | + </el-select> | |
| 26 | + </el-form-item> | |
| 27 | + <el-form-item label="密码" prop="password"> | |
| 28 | + <el-input v-model="password" autocomplete="off"></el-input> | |
| 29 | + </el-form-item> | |
| 30 | + <el-form-item label="确认密码" prop="confirmPassword"> | |
| 31 | + <el-input v-model="confirmPassword" autocomplete="off"></el-input> | |
| 32 | + </el-form-item> | |
| 33 | + | |
| 34 | + <el-form-item> | |
| 35 | + <div style="float: right;"> | |
| 36 | + <el-button type="primary" @click="onSubmit">保存</el-button> | |
| 37 | + <el-button @click="close">取消</el-button> | |
| 38 | + </div> | |
| 39 | + </el-form-item> | |
| 40 | + </el-form> | |
| 41 | + </div> | |
| 42 | + </el-dialog> | |
| 43 | + </div> | |
| 44 | +</template> | |
| 45 | + | |
| 46 | +<script> | |
| 47 | + | |
| 48 | +export default { | |
| 49 | + name: "addUser", | |
| 50 | + props: {}, | |
| 51 | + computed: {}, | |
| 52 | + created() { | |
| 53 | + this.getAllRole(); | |
| 54 | + }, | |
| 55 | + data() { | |
| 56 | + let validatePass1 = (rule, value, callback) => { | |
| 57 | + if (value === '') { | |
| 58 | + callback(new Error('请输入新密码')); | |
| 59 | + } else { | |
| 60 | + if (this.confirmPassword !== '') { | |
| 61 | + this.$refs.passwordForm.validateField('confirmPassword'); | |
| 62 | + } | |
| 63 | + callback(); | |
| 64 | + } | |
| 65 | + }; | |
| 66 | + let validatePass2 = (rule, value, callback) => { | |
| 67 | + if (this.confirmPassword === '') { | |
| 68 | + callback(new Error('请再次输入密码')); | |
| 69 | + } else if (this.confirmPassword !== this.password) { | |
| 70 | + callback(new Error('两次输入密码不一致!')); | |
| 71 | + } else { | |
| 72 | + callback(); | |
| 73 | + } | |
| 74 | + }; | |
| 75 | + return { | |
| 76 | + value:"", | |
| 77 | + options: [], | |
| 78 | + loading: false, | |
| 79 | + username: null, | |
| 80 | + password: null, | |
| 81 | + roleId: null, | |
| 82 | + confirmPassword: null, | |
| 83 | + listChangeCallback: null, | |
| 84 | + showDialog: false, | |
| 85 | + isLoging: false, | |
| 86 | + rules: { | |
| 87 | + newPassword: [{required: true, validator: validatePass1, trigger: "blur"}, { | |
| 88 | + pattern: /^(?=.*[a-zA-Z])(?=.*\d)(?=.*[~!@#$%^&*()_+`\-={}:";'<>?,.\/]).{8,20}$/, | |
| 89 | + message: "密码长度在8-20位之间,由字母+数字+特殊字符组成", | |
| 90 | + },], | |
| 91 | + confirmPassword: [{required: true, validator: validatePass2, trigger: "blur"}], | |
| 92 | + }, | |
| 93 | + }; | |
| 94 | + }, | |
| 95 | + methods: { | |
| 96 | + openDialog: function (callback) { | |
| 97 | + this.listChangeCallback = callback; | |
| 98 | + this.showDialog = true; | |
| 99 | + }, | |
| 100 | + onSubmit: function () { | |
| 101 | + this.$axios({ | |
| 102 | + method: 'post', | |
| 103 | + url: "/api/user/add", | |
| 104 | + params: { | |
| 105 | + username: this.username, | |
| 106 | + password: this.password, | |
| 107 | + roleId: this.roleId | |
| 108 | + } | |
| 109 | + }).then((res) => { | |
| 110 | + if (res.data.code === 0) { | |
| 111 | + this.$message({ | |
| 112 | + showClose: true, | |
| 113 | + message: '添加成功', | |
| 114 | + type: 'success', | |
| 115 | + | |
| 116 | + }); | |
| 117 | + this.showDialog = false; | |
| 118 | + this.listChangeCallback() | |
| 119 | + | |
| 120 | + } else { | |
| 121 | + this.$message({ | |
| 122 | + showClose: true, | |
| 123 | + message: res.data.msg, | |
| 124 | + type: 'error' | |
| 125 | + }); | |
| 126 | + } | |
| 127 | + }).catch((error) => { | |
| 128 | + console.error(error) | |
| 129 | + }); | |
| 130 | + }, | |
| 131 | + close: function () { | |
| 132 | + this.showDialog = false; | |
| 133 | + this.password = null; | |
| 134 | + this.confirmPassword = null; | |
| 135 | + this.username = null; | |
| 136 | + this.roleId = null; | |
| 137 | + }, | |
| 138 | + getAllRole:function () { | |
| 139 | + | |
| 140 | + this.$axios({ | |
| 141 | + method: 'get', | |
| 142 | + url: "/api/role/all" | |
| 143 | + }).then((res) => { | |
| 144 | + this.loading = true; | |
| 145 | + console.info(res) | |
| 146 | + res.data | |
| 147 | + console.info(res.data.code) | |
| 148 | + if (res.data.code === 0) { | |
| 149 | + console.info(res.data.data) | |
| 150 | + this.options=res.data.data | |
| 151 | + | |
| 152 | + } | |
| 153 | + }).catch((error) => { | |
| 154 | + console.error(error) | |
| 155 | + }); | |
| 156 | + } | |
| 157 | + }, | |
| 158 | +}; | |
| 159 | +</script> | ... | ... |
web_src/src/components/dialog/catalogEdit.vue
| ... | ... | @@ -49,11 +49,42 @@ export default { |
| 49 | 49 | props: ['platformId'], |
| 50 | 50 | created() {}, |
| 51 | 51 | data() { |
| 52 | + let checkId = (rule, value, callback) => { | |
| 53 | + console.log("checkId") | |
| 54 | + console.log(this.treeType) | |
| 55 | + console.log(rule) | |
| 56 | + console.log(value) | |
| 57 | + console.log(value.length) | |
| 58 | + console.log(this.level) | |
| 59 | + if (!value) { | |
| 60 | + return callback(new Error('编号不能为空')); | |
| 61 | + } | |
| 62 | + if (this.treeType === "BusinessGroup" && value.length !== 20) { | |
| 63 | + return callback(new Error('编号必须由20位数字组成')); | |
| 64 | + } | |
| 65 | + if (this.treeType === "CivilCode" && value.length <= 8 && value.length%2 !== 0) { | |
| 66 | + return callback(new Error('行政区划必须是八位以下的偶数个数字组成')); | |
| 67 | + } | |
| 68 | + if (this.treeType === "BusinessGroup") { | |
| 69 | + let catalogType = value.substring(10, 13); | |
| 70 | + console.log(catalogType) | |
| 71 | + // 216 为虚拟组织 215 为业务分组;目录第一级必须为业务分组, 业务分组下为虚拟组织,虚拟组织下可以有其他虚拟组织 | |
| 72 | + if (this.level === 1 && catalogType !== "215") { | |
| 73 | + return callback(new Error('业务分组模式下第一层目录的编号11到13位必须为215')); | |
| 74 | + } | |
| 75 | + if (this.level > 1 && catalogType !== "216") { | |
| 76 | + return callback(new Error('业务分组模式下第一层以下目录的编号11到13位必须为216')); | |
| 77 | + } | |
| 78 | + } | |
| 79 | + callback(); | |
| 80 | + } | |
| 52 | 81 | return { |
| 53 | 82 | submitCallback: null, |
| 54 | 83 | showDialog: false, |
| 55 | 84 | isLoging: false, |
| 56 | 85 | isEdit: false, |
| 86 | + treeType: null, | |
| 87 | + level: 0, | |
| 57 | 88 | form: { |
| 58 | 89 | id: null, |
| 59 | 90 | name: null, |
| ... | ... | @@ -62,12 +93,12 @@ export default { |
| 62 | 93 | }, |
| 63 | 94 | rules: { |
| 64 | 95 | name: [{ required: true, message: "请输入名称", trigger: "blur" }], |
| 65 | - id: [{ required: true, message: "请输入ID", trigger: "blur" }] | |
| 96 | + id: [{ required: true, trigger: "blur",validator: checkId }] | |
| 66 | 97 | }, |
| 67 | 98 | }; |
| 68 | 99 | }, |
| 69 | 100 | methods: { |
| 70 | - openDialog: function (isEdit, id, name, parentId, callback) { | |
| 101 | + openDialog: function (isEdit, id, name, parentId, treeType, level, callback) { | |
| 71 | 102 | console.log("parentId: " + parentId) |
| 72 | 103 | console.log(this.form) |
| 73 | 104 | this.isEdit = isEdit; |
| ... | ... | @@ -77,6 +108,8 @@ export default { |
| 77 | 108 | this.form.parentId = parentId; |
| 78 | 109 | this.showDialog = true; |
| 79 | 110 | this.submitCallback = callback; |
| 111 | + this.treeType = treeType; | |
| 112 | + this.level = level; | |
| 80 | 113 | }, |
| 81 | 114 | onSubmit: function () { |
| 82 | 115 | console.log("onSubmit"); | ... | ... |
web_src/src/components/dialog/changePasswordForAdmin.vue
0 → 100644
| 1 | +<template> | |
| 2 | + <div id="changePassword" v-loading="isLoging"> | |
| 3 | + <el-dialog | |
| 4 | + title="修改密码" | |
| 5 | + width="40%" | |
| 6 | + top="2rem" | |
| 7 | + :close-on-click-modal="false" | |
| 8 | + :visible.sync="showDialog" | |
| 9 | + :destroy-on-close="true" | |
| 10 | + @close="close()" | |
| 11 | + > | |
| 12 | + <div id="shared" style="margin-right: 20px;"> | |
| 13 | + <el-form ref="passwordForm" :rules="rules" status-icon label-width="80px"> | |
| 14 | + <el-form-item label="新密码" prop="newPassword" > | |
| 15 | + <el-input v-model="newPassword" autocomplete="off"></el-input> | |
| 16 | + </el-form-item> | |
| 17 | + <el-form-item label="确认密码" prop="confirmPassword"> | |
| 18 | + <el-input v-model="confirmPassword" autocomplete="off"></el-input> | |
| 19 | + </el-form-item> | |
| 20 | + | |
| 21 | + <el-form-item> | |
| 22 | + <div style="float: right;"> | |
| 23 | + <el-button type="primary" @click="onSubmit">保存</el-button> | |
| 24 | + <el-button @click="close">取消</el-button> | |
| 25 | + </div> | |
| 26 | + </el-form-item> | |
| 27 | + </el-form> | |
| 28 | + </div> | |
| 29 | + </el-dialog> | |
| 30 | + </div> | |
| 31 | +</template> | |
| 32 | + | |
| 33 | +<script> | |
| 34 | +export default { | |
| 35 | + name: "changePasswordForAdmin", | |
| 36 | + props: {}, | |
| 37 | + computed: {}, | |
| 38 | + created() {}, | |
| 39 | + data() { | |
| 40 | + let validatePass1 = (rule, value, callback) => { | |
| 41 | + if (value === '') { | |
| 42 | + callback(new Error('请输入新密码')); | |
| 43 | + } else { | |
| 44 | + if (this.confirmPassword !== '') { | |
| 45 | + this.$refs.passwordForm.validateField('confirmPassword'); | |
| 46 | + } | |
| 47 | + callback(); | |
| 48 | + } | |
| 49 | + }; | |
| 50 | + let validatePass2 = (rule, value, callback) => { | |
| 51 | + if (this.confirmPassword === '') { | |
| 52 | + callback(new Error('请再次输入密码')); | |
| 53 | + } else if (this.confirmPassword !== this.newPassword) { | |
| 54 | + callback(new Error('两次输入密码不一致!')); | |
| 55 | + } else { | |
| 56 | + callback(); | |
| 57 | + } | |
| 58 | + }; | |
| 59 | + return { | |
| 60 | + newPassword: null, | |
| 61 | + confirmPassword: null, | |
| 62 | + userId: null, | |
| 63 | + showDialog: false, | |
| 64 | + isLoging: false, | |
| 65 | + listChangeCallback: null, | |
| 66 | + form: {}, | |
| 67 | + rules: { | |
| 68 | + newPassword: [{ required: true, validator: validatePass1, trigger: "blur" }, { | |
| 69 | + pattern: /^(?=.*[a-zA-Z])(?=.*\d)(?=.*[~!@#$%^&*()_+`\-={}:";'<>?,.\/]).{8,20}$/, | |
| 70 | + message: "密码长度在8-20位之间,由字母+数字+特殊字符组成", | |
| 71 | + },], | |
| 72 | + confirmPassword: [{ required: true, validator: validatePass2, trigger: "blur" }], | |
| 73 | + }, | |
| 74 | + }; | |
| 75 | + }, | |
| 76 | + methods: { | |
| 77 | + openDialog: function (row, callback) { | |
| 78 | + console.log(row) | |
| 79 | + this.showDialog = true; | |
| 80 | + this.listChangeCallback = callback; | |
| 81 | + if (row != null) { | |
| 82 | + this.form = row; | |
| 83 | + } | |
| 84 | + }, | |
| 85 | + onSubmit: function () { | |
| 86 | + this.$axios({ | |
| 87 | + method: 'post', | |
| 88 | + url:"/api/user/changePasswordForAdmin", | |
| 89 | + params: { | |
| 90 | + password: this.newPassword, | |
| 91 | + userId: this.form.id, | |
| 92 | + } | |
| 93 | + }).then((res)=> { | |
| 94 | + if (res.data === "success"){ | |
| 95 | + this.$message({ | |
| 96 | + showClose: true, | |
| 97 | + message: '修改成功', | |
| 98 | + type: 'success' | |
| 99 | + }); | |
| 100 | + this.showDialog = false; | |
| 101 | + }else { | |
| 102 | + this.$message({ | |
| 103 | + showClose: true, | |
| 104 | + message: '修改密码失败,是否已登录(接口鉴权关闭无法修改密码)', | |
| 105 | + type: 'error' | |
| 106 | + }); | |
| 107 | + } | |
| 108 | + }).catch((error)=> { | |
| 109 | + console.error(error) | |
| 110 | + }); | |
| 111 | + }, | |
| 112 | + close: function () { | |
| 113 | + this.showDialog = false; | |
| 114 | + this.newPassword = null; | |
| 115 | + this.confirmPassword = null; | |
| 116 | + this.userId=null; | |
| 117 | + this.adminId=null; | |
| 118 | + }, | |
| 119 | + }, | |
| 120 | +}; | |
| 121 | +</script> | ... | ... |
web_src/src/components/dialog/changePushKey.vue
0 → 100644
| 1 | +<template> | |
| 2 | + <div id="changepushKey" v-loading="isLoging"> | |
| 3 | + <el-dialog | |
| 4 | + title="修改pushKey" | |
| 5 | + width="42%" | |
| 6 | + top="2rem" | |
| 7 | + :close-on-click-modal="false" | |
| 8 | + :visible.sync="showDialog" | |
| 9 | + :destroy-on-close="true" | |
| 10 | + @close="close()" | |
| 11 | + > | |
| 12 | + <div id="shared" style="margin-right: 18px;"> | |
| 13 | + <el-form ref="pushKeyForm" :rules="rules" status-icon label-width="86px"> | |
| 14 | + <el-form-item label="新pushKey" prop="newPushKey" > | |
| 15 | + <el-input v-model="newPushKey" autocomplete="off"></el-input> | |
| 16 | + </el-form-item> | |
| 17 | + <el-form-item> | |
| 18 | + <div style="float: right;"> | |
| 19 | + <el-button type="primary" @click="onSubmit">保存</el-button> | |
| 20 | + <el-button @click="close">取消</el-button> | |
| 21 | + </div> | |
| 22 | + </el-form-item> | |
| 23 | + </el-form> | |
| 24 | + </div> | |
| 25 | + </el-dialog> | |
| 26 | + </div> | |
| 27 | +</template> | |
| 28 | + | |
| 29 | +<script> | |
| 30 | +export default { | |
| 31 | + name: "changePushKey", | |
| 32 | + props: {}, | |
| 33 | + computed: {}, | |
| 34 | + created() {}, | |
| 35 | + data() { | |
| 36 | + let validatePass1 = (rule, value, callback) => { | |
| 37 | + if (value === '') { | |
| 38 | + callback(new Error('请输入新pushKey')); | |
| 39 | + } else { | |
| 40 | + callback(); | |
| 41 | + } | |
| 42 | + }; | |
| 43 | + return { | |
| 44 | + newPushKey: null, | |
| 45 | + confirmpushKey: null, | |
| 46 | + userId: null, | |
| 47 | + showDialog: false, | |
| 48 | + isLoging: false, | |
| 49 | + listChangeCallback: null, | |
| 50 | + form: {}, | |
| 51 | + rules: { | |
| 52 | + newpushKey: [{ required: true, validator: validatePass1, trigger: "blur" }], | |
| 53 | + }, | |
| 54 | + }; | |
| 55 | + }, | |
| 56 | + methods: { | |
| 57 | + openDialog: function (row, callback) { | |
| 58 | + console.log(row) | |
| 59 | + this.showDialog = true; | |
| 60 | + this.listChangeCallback = callback; | |
| 61 | + if (row != null) { | |
| 62 | + this.form = row; | |
| 63 | + } | |
| 64 | + }, | |
| 65 | + onSubmit: function () { | |
| 66 | + this.$axios({ | |
| 67 | + method: 'post', | |
| 68 | + url:"/api/user/changePushKey", | |
| 69 | + params: { | |
| 70 | + pushKey: this.newPushKey, | |
| 71 | + userId: this.form.id, | |
| 72 | + } | |
| 73 | + }).then((res)=> { | |
| 74 | + console.log(res.data) | |
| 75 | + if (res.data.msg === "success"){ | |
| 76 | + this.$message({ | |
| 77 | + showClose: true, | |
| 78 | + message: '修改成功', | |
| 79 | + type: 'success' | |
| 80 | + }); | |
| 81 | + this.showDialog = false; | |
| 82 | + this.listChangeCallback(); | |
| 83 | + }else { | |
| 84 | + this.$message({ | |
| 85 | + showClose: true, | |
| 86 | + message: '修改pushKey失败,是否已登录(接口鉴权关闭无法修改pushKey)', | |
| 87 | + type: 'error' | |
| 88 | + }); | |
| 89 | + } | |
| 90 | + }).catch((error)=> { | |
| 91 | + console.error(error) | |
| 92 | + }); | |
| 93 | + }, | |
| 94 | + close: function () { | |
| 95 | + this.showDialog = false; | |
| 96 | + this.newpushKey = null; | |
| 97 | + this.userId=null; | |
| 98 | + this.adminId=null; | |
| 99 | + }, | |
| 100 | + }, | |
| 101 | +}; | |
| 102 | +</script> | ... | ... |
web_src/src/components/dialog/chooseChannel.vue
| ... | ... | @@ -8,7 +8,7 @@ |
| 8 | 8 | <el-tab-pane label="目录结构" name="catalog"> |
| 9 | 9 | <el-container> |
| 10 | 10 | <el-main v-bind:style="{backgroundColor: '#FFF', maxHeight: winHeight + 'px'}"> |
| 11 | - <chooseChannelForCatalog ref="chooseChannelForCatalog" :platformId=platformId :platformName=platformName :defaultCatalogId=defaultCatalogId :catalogIdChange="catalogIdChange" ></chooseChannelForCatalog> | |
| 11 | + <chooseChannelForCatalog ref="chooseChannelForCatalog" :platformId=platformId :platformName=platformName :defaultCatalogId=defaultCatalogId :catalogIdChange="catalogIdChange" :treeType=treeType ></chooseChannelForCatalog> | |
| 12 | 12 | </el-main> |
| 13 | 13 | </el-container> |
| 14 | 14 | </el-tab-pane> |
| ... | ... | @@ -66,18 +66,20 @@ export default { |
| 66 | 66 | platformName: "", |
| 67 | 67 | defaultCatalogId: "", |
| 68 | 68 | showDialog: false, |
| 69 | + treeType: null, | |
| 69 | 70 | chooseData: {}, |
| 70 | 71 | winHeight: window.innerHeight - 250, |
| 71 | 72 | |
| 72 | 73 | }; |
| 73 | 74 | }, |
| 74 | 75 | methods: { |
| 75 | - openDialog(platformId, platformName, defaultCatalogId, closeCallback) { | |
| 76 | + openDialog(platformId, platformName, defaultCatalogId, treeType, closeCallback) { | |
| 76 | 77 | this.platformId = platformId |
| 77 | 78 | this.platformName = platformName |
| 78 | 79 | this.defaultCatalogId = defaultCatalogId |
| 79 | 80 | this.showDialog = true |
| 80 | 81 | this.closeCallback = closeCallback |
| 82 | + this.treeType = treeType | |
| 81 | 83 | }, |
| 82 | 84 | tabClick (tab, event){ |
| 83 | 85 | ... | ... |
web_src/src/components/dialog/chooseChannelForCatalog.vue
| ... | ... | @@ -38,7 +38,7 @@ |
| 38 | 38 | import catalogEdit from './catalogEdit.vue' |
| 39 | 39 | export default { |
| 40 | 40 | name: 'chooseChannelForCatalog', |
| 41 | - props: ['platformId', 'platformName', 'defaultCatalogId', 'catalogIdChange'], | |
| 41 | + props: ['platformId', 'platformName', 'defaultCatalogId', 'catalogIdChange', 'treeType'], | |
| 42 | 42 | created() { |
| 43 | 43 | this.chooseId = this.defaultCatalogId; |
| 44 | 44 | this.defaultCatalogIdSign = this.defaultCatalogId; |
| ... | ... | @@ -102,8 +102,9 @@ export default { |
| 102 | 102 | }, |
| 103 | 103 | addCatalog: function (parentId, node){ |
| 104 | 104 | let that = this; |
| 105 | + console.log(this.treeType) | |
| 105 | 106 | // 打开添加弹窗 |
| 106 | - that.$refs.catalogEdit.openDialog(false, null, null, parentId, ()=>{ | |
| 107 | + that.$refs.catalogEdit.openDialog(false, null, null, parentId, this.treeType, node.level, ()=>{ | |
| 107 | 108 | node.loaded = false |
| 108 | 109 | node.expand(); |
| 109 | 110 | }); | ... | ... |
web_src/src/components/dialog/chooseChannelForStream.vue
web_src/src/components/dialog/devicePlayer.vue
| ... | ... | @@ -388,7 +388,7 @@ export default { |
| 388 | 388 | url: '/zlm/' +this.mediaServerId+ '/index/api/getMediaInfo?vhost=__defaultVhost__&schema=rtmp&app='+ this.app +'&stream='+ this.streamId |
| 389 | 389 | }).then(function (res) { |
| 390 | 390 | that.tracksLoading = false; |
| 391 | - if (res.data.code == 0 && res.data.online) { | |
| 391 | + if (res.data.code == 0 && res.data.tracks) { | |
| 392 | 392 | that.tracks = res.data.tracks; |
| 393 | 393 | }else{ |
| 394 | 394 | that.tracksNotLoaded = true; | ... | ... |
web_src/src/components/dialog/platformEdit.vue
| ... | ... | @@ -78,6 +78,12 @@ |
| 78 | 78 | <el-option label="8" value="8"></el-option> |
| 79 | 79 | </el-select> |
| 80 | 80 | </el-form-item> |
| 81 | + <el-form-item label="目录结构" prop="treeType" > | |
| 82 | + <el-select v-model="platform.treeType" style="width: 100%" > | |
| 83 | + <el-option key="WGS84" label="行政区划" value="CivilCode"></el-option> | |
| 84 | + <el-option key="GCJ02" label="业务分组" value="BusinessGroup"></el-option> | |
| 85 | + </el-select> | |
| 86 | + </el-form-item> | |
| 81 | 87 | <el-form-item label="字符集" prop="characterSet"> |
| 82 | 88 | <el-select |
| 83 | 89 | v-model="platform.characterSet" |
| ... | ... | @@ -91,7 +97,6 @@ |
| 91 | 97 | <el-form-item label="其他选项"> |
| 92 | 98 | <el-checkbox label="启用" v-model="platform.enable" @change="checkExpires"></el-checkbox> |
| 93 | 99 | <el-checkbox label="云台控制" v-model="platform.ptz"></el-checkbox> |
| 94 | - <el-checkbox label="共享所有直播流" v-model="platform.shareAllLiveStream"></el-checkbox> | |
| 95 | 100 | <el-checkbox label="拉起离线推流" v-model="platform.startOfflinePush"></el-checkbox> |
| 96 | 101 | </el-form-item> |
| 97 | 102 | <el-form-item> |
| ... | ... | @@ -153,10 +158,10 @@ export default { |
| 153 | 158 | keepTimeout: 60, |
| 154 | 159 | transport: "UDP", |
| 155 | 160 | characterSet: "GB2312", |
| 156 | - shareAllLiveStream: false, | |
| 157 | 161 | startOfflinePush: false, |
| 158 | 162 | catalogGroup: 1, |
| 159 | 163 | administrativeDivision: null, |
| 164 | + treeType: "BusinessGroup", | |
| 160 | 165 | }, |
| 161 | 166 | rules: { |
| 162 | 167 | name: [{ required: true, message: "请输入平台名称", trigger: "blur" }], |
| ... | ... | @@ -194,6 +199,7 @@ export default { |
| 194 | 199 | that.platform.devicePort = res.data.devicePort; |
| 195 | 200 | that.platform.username = res.data.username; |
| 196 | 201 | that.platform.password = res.data.password; |
| 202 | + that.platform.treeType = "BusinessGroup"; | |
| 197 | 203 | that.platform.administrativeDivision = res.data.username.substr(0, 6); |
| 198 | 204 | }).catch(function (error) { |
| 199 | 205 | console.log(error); |
| ... | ... | @@ -217,11 +223,11 @@ export default { |
| 217 | 223 | this.platform.keepTimeout = platform.keepTimeout; |
| 218 | 224 | this.platform.transport = platform.transport; |
| 219 | 225 | this.platform.characterSet = platform.characterSet; |
| 220 | - this.platform.shareAllLiveStream = platform.shareAllLiveStream; | |
| 221 | 226 | this.platform.catalogId = platform.catalogId; |
| 222 | 227 | this.platform.startOfflinePush = platform.startOfflinePush; |
| 223 | 228 | this.platform.catalogGroup = platform.catalogGroup; |
| 224 | 229 | this.platform.administrativeDivision = platform.administrativeDivision; |
| 230 | + this.platform.treeType = platform.treeType; | |
| 225 | 231 | this.onSubmit_text = "保存"; |
| 226 | 232 | this.saveUrl = "/api/platform/save"; |
| 227 | 233 | } |
| ... | ... | @@ -242,32 +248,49 @@ export default { |
| 242 | 248 | |
| 243 | 249 | }, |
| 244 | 250 | onSubmit: function () { |
| 251 | + if (this.onSubmit_text === "保存") { | |
| 252 | + this.$confirm("修改目录结构会导致关联目录与通道数据被清空", '提示', { | |
| 253 | + dangerouslyUseHTMLString: true, | |
| 254 | + confirmButtonText: '确定', | |
| 255 | + cancelButtonText: '取消', | |
| 256 | + center: true, | |
| 257 | + type: 'warning' | |
| 258 | + }).then(() => { | |
| 259 | + this.saveForm() | |
| 260 | + }).catch(() => { | |
| 261 | + | |
| 262 | + }); | |
| 263 | + }else { | |
| 264 | + this.saveForm() | |
| 265 | + } | |
| 266 | + }, | |
| 267 | + saveForm: function (){ | |
| 245 | 268 | var that = this; |
| 246 | 269 | that.$axios({ |
| 247 | 270 | method: 'post', |
| 248 | 271 | url: this.saveUrl, |
| 249 | 272 | data: that.platform |
| 250 | 273 | }).then(function (res) { |
| 251 | - if (res.data.code === 0) { | |
| 252 | - that.$message({ | |
| 253 | - showClose: true, | |
| 254 | - message: "保存成功", | |
| 255 | - type: "success", | |
| 256 | - }); | |
| 257 | - that.showDialog = false; | |
| 258 | - if (that.listChangeCallback != null) { | |
| 259 | - that.listChangeCallback(); | |
| 260 | - } | |
| 261 | - }else { | |
| 262 | - that.$message({ | |
| 263 | - showClose: true, | |
| 264 | - message: res.data.msg, | |
| 265 | - type: "error", | |
| 266 | - }); | |
| 274 | + if (res.data.code === 0) { | |
| 275 | + that.$message({ | |
| 276 | + showClose: true, | |
| 277 | + message: "保存成功", | |
| 278 | + type: "success", | |
| 279 | + }); | |
| 280 | + that.showDialog = false; | |
| 281 | + if (that.listChangeCallback != null) { | |
| 282 | + that.listChangeCallback(); | |
| 267 | 283 | } |
| 268 | - }).catch(function (error) { | |
| 269 | - console.log(error); | |
| 270 | - }); | |
| 284 | + }else { | |
| 285 | + that.$message({ | |
| 286 | + showClose: true, | |
| 287 | + message: res.data.msg, | |
| 288 | + type: "error", | |
| 289 | + }); | |
| 290 | + } | |
| 291 | + }).catch(function (error) { | |
| 292 | + console.log(error); | |
| 293 | + }); | |
| 271 | 294 | }, |
| 272 | 295 | close: function () { |
| 273 | 296 | this.showDialog = false; |
| ... | ... | @@ -293,7 +316,7 @@ export default { |
| 293 | 316 | keepTimeout: 60, |
| 294 | 317 | transport: "UDP", |
| 295 | 318 | characterSet: "GB2312", |
| 296 | - shareAllLiveStream: false, | |
| 319 | + treeType: "BusinessGroup", | |
| 297 | 320 | startOfflinePush: false, |
| 298 | 321 | catalogGroup: 1, |
| 299 | 322 | } | ... | ... |
web_src/src/components/dialog/addStreamTOGB.vue renamed to web_src/src/components/dialog/pushStreamEdit.vue
| ... | ... | @@ -15,20 +15,25 @@ |
| 15 | 15 | <el-input v-model="proxyParam.name" clearable></el-input> |
| 16 | 16 | </el-form-item> |
| 17 | 17 | <el-form-item label="流应用名" prop="app"> |
| 18 | - <el-input v-model="proxyParam.app" clearable :disabled="true"></el-input> | |
| 18 | + <el-input v-model="proxyParam.app" clearable :disabled="edit"></el-input> | |
| 19 | 19 | </el-form-item> |
| 20 | 20 | <el-form-item label="流ID" prop="stream"> |
| 21 | - <el-input v-model="proxyParam.stream" clearable :disabled="true"></el-input> | |
| 21 | + <el-input v-model="proxyParam.stream" clearable :disabled="edit"></el-input> | |
| 22 | 22 | </el-form-item> |
| 23 | 23 | <el-form-item label="国标编码" prop="gbId"> |
| 24 | 24 | <el-input v-model="proxyParam.gbId" placeholder="设置国标编码可推送到国标" clearable></el-input> |
| 25 | 25 | </el-form-item> |
| 26 | + <el-form-item label="经度" prop="longitude" v-if="proxyParam.gbId"> | |
| 27 | + <el-input v-model="proxyParam.longitude" placeholder="经度" clearable></el-input> | |
| 28 | + </el-form-item> | |
| 29 | + <el-form-item label="纬度" prop="latitude" v-if="proxyParam.gbId"> | |
| 30 | + <el-input v-model="proxyParam.latitude" placeholder="经度" clearable></el-input> | |
| 31 | + </el-form-item> | |
| 26 | 32 | <el-form-item> |
| 27 | 33 | <div style="float: right;"> |
| 28 | 34 | <el-button type="primary" @click="onSubmit">保存</el-button> |
| 29 | 35 | <el-button @click="close">取消</el-button> |
| 30 | 36 | </div> |
| 31 | - | |
| 32 | 37 | </el-form-item> |
| 33 | 38 | </el-form> |
| 34 | 39 | </div> |
| ... | ... | @@ -38,7 +43,7 @@ |
| 38 | 43 | |
| 39 | 44 | <script> |
| 40 | 45 | export default { |
| 41 | - name: "streamProxyEdit", | |
| 46 | + name: "pushStreamEdit", | |
| 42 | 47 | props: {}, |
| 43 | 48 | computed: {}, |
| 44 | 49 | created() {}, |
| ... | ... | @@ -63,13 +68,15 @@ export default { |
| 63 | 68 | listChangeCallback: null, |
| 64 | 69 | showDialog: false, |
| 65 | 70 | isLoging: false, |
| 71 | + edit: false, | |
| 66 | 72 | proxyParam: { |
| 67 | 73 | name: null, |
| 68 | 74 | app: null, |
| 69 | 75 | stream: null, |
| 70 | 76 | gbId: null, |
| 77 | + longitude: null, | |
| 78 | + latitude: null, | |
| 71 | 79 | }, |
| 72 | - | |
| 73 | 80 | rules: { |
| 74 | 81 | name: [{ required: true, message: "请输入名称", trigger: "blur" }], |
| 75 | 82 | app: [{ required: true, message: "请输入应用名", trigger: "blur" }], |
| ... | ... | @@ -84,30 +91,63 @@ export default { |
| 84 | 91 | this.listChangeCallback = callback; |
| 85 | 92 | if (proxyParam != null) { |
| 86 | 93 | this.proxyParam = proxyParam; |
| 87 | - } | |
| 94 | + this.edit = true | |
| 95 | + }else{ | |
| 96 | + this.proxyParam= { | |
| 97 | + name: null, | |
| 98 | + app: null, | |
| 99 | + stream: null, | |
| 100 | + gbId: null, | |
| 101 | + longitude: null, | |
| 102 | + latitude: null, | |
| 103 | + } | |
| 104 | + this.edit = false | |
| 105 | + } | |
| 88 | 106 | }, |
| 89 | 107 | onSubmit: function () { |
| 90 | 108 | console.log("onSubmit"); |
| 91 | - var that = this; | |
| 92 | - that.$axios({ | |
| 93 | - method:"post", | |
| 94 | - url:`/api/push/save_to_gb`, | |
| 95 | - data: that.proxyParam | |
| 96 | - }).then(function (res) { | |
| 109 | + if (this.edit) { | |
| 110 | + this.$axios({ | |
| 111 | + method:"post", | |
| 112 | + url:`/api/push/save_to_gb`, | |
| 113 | + data: this.proxyParam | |
| 114 | + }).then( (res) => { | |
| 97 | 115 | if (res.data == "success") { |
| 98 | - that.$message({ | |
| 116 | + this.$message({ | |
| 99 | 117 | showClose: true, |
| 100 | 118 | message: "保存成功", |
| 101 | 119 | type: "success", |
| 102 | 120 | }); |
| 103 | - that.showDialog = false; | |
| 104 | - if (that.listChangeCallback != null) { | |
| 105 | - that.listChangeCallback(); | |
| 121 | + this.showDialog = false; | |
| 122 | + if (this.listChangeCallback != null) { | |
| 123 | + this.listChangeCallback(); | |
| 106 | 124 | } |
| 107 | 125 | } |
| 108 | - }).catch(function (error) { | |
| 126 | + }).catch((error)=> { | |
| 109 | 127 | console.log(error); |
| 110 | - }); | |
| 128 | + }); | |
| 129 | + }else { | |
| 130 | + this.$axios({ | |
| 131 | + method:"post", | |
| 132 | + url:`/api/push/add`, | |
| 133 | + data: this.proxyParam | |
| 134 | + }).then( (res) => { | |
| 135 | + if (res.data.code === 0) { | |
| 136 | + this.$message({ | |
| 137 | + showClose: true, | |
| 138 | + message: "保存成功", | |
| 139 | + type: "success", | |
| 140 | + }); | |
| 141 | + this.showDialog = false; | |
| 142 | + if (this.listChangeCallback != null) { | |
| 143 | + this.listChangeCallback(); | |
| 144 | + } | |
| 145 | + } | |
| 146 | + }).catch((error)=> { | |
| 147 | + console.log(error); | |
| 148 | + }); | |
| 149 | + } | |
| 150 | + | |
| 111 | 151 | }, |
| 112 | 152 | close: function () { |
| 113 | 153 | console.log("关闭加入GB"); |
| ... | ... | @@ -131,6 +171,9 @@ export default { |
| 131 | 171 | if (this.platform.enable && this.platform.expires == "0") { |
| 132 | 172 | this.platform.expires = "300"; |
| 133 | 173 | } |
| 174 | + }, | |
| 175 | + handleNodeClick: function (node){ | |
| 176 | + | |
| 134 | 177 | } |
| 135 | 178 | }, |
| 136 | 179 | }; | ... | ... |
web_src/src/layout/UiHeader.vue
| ... | ... | @@ -13,6 +13,7 @@ |
| 13 | 13 | <el-menu-item index="/cloudRecord">云端录像</el-menu-item> |
| 14 | 14 | <el-menu-item index="/mediaServerManger">节点管理</el-menu-item> |
| 15 | 15 | <el-menu-item index="/parentPlatformList/15/1">国标级联</el-menu-item> |
| 16 | + <el-menu-item v-if="editUser" index="/userManager">用户管理</el-menu-item> | |
| 16 | 17 | |
| 17 | 18 | <!-- <el-submenu index="/setting">--> |
| 18 | 19 | <!-- <template slot="title">系统设置</template>--> |
| ... | ... | @@ -47,9 +48,11 @@ export default { |
| 47 | 48 | alarmNotify: false, |
| 48 | 49 | sseSource: null, |
| 49 | 50 | activeIndex: this.$route.path, |
| 51 | + editUser: this.$cookies.get("session").roleId==1 | |
| 50 | 52 | }; |
| 51 | 53 | }, |
| 52 | 54 | created() { |
| 55 | + console.log(this.$cookies.get("session")) | |
| 53 | 56 | if (this.$route.path.startsWith("/channelList")) { |
| 54 | 57 | this.activeIndex = "/deviceList" |
| 55 | 58 | } | ... | ... |
web_src/src/router/index.js
| ... | ... | @@ -17,6 +17,7 @@ import sip from '../components/setting/Sip.vue' |
| 17 | 17 | import media from '../components/setting/Media.vue' |
| 18 | 18 | import live from '../components/live.vue' |
| 19 | 19 | import deviceTree from '../components/common/DeviceTree.vue' |
| 20 | +import userManager from '../components/UserManager.vue' | |
| 20 | 21 | |
| 21 | 22 | import wasmPlayer from '../components/common/jessibuca.vue' |
| 22 | 23 | import rtcPlayer from '../components/dialog/rtcPlayer.vue' |
| ... | ... | @@ -103,6 +104,11 @@ export default new VueRouter({ |
| 103 | 104 | name: 'map', |
| 104 | 105 | component: map, |
| 105 | 106 | }, |
| 107 | + { | |
| 108 | + path: '/userManager', | |
| 109 | + name: 'userManager', | |
| 110 | + component: userManager, | |
| 111 | + } | |
| 106 | 112 | ] |
| 107 | 113 | }, |
| 108 | 114 | { | ... | ... |
web_src/static/file/推流通道导入.zip
No preview for this file type
web_src/static/js/jessibuca/decoder.wasm
100755 → 100644
No preview for this file type