Compare commits

...

12 Commits

Author SHA1 Message Date
3d3395e1e2 fix打包 2026-03-25 16:22:18 +08:00
a480b06b63 fix 2026-03-24 10:27:54 +08:00
10444f0a67 解决401 2026-03-24 10:20:53 +08:00
996d6bed35 Initial commit 2026-03-24 02:18:45 +00:00
lin
20986f4a48 更新channelMapper以清除流信息 2026-03-19 16:41:31 +08:00
lin
201cec7651 优化callID生成策略 2026-03-18 15:26:01 +08:00
lin
c7904ff897 重构startSendRtpTalk方法 2026-03-17 17:20:38 +08:00
lin
2cca4611c1 更新README.md 2026-03-06 14:17:47 +08:00
648540858
a5674e82cb Merge pull request #2086 from rongzedong/patch-2
Update compile.md ubuntu18的例子中,jre在编译的时候会报错,应该改为jdk。
2026-03-03 16:11:39 +08:00
648540858
70979adf34 Merge pull request #2087 from rongzedong/patch-3
Update Lombok version to 1.18.38
2026-03-02 10:51:24 +08:00
rongzedong
62eff3746c Update Lombok version to 1.18.38
修改 lombok的版本, 两个依赖它的地方版本不同,低版本的报错。改为相同的 1.18.38 就可以了。
2026-02-26 17:20:29 +08:00
rongzedong
1bed6795e0 Update compile.md
ubuntu18的例子中,jre在编译的时候会报错,应该改为jdk。
2026-02-26 17:18:51 +08:00
14 changed files with 145 additions and 54 deletions

36
README.en.md Normal file
View File

@@ -0,0 +1,36 @@
# wvp-pro
#### Description
{**When you're done, you can delete the content in this README and update the file with details for others getting started with your repository**}
#### Software Architecture
Software architecture description
#### Installation
1. xxxx
2. xxxx
3. xxxx
#### Instructions
1. xxxx
2. xxxx
3. xxxx
#### Contribution
1. Fork the repository
2. Create Feat_xxx branch
3. Commit your code
4. Create Pull Request
#### Gitee Feature
1. You can use Readme\_XXX.md to support different languages, such as Readme\_en.md, Readme\_zh.md
2. Gitee blog [blog.gitee.com](https://blog.gitee.com)
3. Explore open source project [https://gitee.com/explore](https://gitee.com/explore)
4. The most valuable open source project [GVP](https://gitee.com/gvp)
5. The manual of Gitee [https://gitee.com/help](https://gitee.com/help)
6. The most popular members [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)

View File

@@ -160,10 +160,6 @@ https://gitee.com/pan648540858/wvp-GB28181-pro.git
# 付费社群
<img src="doc/_media/shequ.png" width="50%" height="50%">
> 加入三天内不满意可以直接自行推出,星球会直接退款给大家。需要发票可以在星球app中直接咨询星球客服获取。
> 星球还提供了包括闭源的全功能试用包, 会随时更新。
> 付费社群即可以对作者提供支持,也可以为大家更加快速的解决问题。如果暂时无法加入,给项目点个星也是极大的鼓励。

View File

@@ -33,7 +33,7 @@ WVP-PRO使用Spring boot开发maven管理依赖。对于熟悉spring开发的
ubuntu环境以ubuntu 18为例
``` bash
apt-get install -y openjdk-21-jre git maven nodejs npm
apt-get install -y openjdk-21-jdk git maven nodejs npm
```
window环境以windows10为例

10
pom.xml
View File

@@ -33,6 +33,10 @@
<id>ECC</id>
<url>https://maven.ecc.no/releases</url>
</repository>
<repository>
<id>ecc-maven-repo</id>
<url>https://ecc-oss.github.io/maven-repo/</url>
</repository>
</repositories>
<pluginRepositories>
@@ -417,8 +421,10 @@
</dependency>
</dependencies>
<build>
<finalName>${project.artifactId}-${project.version}-${maven.build.timestamp}</finalName>
<finalName>wvp</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
@@ -441,7 +447,7 @@
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.30</version>
<version>1.18.38</version>
</path>
</annotationProcessorPaths>
</configuration>

View File

@@ -101,6 +101,8 @@ public class WebSecurityConfig {
defaultExcludes.add("/index/hook/abl/**");
defaultExcludes.add("/api/jt1078/playback/download");
defaultExcludes.add("/api/jt1078/snap");
defaultExcludes.add("/api/push/list/**");
defaultExcludes.add("/api/push/start/**");
if (userSetting.getInterfaceAuthentication() && !userSetting.getInterfaceAuthenticationExcludes().isEmpty()) {
defaultExcludes.addAll(userSetting.getInterfaceAuthenticationExcludes());

View File

@@ -0,0 +1,53 @@
package com.genersoft.iot.vmp.gb28181.bean;
import lombok.Data;
@Data
public class TalkRtpInfo {
/**
* 应用名, 待推送给设备的流应用名
*/
private String app;
/**
* 流id, 待推送给设备的流id
*/
private String stream;
/**
* rtp推流出去的ssrc
*/
private String ssrc;
/**
* 对方rtp推流上来的流id
*/
private String receiveStreamId;
/**
* 是否推送本地MP4录像该参数非必选参数
*/
private Integer fromMp4;
/**
* 类型: 0(ES流)、1(PS流)、2(TS流)默认1(PS流);该参数非必选参数
*/
private Integer type;
/**
* rtp payload type默认96该参数非必选参数
*/
private Integer pt;
/**
* rtp es方式打包时是否只打包音频该参数非必选参数
*/
private Integer onlyAudio;
/**
* 转发rtp(tcp模式)时如果发送不出去是否限制源端收流速度此参数在多倍速rtp转发时作用较大
*/
private Integer enableOriginReceiveLimit;
}

View File

@@ -145,6 +145,7 @@ public class GbChannelPlayServiceImpl implements IGbChannelPlayService {
throw new PlayException(Response.BUSY_HERE, "channel not support");
}
sourceChannelPlayService.stopPlay(channel);
channelMapper.updateStream(channel.getGbId(), null);
}
@Override

View File

@@ -143,7 +143,7 @@ public class SIPSender {
public CallIdHeader getNewCallIdHeader(String ip, String transport) {
if (ObjectUtils.isEmpty(transport)) {
return sipLayer.getUdpSipProvider().getNewCallId();
return sipLayer.getUdpSipProvider() != null ? sipLayer.getUdpSipProvider().getNewCallId() : sipLayer.getTcpSipProvider().getNewCallId();
}
SipProviderImpl sipProvider;
if (ObjectUtils.isEmpty(ip)) {
@@ -155,7 +155,8 @@ public class SIPSender {
}
if (sipProvider == null) {
sipProvider = sipLayer.getUdpSipProvider();
sipProvider = transport.equalsIgnoreCase("TCP") ? sipLayer.getTcpSipProvider()
: sipLayer.getUdpSipProvider();
}
if (sipProvider != null) {

View File

@@ -10,6 +10,7 @@ import com.genersoft.iot.vmp.conf.SipConfig;
import com.genersoft.iot.vmp.conf.UserSetting;
import com.genersoft.iot.vmp.conf.exception.ControllerException;
import com.genersoft.iot.vmp.gb28181.bean.SendRtpInfo;
import com.genersoft.iot.vmp.gb28181.bean.TalkRtpInfo;
import com.genersoft.iot.vmp.gb28181.service.IInviteStreamService;
import com.genersoft.iot.vmp.media.abl.bean.ABLMedia;
import com.genersoft.iot.vmp.media.abl.bean.ABLResult;
@@ -387,7 +388,7 @@ public class ABLMediaNodeServerService implements IMediaNodeServerService {
}
@Override
public Integer startSendRtpTalk(MediaServer mediaServer, SendRtpInfo sendRtpItem, Integer timeout) {
public Integer startSendRtpTalk(MediaServer mediaServer, TalkRtpInfo talkRtpInfo, Integer timeout) {
logger.warn("[abl-startSendRtpTalk] 未实现");
return 0;
}

View File

@@ -3,6 +3,7 @@ package com.genersoft.iot.vmp.media.service;
import com.genersoft.iot.vmp.common.CommonCallback;
import com.genersoft.iot.vmp.common.StreamInfo;
import com.genersoft.iot.vmp.gb28181.bean.SendRtpInfo;
import com.genersoft.iot.vmp.gb28181.bean.TalkRtpInfo;
import com.genersoft.iot.vmp.media.bean.MediaInfo;
import com.genersoft.iot.vmp.media.bean.MediaServer;
import com.genersoft.iot.vmp.media.bean.RecordInfo;
@@ -67,7 +68,7 @@ public interface IMediaNodeServerService {
void startSendRtpStream(MediaServer mediaServer, SendRtpInfo sendRtpItem);
Integer startSendRtpTalk(MediaServer mediaServer, SendRtpInfo sendRtpItem, Integer timeout);
Integer startSendRtpTalk(MediaServer mediaServer, TalkRtpInfo talkRtpInfo, Integer timeout);
Long updateDownloadProcess(MediaServer mediaServer, String app, String stream);

View File

@@ -3,6 +3,7 @@ package com.genersoft.iot.vmp.media.service;
import com.genersoft.iot.vmp.common.CommonCallback;
import com.genersoft.iot.vmp.common.StreamInfo;
import com.genersoft.iot.vmp.gb28181.bean.SendRtpInfo;
import com.genersoft.iot.vmp.gb28181.bean.TalkRtpInfo;
import com.genersoft.iot.vmp.media.bean.MediaInfo;
import com.genersoft.iot.vmp.media.bean.MediaServer;
import com.genersoft.iot.vmp.media.bean.RecordInfo;
@@ -139,7 +140,7 @@ public interface IMediaServerService {
Integer startSendRtpPassive(MediaServer mediaServer, SendRtpInfo sendRtpItem, Integer timeout);
Integer startSendRtpTalk(MediaServer mediaServer, SendRtpInfo sendRtpItem, Integer timeout);
Integer startSendRtpTalk(MediaServer mediaServer, TalkRtpInfo talkRtpInfo, Integer timeout);
void startSendRtp(MediaServer mediaServer, SendRtpInfo sendRtpItem);

View File

@@ -7,6 +7,7 @@ import com.genersoft.iot.vmp.conf.MediaConfig;
import com.genersoft.iot.vmp.conf.UserSetting;
import com.genersoft.iot.vmp.conf.exception.ControllerException;
import com.genersoft.iot.vmp.gb28181.bean.SendRtpInfo;
import com.genersoft.iot.vmp.gb28181.bean.TalkRtpInfo;
import com.genersoft.iot.vmp.gb28181.service.IInviteStreamService;
import com.genersoft.iot.vmp.gb28181.session.SSRCFactory;
import com.genersoft.iot.vmp.media.bean.MediaInfo;
@@ -24,7 +25,6 @@ import com.genersoft.iot.vmp.media.zlm.dto.hook.OriginType;
import com.genersoft.iot.vmp.service.bean.DownloadFileInfo;
import com.genersoft.iot.vmp.service.bean.ErrorCallback;
import com.genersoft.iot.vmp.service.bean.MediaServerLoad;
import com.genersoft.iot.vmp.service.bean.SSRCInfo;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import com.genersoft.iot.vmp.storager.dao.MediaServerMapper;
import com.genersoft.iot.vmp.streamProxy.bean.StreamProxy;
@@ -32,7 +32,6 @@ import com.genersoft.iot.vmp.utils.DateUtil;
import com.genersoft.iot.vmp.utils.redis.RedisUtil;
import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
import jakarta.validation.constraints.NotNull;
import lombok.extern.slf4j.Slf4j;
import okhttp3.OkHttpClient;
import okhttp3.Request;
@@ -803,15 +802,16 @@ public class MediaServerServiceImpl implements IMediaServerService {
}
@Override
public Integer startSendRtpTalk(MediaServer mediaServer, SendRtpInfo sendRtpItem, Integer timeout) {
public Integer startSendRtpTalk(MediaServer mediaServer, TalkRtpInfo talkRtpInfo, Integer timeout) {
IMediaNodeServerService mediaNodeServerService = nodeServerServiceMap.get(mediaServer.getType());
if (mediaNodeServerService == null) {
log.info("[startSendRtpPassive] 失败, mediaServer的类型 {},未找到对应的实现类", mediaServer.getType());
throw new ControllerException(ErrorCode.ERROR100.getCode(), "未找到mediaServer对应的实现类");
}
return mediaNodeServerService.startSendRtpTalk(mediaServer, sendRtpItem, timeout);
return mediaNodeServerService.startSendRtpTalk(mediaServer, talkRtpInfo, timeout);
}
@Override
public void startSendRtp(MediaServer mediaServer, SendRtpInfo sendRtpItem) {
IMediaNodeServerService mediaNodeServerService = nodeServerServiceMap.get(mediaServer.getType());

View File

@@ -9,6 +9,7 @@ import com.genersoft.iot.vmp.common.enums.MediaApp;
import com.genersoft.iot.vmp.conf.UserSetting;
import com.genersoft.iot.vmp.conf.exception.ControllerException;
import com.genersoft.iot.vmp.gb28181.bean.SendRtpInfo;
import com.genersoft.iot.vmp.gb28181.bean.TalkRtpInfo;
import com.genersoft.iot.vmp.media.bean.MediaInfo;
import com.genersoft.iot.vmp.media.bean.MediaServer;
import com.genersoft.iot.vmp.media.bean.RecordInfo;
@@ -371,17 +372,17 @@ public class ZLMMediaNodeServerService implements IMediaNodeServerService {
}
@Override
public Integer startSendRtpTalk(MediaServer mediaServer, SendRtpInfo sendRtpItem, Integer timeout) {
public Integer startSendRtpTalk(MediaServer mediaServer, TalkRtpInfo talkRtpInfo, Integer timeout) {
Map<String, Object> param = new HashMap<>(12);
param.put("vhost","__defaultVhost__");
param.put("app", sendRtpItem.getApp());
param.put("stream", sendRtpItem.getStream());
param.put("ssrc", sendRtpItem.getSsrc());
param.put("pt", sendRtpItem.getPt());
param.put("type", sendRtpItem.isUsePs() ? "1" : "0");
param.put("only_audio", sendRtpItem.isOnlyAudio() ? "1" : "0");
param.put("recv_stream_id", sendRtpItem.getReceiveStream());
param.put("enable_origin_recv_limit", "1");
param.put("app", talkRtpInfo.getApp());
param.put("stream", talkRtpInfo.getStream());
param.put("ssrc", talkRtpInfo.getSsrc());
param.put("pt", talkRtpInfo.getPt());
param.put("type", talkRtpInfo.getType());
param.put("only_audio", talkRtpInfo.getOnlyAudio());
param.put("recv_stream_id", talkRtpInfo.getReceiveStreamId());
param.put("enable_origin_recv_limit", talkRtpInfo.getEnableOriginReceiveLimit() != null && talkRtpInfo.getEnableOriginReceiveLimit() == 1 ? "1" : "0");
ZLMResult<?> zlmResult = zlmServerFactory.startSendRtpTalk(mediaServer, param, null);
if (zlmResult.getCode() != 0 ) {
log.error("启动监听TCP被动推流失败: {}, 参数:{}", zlmResult.getMsg(), JSON.toJSONString(param));

View File

@@ -16,38 +16,23 @@ spring:
# REDIS数据库配置
redis:
# [必须修改] Redis服务器IP, REDIS安装在本机的,使用127.0.0.1
host: 127.0.0.1
host: 192.168.0.93
# [必须修改] 端口号
port: 6379
# [可选] 数据库 DB
database: 7
database: 8
# [可选] 访问密码,若你的redis服务器没有设置密码就不需要用密码去连接
password: luna
password: qwer12345
# [可选] 超时时间
timeout: 10000
# mysql数据源
datasource:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/wvp273数据库统合?useUnicode=true&characterEncoding=UTF8&rewriteBatchedStatements=true&serverTimezone=PRC&useSSL=false&allowMultiQueries=true&allowPublicKeyRetrieval=true
url: jdbc:mysql://192.168.0.93:3306/wvp?useUnicode=true&characterEncoding=UTF8&rewriteBatchedStatements=true&serverTimezone=PRC&useSSL=false&allowMultiQueries=true&allowPublicKeyRetrieval=true
username: root
password: 12345678
# h2数据库
# datasource:
# driver-class-name: org.h2.Driver
# url: jdbc:h2:mem:wvp
# username: sa
# password: 12345678
# sql:
# init:
# # 启动时仅初始化内置的数据库例如h2:mem
# mode: embedded
# schema-locations: file:数据库/2.7.4-h2/h2-schema.sql
# data-locations: file:数据库/2.7.4-h2/h2-data.sql
# # h2数据库控制台请注意仅在测试环境下使用
# h2:
# console:
# enabled: true
password: qwer12345
#[可选] WVP监听的HTTP端口, 网页和接口调用都是这个端口
server:
port: 18080
@@ -64,6 +49,11 @@ server:
# 作为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
# [可选] 28181服务监听的端口
port: 8116
# 根据国标6.1.2中规定domain宜采用ID统一编码的前十位编码。国标附录D中定义前8位为中心编码由省级、市级、区级、基层编号组成参照GB/T 2260-2007
@@ -80,21 +70,23 @@ sip:
#zlm 默认服务器配置
media:
id: zlmediakit-local
id: yuyi-media
# [必须修改] zlm服务器的内网IP
ip: 192.168.1.10
ip: 192.168.0.93
# [必须修改] zlm服务器的http.port
http-port: 9092
http-port: 8081
# [可选] zlm服务器的hook所使用的IP, 默认使用sip.ip
hook-ip: 192.168.0.93
# [必选选] zlm服务器的hook.admin_params=secret
secret: TWSYFgYJOQWB4ftgeYut8DW4wbs7pQnj
secret: EzrujHJwJoPaR3ruLT1qoB4z6z2RyvLw
# 启用多端口模式, 多端口模式使用端口区分每路流,兼容性更好。 单端口使用流的ssrc区分 点播超时建议使用多端口测试
rtp:
# [可选] 是否启用多端口模式, 开启后会在portRange范围内选择端口用于媒体流传输
enable: true
# [可选] 在此范围内选择端口用于媒体流传输, 必须提前在zlm上配置该属性不然自动配置此属性可能不成功
port-range: 40000,45000 # 端口范围
port-range: 30000,30100 # 端口范围
# [可选] 国标级联在此范围内选择端口发送媒体流,
send-port-range: 50000,55000 # 端口范围
send-port-range: 30000,30100 # 端口范围
# [根据业务需求配置]
user-settings:
# 点播/录像回放 等待超时时间,单位:毫秒
@@ -102,9 +94,9 @@ user-settings:
# [可选] 自动点播, 使用固定流地址进行播放时,如果未点播则自动进行点播, 需要rtp.enable=true
auto-apply-play: true
# 推流直播是否录制
record-push-live: true
record-push-live: false
# 国标是否录制
record-sip: true
record-sip: false
# 国标点播 按需拉流, true有人观看拉流无人观看释放 false拉起后不自动释放
stream-on-demand: true
# 是否返回Date属性true不返回避免摄像头通过该参数自动校时false返回摄像头可能会根据该时间校时