Compare commits

..

No commits in common. "9941608207c23f184a9889135ec64107817bf7a1" and "3a5513a2e63488043588765d31846de1ee415001" have entirely different histories.

529 changed files with 4631 additions and 36529 deletions

View File

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

View File

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

2
.gitignore vendored
View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

137
pom.xml
View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -2,13 +2,13 @@ package com.genersoft.iot.vmp.conf.webLog;
import lombok.extern.slf4j.Slf4j;
import jakarta.websocket.*;
import jakarta.websocket.server.ServerEndpoint;
import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
@ServerEndpoint(value = "/channel/log")
@ServerEndpoint(value = "/channel/log")
@Slf4j
public class LogChannel {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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