mirror of
https://gitee.com/pan648540858/wvp-GB28181-pro.git
synced 2026-05-26 06:57:50 +08:00
Merge remote-tracking branch 'origin/1078' into 1078
This commit is contained in:
commit
4005a12403
@ -1,6 +1,6 @@
|
|||||||
<!-- 云端录像 -->
|
<!-- 云端录像 -->
|
||||||
# 云端录像
|
# 云端录像
|
||||||
云端录像是对录制在zlm服务下的录像文件的管理,录像的文件路径默认在ZLM/www/record下,使用云端录像功能必须部署wvp-pro-assist,主要通过调用wvp-pro-assist的接口完成各种功能。
|
云端录像是对录制在zlm服务下的录像文件的管理,录像的文件路径默认在ZLM/www/record下。
|
||||||
如果你需要24小时的录像,目前有一个这种方案,可以参考[7*24不间断录像](./_content/ability/continuous_recording.md)。
|
如果你需要24小时的录像,目前有一个这种方案,可以参考[7*24不间断录像](./_content/ability/continuous_recording.md)。
|
||||||
1. 云段录像支持录像文件的查看,播放(可能因为编码的原因导致无法播放);
|
1. 云段录像支持录像文件的查看,播放(可能因为编码的原因导致无法播放);
|
||||||
2. 支持录像的下载;
|
2. 支持录像的下载;
|
||||||
|
|||||||
@ -16,7 +16,6 @@ WVP-PRO使用Spring boot开发,maven管理依赖。对于熟悉spring开发的
|
|||||||
|----------------|------------------------------------------|-------------------------|
|
|----------------|------------------------------------------|-------------------------|
|
||||||
| WVP-PRO | 实现国标28181的信令以及视频平台相关的功能 | 是 |
|
| WVP-PRO | 实现国标28181的信令以及视频平台相关的功能 | 是 |
|
||||||
| ZLMediaKit | 为WVP-PRO提供国标28181的媒体部分的实现,以及各种视频流格式的分发支持 | 是 |
|
| ZLMediaKit | 为WVP-PRO提供国标28181的媒体部分的实现,以及各种视频流格式的分发支持 | 是 |
|
||||||
| wvp-pro-assist | wvp的辅助录像程序,也可单独跟zlm一起使用,提供录像控制,录像合并下载接口 | 否(不安装只是影响云端录像功能和国标录像下载) |
|
|
||||||
|
|
||||||
## 2 安装依赖
|
## 2 安装依赖
|
||||||
| 依赖 | 版本 | 用途 | 开发环境需要 | 生产环境需要 |
|
| 依赖 | 版本 | 用途 | 开发环境需要 | 生产环境需要 |
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
# 部署
|
# 部署
|
||||||
**请仔细阅读以下内容**
|
**请仔细阅读以下内容**
|
||||||
1. WVP-PRO与ZLM支持分开部署,但是wvp-pro-assist必须与zlm部署在同一台主机;
|
1. WVP-PRO与ZLM支持分开部署;
|
||||||
2. 需要开放的端口
|
2. 需要开放的端口
|
||||||
| 服务 | 端口 | 类型 | 必选 |
|
| 服务 | 端口 | 类型 | 必选 |
|
||||||
|-----|:-------------------------|-------------|-------|
|
|-----|:-------------------------|-------------|-------|
|
||||||
@ -18,11 +18,10 @@
|
|||||||
| zlm | rtp.port-range(在wvp中配置) | udp and tcp | 多端口开放 |
|
| zlm | rtp.port-range(在wvp中配置) | udp and tcp | 多端口开放 |
|
||||||
|
|
||||||
3. 测试环境部署建议所有服务部署在一台主机,关闭防火墙,减少因网络出现问题的可能;
|
3. 测试环境部署建议所有服务部署在一台主机,关闭防火墙,减少因网络出现问题的可能;
|
||||||
4. WVP-PRO与ZLM支持分开部署,但是wvp-pro-assist必须与zlm部署在同一台主机;
|
4. 生产环境按需开放端口,但是建议修改默认端口,尤其是5060端口,易受到攻击;
|
||||||
5. 生产环境按需开放端口,但是建议修改默认端口,尤其是5060端口,易受到攻击;
|
5. zlm使用docker部署的情况,要求端口映射一致,比如映射5060,应将外部端口也映射为5060端口;
|
||||||
6. zlm使用docker部署的情况,要求端口映射一致,比如映射5060,应将外部端口也映射为5060端口;
|
6. zlm与wvp会保持高频率的通信,所以不要去将wvp与zlm分属在两个网络,比如wvp在内网,zlm却在公网的情况。
|
||||||
7. zlm与wvp会保持高频率的通信,所以不要去将wvp与zlm分属在两个网络,比如wvp在内网,zlm却在公网的情况。
|
7. 启动服务,以linux为例
|
||||||
8. 启动服务,以linux为例
|
|
||||||
**启动WVP-PRO**
|
**启动WVP-PRO**
|
||||||
```shell
|
```shell
|
||||||
nohup java -jar wvp-pro-*.jar &
|
nohup java -jar wvp-pro-*.jar &
|
||||||
|
|||||||
6
pom.xml
6
pom.xml
@ -11,7 +11,7 @@
|
|||||||
|
|
||||||
<groupId>com.genersoft</groupId>
|
<groupId>com.genersoft</groupId>
|
||||||
<artifactId>wvp-pro</artifactId>
|
<artifactId>wvp-pro</artifactId>
|
||||||
<version>2.7.0</version>
|
<version>2.7.1</version>
|
||||||
<name>web video platform</name>
|
<name>web video platform</name>
|
||||||
<description>国标28181视频平台</description>
|
<description>国标28181视频平台</description>
|
||||||
<packaging>${project.packaging}</packaging>
|
<packaging>${project.packaging}</packaging>
|
||||||
@ -99,6 +99,10 @@
|
|||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-data-redis</artifactId>
|
<artifactId>spring-boot-starter-data-redis</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-cache</artifactId>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-web</artifactId>
|
<artifactId>spring-boot-starter-web</artifactId>
|
||||||
|
|||||||
@ -9,6 +9,7 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
|
|||||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||||
import org.springframework.boot.web.servlet.ServletComponentScan;
|
import org.springframework.boot.web.servlet.ServletComponentScan;
|
||||||
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
|
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
|
||||||
|
import org.springframework.cache.annotation.EnableCaching;
|
||||||
import org.springframework.context.ConfigurableApplicationContext;
|
import org.springframework.context.ConfigurableApplicationContext;
|
||||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||||
|
|
||||||
@ -24,6 +25,7 @@ import java.util.Collections;
|
|||||||
@ServletComponentScan("com.genersoft.iot.vmp.conf")
|
@ServletComponentScan("com.genersoft.iot.vmp.conf")
|
||||||
@SpringBootApplication
|
@SpringBootApplication
|
||||||
@EnableScheduling
|
@EnableScheduling
|
||||||
|
@EnableCaching
|
||||||
public class VManageBootstrap extends SpringBootServletInitializer {
|
public class VManageBootstrap extends SpringBootServletInitializer {
|
||||||
|
|
||||||
private final static Logger logger = LoggerFactory.getLogger(VManageBootstrap.class);
|
private final static Logger logger = LoggerFactory.getLogger(VManageBootstrap.class);
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
package com.genersoft.iot.vmp.common;
|
package com.genersoft.iot.vmp.common;
|
||||||
|
|
||||||
|
import com.genersoft.iot.vmp.media.bean.MediaInfo;
|
||||||
import com.genersoft.iot.vmp.service.bean.DownloadFileInfo;
|
import com.genersoft.iot.vmp.service.bean.DownloadFileInfo;
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
|
||||||
@ -70,7 +71,7 @@ public class StreamInfo implements Serializable, Cloneable{
|
|||||||
@Schema(description = "流媒体ID")
|
@Schema(description = "流媒体ID")
|
||||||
private String mediaServerId;
|
private String mediaServerId;
|
||||||
@Schema(description = "流编码信息")
|
@Schema(description = "流编码信息")
|
||||||
private Object tracks;
|
private MediaInfo mediaInfo;
|
||||||
@Schema(description = "开始时间")
|
@Schema(description = "开始时间")
|
||||||
private String startTime;
|
private String startTime;
|
||||||
@Schema(description = "结束时间")
|
@Schema(description = "结束时间")
|
||||||
@ -83,6 +84,9 @@ public class StreamInfo implements Serializable, Cloneable{
|
|||||||
@Schema(description = "是否暂停(录像回放使用)")
|
@Schema(description = "是否暂停(录像回放使用)")
|
||||||
private boolean pause;
|
private boolean pause;
|
||||||
|
|
||||||
|
@Schema(description = "产生源类型,包括 unknown = 0,rtmp_push=1,rtsp_push=2,rtp_push=3,pull=4,ffmpeg_pull=5,mp4_vod=6,device_chn=7")
|
||||||
|
private int originType;
|
||||||
|
|
||||||
public void setFlv(StreamURL flv) {
|
public void setFlv(StreamURL flv) {
|
||||||
this.flv = flv;
|
this.flv = flv;
|
||||||
}
|
}
|
||||||
@ -191,8 +195,7 @@ public class StreamInfo implements Serializable, Cloneable{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setFlv(String host, int port, int sslPort, String app, String stream, String callIdParam) {
|
public void setFlv(String host, int port, int sslPort, String file) {
|
||||||
String file = String.format("%s/%s.live.flv%s", app, stream, callIdParam);
|
|
||||||
if (port > 0) {
|
if (port > 0) {
|
||||||
this.flv = new StreamURL("http", host, port, file);
|
this.flv = new StreamURL("http", host, port, file);
|
||||||
}
|
}
|
||||||
@ -203,6 +206,15 @@ public class StreamInfo implements Serializable, Cloneable{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 > 0) {
|
||||||
|
this.wss_flv = new StreamURL("wss", host, sslPort, file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void setFmp4(String host, int port, int sslPort, String app, String stream, String callIdParam) {
|
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);
|
String file = String.format("%s/%s.live.mp4%s", app, stream, callIdParam);
|
||||||
if (port > 0) {
|
if (port > 0) {
|
||||||
@ -473,12 +485,12 @@ public class StreamInfo implements Serializable, Cloneable{
|
|||||||
this.mediaServerId = mediaServerId;
|
this.mediaServerId = mediaServerId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object getTracks() {
|
public MediaInfo getMediaInfo() {
|
||||||
return tracks;
|
return mediaInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setTracks(Object tracks) {
|
public void setMediaInfo(MediaInfo mediaInfo) {
|
||||||
this.tracks = tracks;
|
this.mediaInfo = mediaInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getStartTime() {
|
public String getStartTime() {
|
||||||
@ -615,4 +627,12 @@ public class StreamInfo implements Serializable, Cloneable{
|
|||||||
public void setDownLoadFilePath(DownloadFileInfo downLoadFilePath) {
|
public void setDownLoadFilePath(DownloadFileInfo downLoadFilePath) {
|
||||||
this.downLoadFilePath = downLoadFilePath;
|
this.downLoadFilePath = downLoadFilePath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getOriginType() {
|
||||||
|
return originType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOriginType(int originType) {
|
||||||
|
this.originType = originType;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,9 +12,9 @@ public class VideoManagerConstants {
|
|||||||
|
|
||||||
public static final String WVP_SERVER_STREAM_PREFIX = "VMP_SIGNALLING_STREAM_";
|
public static final String WVP_SERVER_STREAM_PREFIX = "VMP_SIGNALLING_STREAM_";
|
||||||
|
|
||||||
public static final String MEDIA_SERVER_PREFIX = "VMP_MEDIA_SERVER_";
|
public static final String MEDIA_SERVER_PREFIX = "VMP_MEDIA_SERVER:";
|
||||||
|
|
||||||
public static final String MEDIA_SERVERS_ONLINE_PREFIX = "VMP_MEDIA_ONLINE_SERVERS_";
|
public static final String ONLINE_MEDIA_SERVERS_PREFIX = "VMP_ONLINE_MEDIA_SERVERS:";
|
||||||
|
|
||||||
public static final String DEVICE_PREFIX = "VMP_DEVICE_";
|
public static final String DEVICE_PREFIX = "VMP_DEVICE_";
|
||||||
|
|
||||||
|
|||||||
@ -1,14 +1,10 @@
|
|||||||
package com.genersoft.iot.vmp.conf;
|
package com.genersoft.iot.vmp.conf;
|
||||||
|
|
||||||
|
|
||||||
import com.alibaba.fastjson2.JSONObject;
|
import com.genersoft.iot.vmp.media.bean.MediaServer;
|
||||||
import com.genersoft.iot.vmp.media.zlm.AssistRESTfulUtils;
|
import com.genersoft.iot.vmp.media.service.IMediaServerService;
|
||||||
import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
|
|
||||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
|
||||||
import com.genersoft.iot.vmp.service.IMediaServerService;
|
|
||||||
import com.genersoft.iot.vmp.service.bean.CloudRecordItem;
|
import com.genersoft.iot.vmp.service.bean.CloudRecordItem;
|
||||||
import com.genersoft.iot.vmp.storager.dao.CloudRecordServiceMapper;
|
import com.genersoft.iot.vmp.storager.dao.CloudRecordServiceMapper;
|
||||||
import com.genersoft.iot.vmp.vmanager.cloudRecord.CloudRecordController;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
@ -16,7 +12,6 @@ import org.springframework.scheduling.annotation.Scheduled;
|
|||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -35,9 +30,6 @@ public class CloudRecordTimer {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private CloudRecordServiceMapper cloudRecordServiceMapper;
|
private CloudRecordServiceMapper cloudRecordServiceMapper;
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private ZLMRESTfulUtils zlmresTfulUtils;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 定时查询待删除的录像文件
|
* 定时查询待删除的录像文件
|
||||||
*/
|
*/
|
||||||
@ -46,12 +38,12 @@ public class CloudRecordTimer {
|
|||||||
public void execute(){
|
public void execute(){
|
||||||
logger.info("[录像文件定时清理] 开始清理过期录像文件");
|
logger.info("[录像文件定时清理] 开始清理过期录像文件");
|
||||||
// 获取配置了assist的流媒体节点
|
// 获取配置了assist的流媒体节点
|
||||||
List<MediaServerItem> mediaServerItemList = mediaServerService.getAllOnline();
|
List<MediaServer> mediaServerItemList = mediaServerService.getAllOnline();
|
||||||
if (mediaServerItemList.isEmpty()) {
|
if (mediaServerItemList.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
long result = 0;
|
long result = 0;
|
||||||
for (MediaServerItem mediaServerItem : mediaServerItemList) {
|
for (MediaServer mediaServerItem : mediaServerItemList) {
|
||||||
|
|
||||||
Calendar lastCalendar = Calendar.getInstance();
|
Calendar lastCalendar = Calendar.getInstance();
|
||||||
if (mediaServerItem.getRecordDay() > 0) {
|
if (mediaServerItem.getRecordDay() > 0) {
|
||||||
@ -69,10 +61,10 @@ public class CloudRecordTimer {
|
|||||||
// TODO 后续可以删除空了的过期日期文件夹
|
// TODO 后续可以删除空了的过期日期文件夹
|
||||||
for (CloudRecordItem cloudRecordItem : cloudRecordItemList) {
|
for (CloudRecordItem cloudRecordItem : cloudRecordItemList) {
|
||||||
String date = new File(cloudRecordItem.getFilePath()).getParentFile().getName();
|
String date = new File(cloudRecordItem.getFilePath()).getParentFile().getName();
|
||||||
JSONObject jsonObject = zlmresTfulUtils.deleteRecordDirectory(mediaServerItem, cloudRecordItem.getApp(),
|
boolean deleteResult = mediaServerService.deleteRecordDirectory(mediaServerItem, cloudRecordItem.getApp(),
|
||||||
cloudRecordItem.getStream(), date, cloudRecordItem.getFileName());
|
cloudRecordItem.getStream(), date, cloudRecordItem.getFileName());
|
||||||
if (jsonObject.getInteger("code") != 0) {
|
if (deleteResult) {
|
||||||
logger.warn("[录像文件定时清理] 删除磁盘文件错误: {}:{}", cloudRecordItem.getFilePath(), jsonObject);
|
logger.warn("[录像文件定时清理] 删除磁盘文件成功: {}", cloudRecordItem.getFilePath());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
result += cloudRecordServiceMapper.deleteList(cloudRecordItemList);
|
result += cloudRecordServiceMapper.deleteList(cloudRecordItemList);
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
package com.genersoft.iot.vmp.conf;
|
package com.genersoft.iot.vmp.conf;
|
||||||
|
|
||||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
import com.genersoft.iot.vmp.media.bean.MediaServer;
|
||||||
import com.genersoft.iot.vmp.utils.DateUtil;
|
import com.genersoft.iot.vmp.utils.DateUtil;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
@ -42,12 +42,24 @@ public class MediaConfig{
|
|||||||
@Value("${media.stream-ip:${media.ip}}")
|
@Value("${media.stream-ip:${media.ip}}")
|
||||||
private String streamIp;
|
private String streamIp;
|
||||||
|
|
||||||
@Value("${media.http-port}")
|
@Value("${media.http-port:0}")
|
||||||
private Integer httpPort;
|
private Integer httpPort;
|
||||||
|
|
||||||
|
@Value("${media.flv-port:0}")
|
||||||
|
private Integer flvPort = 0;
|
||||||
|
|
||||||
|
@Value("${media.ws-flv-port:0}")
|
||||||
|
private Integer wsFlvPort = 0;
|
||||||
|
|
||||||
@Value("${media.http-ssl-port:0}")
|
@Value("${media.http-ssl-port:0}")
|
||||||
private Integer httpSSlPort = 0;
|
private Integer httpSSlPort = 0;
|
||||||
|
|
||||||
|
@Value("${media.flv-ssl-port:0}")
|
||||||
|
private Integer flvSSlPort = 0;
|
||||||
|
|
||||||
|
@Value("${media.ws-flv-ssl-port:0}")
|
||||||
|
private Integer wsFlvSSlPort = 0;
|
||||||
|
|
||||||
@Value("${media.rtmp-port:0}")
|
@Value("${media.rtmp-port:0}")
|
||||||
private Integer rtmpPort = 0;
|
private Integer rtmpPort = 0;
|
||||||
|
|
||||||
@ -87,6 +99,9 @@ public class MediaConfig{
|
|||||||
@Value("${media.record-path:}")
|
@Value("${media.record-path:}")
|
||||||
private String recordPath;
|
private String recordPath;
|
||||||
|
|
||||||
|
@Value("${media.type:zlm}")
|
||||||
|
private String type;
|
||||||
|
|
||||||
public String getId() {
|
public String getId() {
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
@ -196,36 +211,59 @@ public class MediaConfig{
|
|||||||
return sipDomain;
|
return sipDomain;
|
||||||
}
|
}
|
||||||
|
|
||||||
public MediaServerItem getMediaSerItem(){
|
public MediaServer getMediaSerItem(){
|
||||||
MediaServerItem mediaServerItem = new MediaServerItem();
|
MediaServer mediaServer = new MediaServer();
|
||||||
mediaServerItem.setId(id);
|
mediaServer.setId(id);
|
||||||
mediaServerItem.setIp(ip);
|
mediaServer.setIp(ip);
|
||||||
mediaServerItem.setDefaultServer(true);
|
mediaServer.setDefaultServer(true);
|
||||||
mediaServerItem.setHookIp(getHookIp());
|
mediaServer.setHookIp(getHookIp());
|
||||||
mediaServerItem.setSdpIp(getSdpIp());
|
mediaServer.setSdpIp(getSdpIp());
|
||||||
mediaServerItem.setStreamIp(getStreamIp());
|
mediaServer.setStreamIp(getStreamIp());
|
||||||
mediaServerItem.setHttpPort(httpPort);
|
mediaServer.setHttpPort(httpPort);
|
||||||
mediaServerItem.setHttpSSlPort(httpSSlPort);
|
if (flvPort == 0) {
|
||||||
mediaServerItem.setRtmpPort(rtmpPort);
|
mediaServer.setFlvPort(httpPort);
|
||||||
mediaServerItem.setRtmpSSlPort(rtmpSSlPort);
|
}else {
|
||||||
mediaServerItem.setRtpProxyPort(getRtpProxyPort());
|
mediaServer.setFlvPort(flvPort);
|
||||||
mediaServerItem.setRtspPort(rtspPort);
|
}
|
||||||
mediaServerItem.setRtspSSLPort(rtspSSLPort);
|
if (wsFlvPort == 0) {
|
||||||
mediaServerItem.setAutoConfig(autoConfig);
|
mediaServer.setWsFlvPort(httpPort);
|
||||||
mediaServerItem.setSecret(secret);
|
}else {
|
||||||
mediaServerItem.setRtpEnable(rtpEnable);
|
mediaServer.setWsFlvPort(wsFlvPort);
|
||||||
mediaServerItem.setRtpPortRange(rtpPortRange);
|
}
|
||||||
mediaServerItem.setSendRtpPortRange(rtpSendPortRange);
|
if (flvSSlPort == 0) {
|
||||||
mediaServerItem.setRecordAssistPort(recordAssistPort);
|
mediaServer.setFlvSSLPort(httpSSlPort);
|
||||||
mediaServerItem.setHookAliveInterval(30.00f);
|
}else {
|
||||||
mediaServerItem.setRecordDay(recordDay);
|
mediaServer.setFlvSSLPort(flvSSlPort);
|
||||||
if (recordPath != null) {
|
}
|
||||||
mediaServerItem.setRecordPath(recordPath);
|
if (wsFlvSSlPort == 0) {
|
||||||
|
mediaServer.setWsFlvSSLPort(httpSSlPort);
|
||||||
|
}else {
|
||||||
|
mediaServer.setWsFlvSSLPort(wsFlvSSlPort);
|
||||||
}
|
}
|
||||||
mediaServerItem.setCreateTime(DateUtil.getNow());
|
|
||||||
mediaServerItem.setUpdateTime(DateUtil.getNow());
|
|
||||||
|
|
||||||
return mediaServerItem;
|
mediaServer.setHttpSSlPort(httpSSlPort);
|
||||||
|
mediaServer.setRtmpPort(rtmpPort);
|
||||||
|
mediaServer.setRtmpSSlPort(rtmpSSlPort);
|
||||||
|
mediaServer.setRtpProxyPort(getRtpProxyPort());
|
||||||
|
mediaServer.setRtspPort(rtspPort);
|
||||||
|
mediaServer.setRtspSSLPort(rtspSSLPort);
|
||||||
|
mediaServer.setAutoConfig(autoConfig);
|
||||||
|
mediaServer.setSecret(secret);
|
||||||
|
mediaServer.setRtpEnable(rtpEnable);
|
||||||
|
mediaServer.setRtpPortRange(rtpPortRange);
|
||||||
|
mediaServer.setSendRtpPortRange(rtpSendPortRange);
|
||||||
|
mediaServer.setRecordAssistPort(recordAssistPort);
|
||||||
|
mediaServer.setHookAliveInterval(10f);
|
||||||
|
mediaServer.setRecordDay(recordDay);
|
||||||
|
mediaServer.setStatus(false);
|
||||||
|
mediaServer.setType(type);
|
||||||
|
if (recordPath != null) {
|
||||||
|
mediaServer.setRecordPath(recordPath);
|
||||||
|
}
|
||||||
|
mediaServer.setCreateTime(DateUtil.getNow());
|
||||||
|
mediaServer.setUpdateTime(DateUtil.getNow());
|
||||||
|
|
||||||
|
return mediaServer;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Integer getRecordDay() {
|
public Integer getRecordDay() {
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
package com.genersoft.iot.vmp.conf;
|
package com.genersoft.iot.vmp.conf;
|
||||||
|
|
||||||
import org.apache.ibatis.logging.stdout.StdOutImpl;
|
import org.apache.ibatis.logging.stdout.StdOutImpl;
|
||||||
|
import org.apache.ibatis.mapping.DatabaseIdProvider;
|
||||||
|
import org.apache.ibatis.mapping.VendorDatabaseIdProvider;
|
||||||
import org.apache.ibatis.session.SqlSessionFactory;
|
import org.apache.ibatis.session.SqlSessionFactory;
|
||||||
import org.mybatis.spring.SqlSessionFactoryBean;
|
import org.mybatis.spring.SqlSessionFactoryBean;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
@ -9,6 +11,7 @@ import org.springframework.context.annotation.Configuration;
|
|||||||
import org.springframework.core.annotation.Order;
|
import org.springframework.core.annotation.Order;
|
||||||
|
|
||||||
import javax.sql.DataSource;
|
import javax.sql.DataSource;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 配置mybatis
|
* 配置mybatis
|
||||||
@ -21,7 +24,29 @@ public class MybatisConfig {
|
|||||||
private UserSetting userSetting;
|
private UserSetting userSetting;
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
|
public DatabaseIdProvider databaseIdProvider() {
|
||||||
|
VendorDatabaseIdProvider databaseIdProvider = new VendorDatabaseIdProvider();
|
||||||
|
Properties properties = new Properties();
|
||||||
|
properties.setProperty("Oracle", "oracle");
|
||||||
|
properties.setProperty("MySQL", "mysql");
|
||||||
|
properties.setProperty("DB2", "db2");
|
||||||
|
properties.setProperty("Derby", "derby");
|
||||||
|
properties.setProperty("H2", "h2");
|
||||||
|
properties.setProperty("HSQL", "hsql");
|
||||||
|
properties.setProperty("Informix", "informix");
|
||||||
|
properties.setProperty("MS-SQL", "ms-sql");
|
||||||
|
properties.setProperty("PostgreSQL", "postgresql");
|
||||||
|
properties.setProperty("Sybase", "sybase");
|
||||||
|
properties.setProperty("Hana", "hana");
|
||||||
|
properties.setProperty("DM", "dm");
|
||||||
|
properties.setProperty("KingbaseES", "kingbase");
|
||||||
|
properties.setProperty("KingBase8", "kingbase");
|
||||||
|
databaseIdProvider.setProperties(properties);
|
||||||
|
return databaseIdProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public SqlSessionFactory sqlSessionFactory(DataSource dataSource, DatabaseIdProvider databaseIdProvider) throws Exception {
|
||||||
final SqlSessionFactoryBean sqlSessionFactory = new SqlSessionFactoryBean();
|
final SqlSessionFactoryBean sqlSessionFactory = new SqlSessionFactoryBean();
|
||||||
sqlSessionFactory.setDataSource(dataSource);
|
sqlSessionFactory.setDataSource(dataSource);
|
||||||
org.apache.ibatis.session.Configuration config = new org.apache.ibatis.session.Configuration();
|
org.apache.ibatis.session.Configuration config = new org.apache.ibatis.session.Configuration();
|
||||||
@ -30,6 +55,7 @@ public class MybatisConfig {
|
|||||||
}
|
}
|
||||||
config.setMapUnderscoreToCamelCase(true);
|
config.setMapUnderscoreToCamelCase(true);
|
||||||
sqlSessionFactory.setConfiguration(config);
|
sqlSessionFactory.setConfiguration(config);
|
||||||
|
sqlSessionFactory.setDatabaseIdProvider(databaseIdProvider);
|
||||||
return sqlSessionFactory.getObject();
|
return sqlSessionFactory.getObject();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
package com.genersoft.iot.vmp.conf;
|
package com.genersoft.iot.vmp.conf;
|
||||||
|
|
||||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
import com.genersoft.iot.vmp.media.bean.MediaServer;
|
||||||
import com.genersoft.iot.vmp.service.IMediaServerService;
|
import com.genersoft.iot.vmp.media.service.IMediaServerService;
|
||||||
import org.apache.http.HttpHost;
|
import org.apache.http.HttpHost;
|
||||||
import org.apache.http.HttpRequest;
|
import org.apache.http.HttpRequest;
|
||||||
import org.apache.http.HttpResponse;
|
import org.apache.http.HttpResponse;
|
||||||
@ -54,7 +54,7 @@ public class ProxyServletConfig {
|
|||||||
@Override
|
@Override
|
||||||
protected String rewriteQueryStringFromRequest(HttpServletRequest servletRequest, String queryString) {
|
protected String rewriteQueryStringFromRequest(HttpServletRequest servletRequest, String queryString) {
|
||||||
String queryStr = super.rewriteQueryStringFromRequest(servletRequest, queryString);
|
String queryStr = super.rewriteQueryStringFromRequest(servletRequest, queryString);
|
||||||
MediaServerItem mediaInfo = getMediaInfoByUri(servletRequest.getRequestURI());
|
MediaServer mediaInfo = getMediaInfoByUri(servletRequest.getRequestURI());
|
||||||
if (mediaInfo != null) {
|
if (mediaInfo != null) {
|
||||||
if (!ObjectUtils.isEmpty(queryStr)) {
|
if (!ObjectUtils.isEmpty(queryStr)) {
|
||||||
queryStr += "&secret=" + mediaInfo.getSecret();
|
queryStr += "&secret=" + mediaInfo.getSecret();
|
||||||
@ -103,7 +103,7 @@ public class ProxyServletConfig {
|
|||||||
@Override
|
@Override
|
||||||
protected String getTargetUri(HttpServletRequest servletRequest) {
|
protected String getTargetUri(HttpServletRequest servletRequest) {
|
||||||
String requestURI = servletRequest.getRequestURI();
|
String requestURI = servletRequest.getRequestURI();
|
||||||
MediaServerItem mediaInfo = getMediaInfoByUri(requestURI);
|
MediaServer mediaInfo = getMediaInfoByUri(requestURI);
|
||||||
|
|
||||||
String uri = null;
|
String uri = null;
|
||||||
if (mediaInfo != null) {
|
if (mediaInfo != null) {
|
||||||
@ -121,7 +121,7 @@ public class ProxyServletConfig {
|
|||||||
@Override
|
@Override
|
||||||
protected HttpHost getTargetHost(HttpServletRequest servletRequest) {
|
protected HttpHost getTargetHost(HttpServletRequest servletRequest) {
|
||||||
String requestURI = servletRequest.getRequestURI();
|
String requestURI = servletRequest.getRequestURI();
|
||||||
MediaServerItem mediaInfo = getMediaInfoByUri(requestURI);
|
MediaServer mediaInfo = getMediaInfoByUri(requestURI);
|
||||||
HttpHost host;
|
HttpHost host;
|
||||||
if (mediaInfo != null) {
|
if (mediaInfo != null) {
|
||||||
host = new HttpHost(mediaInfo.getIp(), mediaInfo.getHttpPort());
|
host = new HttpHost(mediaInfo.getIp(), mediaInfo.getHttpPort());
|
||||||
@ -135,7 +135,7 @@ public class ProxyServletConfig {
|
|||||||
/**
|
/**
|
||||||
* 根据uri获取流媒体信息
|
* 根据uri获取流媒体信息
|
||||||
*/
|
*/
|
||||||
MediaServerItem getMediaInfoByUri(String uri){
|
MediaServer getMediaInfoByUri(String uri){
|
||||||
String[] split = uri.split("/");
|
String[] split = uri.split("/");
|
||||||
String mediaServerId = split[2];
|
String mediaServerId = split[2];
|
||||||
if ("default".equalsIgnoreCase(mediaServerId)) {
|
if ("default".equalsIgnoreCase(mediaServerId)) {
|
||||||
@ -151,7 +151,7 @@ public class ProxyServletConfig {
|
|||||||
@Override
|
@Override
|
||||||
protected String rewriteUrlFromRequest(HttpServletRequest servletRequest) {
|
protected String rewriteUrlFromRequest(HttpServletRequest servletRequest) {
|
||||||
String requestURI = servletRequest.getRequestURI();
|
String requestURI = servletRequest.getRequestURI();
|
||||||
MediaServerItem mediaInfo = getMediaInfoByUri(requestURI);
|
MediaServer mediaInfo = getMediaInfoByUri(requestURI);
|
||||||
String url = super.rewriteUrlFromRequest(servletRequest);
|
String url = super.rewriteUrlFromRequest(servletRequest);
|
||||||
if (mediaInfo == null) {
|
if (mediaInfo == null) {
|
||||||
logger.error("[ZLM服务访问代理],错误:处理url信息时未找到流媒体信息=>{}", requestURI);
|
logger.error("[ZLM服务访问代理],错误:处理url信息时未找到流媒体信息=>{}", requestURI);
|
||||||
@ -181,7 +181,7 @@ public class ProxyServletConfig {
|
|||||||
@Override
|
@Override
|
||||||
protected String rewriteQueryStringFromRequest(HttpServletRequest servletRequest, String queryString) {
|
protected String rewriteQueryStringFromRequest(HttpServletRequest servletRequest, String queryString) {
|
||||||
String queryStr = super.rewriteQueryStringFromRequest(servletRequest, queryString);
|
String queryStr = super.rewriteQueryStringFromRequest(servletRequest, queryString);
|
||||||
MediaServerItem mediaInfo = getMediaInfoByUri(servletRequest.getRequestURI());
|
MediaServer mediaInfo = getMediaInfoByUri(servletRequest.getRequestURI());
|
||||||
if (mediaInfo == null) {
|
if (mediaInfo == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -238,7 +238,7 @@ public class ProxyServletConfig {
|
|||||||
@Override
|
@Override
|
||||||
protected String getTargetUri(HttpServletRequest servletRequest) {
|
protected String getTargetUri(HttpServletRequest servletRequest) {
|
||||||
String requestURI = servletRequest.getRequestURI();
|
String requestURI = servletRequest.getRequestURI();
|
||||||
MediaServerItem mediaInfo = getMediaInfoByUri(requestURI);
|
MediaServer mediaInfo = getMediaInfoByUri(requestURI);
|
||||||
|
|
||||||
String uri = null;
|
String uri = null;
|
||||||
if (mediaInfo != null) {
|
if (mediaInfo != null) {
|
||||||
@ -256,7 +256,7 @@ public class ProxyServletConfig {
|
|||||||
@Override
|
@Override
|
||||||
protected HttpHost getTargetHost(HttpServletRequest servletRequest) {
|
protected HttpHost getTargetHost(HttpServletRequest servletRequest) {
|
||||||
String requestURI = servletRequest.getRequestURI();
|
String requestURI = servletRequest.getRequestURI();
|
||||||
MediaServerItem mediaInfo = getMediaInfoByUri(requestURI);
|
MediaServer mediaInfo = getMediaInfoByUri(requestURI);
|
||||||
HttpHost host;
|
HttpHost host;
|
||||||
if (mediaInfo != null) {
|
if (mediaInfo != null) {
|
||||||
host = new HttpHost(mediaInfo.getIp(), mediaInfo.getRecordAssistPort());
|
host = new HttpHost(mediaInfo.getIp(), mediaInfo.getRecordAssistPort());
|
||||||
@ -270,7 +270,7 @@ public class ProxyServletConfig {
|
|||||||
/**
|
/**
|
||||||
* 根据uri获取流媒体信息
|
* 根据uri获取流媒体信息
|
||||||
*/
|
*/
|
||||||
MediaServerItem getMediaInfoByUri(String uri){
|
MediaServer getMediaInfoByUri(String uri){
|
||||||
String[] split = uri.split("/");
|
String[] split = uri.split("/");
|
||||||
String mediaServerId = split[2];
|
String mediaServerId = split[2];
|
||||||
if ("default".equalsIgnoreCase(mediaServerId)) {
|
if ("default".equalsIgnoreCase(mediaServerId)) {
|
||||||
@ -287,7 +287,7 @@ public class ProxyServletConfig {
|
|||||||
@Override
|
@Override
|
||||||
protected String rewriteUrlFromRequest(HttpServletRequest servletRequest) {
|
protected String rewriteUrlFromRequest(HttpServletRequest servletRequest) {
|
||||||
String requestURI = servletRequest.getRequestURI();
|
String requestURI = servletRequest.getRequestURI();
|
||||||
MediaServerItem mediaInfo = getMediaInfoByUri(requestURI);
|
MediaServer mediaInfo = getMediaInfoByUri(requestURI);
|
||||||
String url = super.rewriteUrlFromRequest(servletRequest);
|
String url = super.rewriteUrlFromRequest(servletRequest);
|
||||||
if (mediaInfo == null) {
|
if (mediaInfo == null) {
|
||||||
logger.error("[录像服务访问代理],错误:处理url信息时未找到流媒体信息=>{}", requestURI);
|
logger.error("[录像服务访问代理],错误:处理url信息时未找到流媒体信息=>{}", requestURI);
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
package com.genersoft.iot.vmp.conf;
|
package com.genersoft.iot.vmp.conf;
|
||||||
|
|
||||||
import com.alibaba.fastjson2.JSONObject;
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
import com.genersoft.iot.vmp.service.IMediaServerService;
|
|
||||||
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
|
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
@ -14,9 +13,6 @@ public class WVPTimerTask {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private IRedisCatchStorage redisCatchStorage;
|
private IRedisCatchStorage redisCatchStorage;
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private IMediaServerService mediaServerService;
|
|
||||||
|
|
||||||
@Value("${server.port}")
|
@Value("${server.port}")
|
||||||
private int serverPort;
|
private int serverPort;
|
||||||
|
|
||||||
|
|||||||
@ -51,8 +51,11 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter {
|
|||||||
if (StringUtils.isBlank(jwt)) {
|
if (StringUtils.isBlank(jwt)) {
|
||||||
jwt = request.getParameter(JwtUtils.getHeader());
|
jwt = request.getParameter(JwtUtils.getHeader());
|
||||||
if (StringUtils.isBlank(jwt)) {
|
if (StringUtils.isBlank(jwt)) {
|
||||||
chain.doFilter(request, response);
|
jwt = request.getHeader(JwtUtils.getApiKeyHeader());
|
||||||
return;
|
if (StringUtils.isBlank(jwt)) {
|
||||||
|
chain.doFilter(request, response);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,8 +1,12 @@
|
|||||||
package com.genersoft.iot.vmp.conf.security;
|
package com.genersoft.iot.vmp.conf.security;
|
||||||
|
|
||||||
import com.genersoft.iot.vmp.conf.security.dto.JwtUser;
|
import com.genersoft.iot.vmp.conf.security.dto.JwtUser;
|
||||||
|
import com.genersoft.iot.vmp.service.IUserApiKeyService;
|
||||||
import com.genersoft.iot.vmp.service.IUserService;
|
import com.genersoft.iot.vmp.service.IUserService;
|
||||||
import com.genersoft.iot.vmp.storager.dao.dto.User;
|
import com.genersoft.iot.vmp.storager.dao.dto.User;
|
||||||
|
import com.genersoft.iot.vmp.storager.dao.dto.UserApiKey;
|
||||||
|
import org.jose4j.jwk.JsonWebKey;
|
||||||
|
import org.jose4j.jwk.JsonWebKeySet;
|
||||||
import org.jose4j.jwk.RsaJsonWebKey;
|
import org.jose4j.jwk.RsaJsonWebKey;
|
||||||
import org.jose4j.jwk.RsaJwkGenerator;
|
import org.jose4j.jwk.RsaJwkGenerator;
|
||||||
import org.jose4j.jws.AlgorithmIdentifiers;
|
import org.jose4j.jws.AlgorithmIdentifiers;
|
||||||
@ -20,8 +24,13 @@ import org.springframework.beans.factory.InitializingBean;
|
|||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.time.ZoneOffset;
|
import java.time.ZoneOffset;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
public class JwtUtils implements InitializingBean {
|
public class JwtUtils implements InitializingBean {
|
||||||
@ -30,6 +39,8 @@ public class JwtUtils implements InitializingBean {
|
|||||||
|
|
||||||
public static final String HEADER = "access-token";
|
public static final String HEADER = "access-token";
|
||||||
|
|
||||||
|
public static final String API_KEY_HEADER = "api-key";
|
||||||
|
|
||||||
private static final String AUDIENCE = "Audience";
|
private static final String AUDIENCE = "Audience";
|
||||||
|
|
||||||
private static final String keyId = "3e79646c4dbc408383a9eed09f2b85ae";
|
private static final String keyId = "3e79646c4dbc408383a9eed09f2b85ae";
|
||||||
@ -37,17 +48,28 @@ public class JwtUtils implements InitializingBean {
|
|||||||
/**
|
/**
|
||||||
* token过期时间(分钟)
|
* token过期时间(分钟)
|
||||||
*/
|
*/
|
||||||
public static final long expirationTime = 30 * 24 * 60;
|
public static final long EXPIRATION_TIME = 30 * 24 * 60;
|
||||||
|
|
||||||
private static RsaJsonWebKey rsaJsonWebKey;
|
private static RsaJsonWebKey rsaJsonWebKey;
|
||||||
|
|
||||||
private static IUserService userService;
|
private static IUserService userService;
|
||||||
|
|
||||||
|
private static IUserApiKeyService userApiKeyService;
|
||||||
|
|
||||||
|
public static String getApiKeyHeader() {
|
||||||
|
return API_KEY_HEADER;
|
||||||
|
}
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
public void setUserService(IUserService userService) {
|
public void setUserService(IUserService userService) {
|
||||||
JwtUtils.userService = userService;
|
JwtUtils.userService = userService;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
public void setUserApiKeyService(IUserApiKeyService userApiKeyService) {
|
||||||
|
JwtUtils.userApiKeyService = userApiKeyService;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void afterPropertiesSet() {
|
public void afterPropertiesSet() {
|
||||||
try {
|
try {
|
||||||
@ -59,17 +81,34 @@ public class JwtUtils implements InitializingBean {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建密钥对
|
* 创建密钥对
|
||||||
|
*
|
||||||
* @throws JoseException JoseException
|
* @throws JoseException JoseException
|
||||||
*/
|
*/
|
||||||
private RsaJsonWebKey generateRsaJsonWebKey() throws JoseException {
|
private RsaJsonWebKey generateRsaJsonWebKey() throws JoseException {
|
||||||
// 生成一个RSA密钥对,该密钥对将用于JWT的签名和验证,包装在JWK中
|
RsaJsonWebKey rsaJsonWebKey = null;
|
||||||
RsaJsonWebKey rsaJsonWebKey = RsaJwkGenerator.generateJwk(2048);
|
try (BufferedReader reader = new BufferedReader(new InputStreamReader(getClass().getClassLoader().getResourceAsStream("/jwk.json"), StandardCharsets.UTF_8))) {
|
||||||
// 给JWK一个密钥ID
|
String jwkJson = reader.readLine();
|
||||||
rsaJsonWebKey.setKeyId(keyId);
|
JsonWebKeySet jsonWebKeySet = new JsonWebKeySet(jwkJson);
|
||||||
|
List<JsonWebKey> jsonWebKeys = jsonWebKeySet.getJsonWebKeys();
|
||||||
|
if (!jsonWebKeys.isEmpty()) {
|
||||||
|
JsonWebKey jsonWebKey = jsonWebKeys.get(0);
|
||||||
|
if (jsonWebKey instanceof RsaJsonWebKey) {
|
||||||
|
rsaJsonWebKey = (RsaJsonWebKey) jsonWebKey;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
// ignored
|
||||||
|
}
|
||||||
|
if (rsaJsonWebKey == null) {
|
||||||
|
// 生成一个RSA密钥对,该密钥对将用于JWT的签名和验证,包装在JWK中
|
||||||
|
rsaJsonWebKey = RsaJwkGenerator.generateJwk(2048);
|
||||||
|
// 给JWK一个密钥ID
|
||||||
|
rsaJsonWebKey.setKeyId(keyId);
|
||||||
|
}
|
||||||
return rsaJsonWebKey;
|
return rsaJsonWebKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String createToken(String username) {
|
public static String createToken(String username, Long expirationTime, Map<String, Object> extra) {
|
||||||
try {
|
try {
|
||||||
/*
|
/*
|
||||||
* “iss” (issuer) 发行人
|
* “iss” (issuer) 发行人
|
||||||
@ -83,13 +122,17 @@ public class JwtUtils implements InitializingBean {
|
|||||||
claims.setGeneratedJwtId();
|
claims.setGeneratedJwtId();
|
||||||
claims.setIssuedAtToNow();
|
claims.setIssuedAtToNow();
|
||||||
// 令牌将过期的时间 分钟
|
// 令牌将过期的时间 分钟
|
||||||
claims.setExpirationTimeMinutesInTheFuture(expirationTime);
|
if (expirationTime != null) {
|
||||||
|
claims.setExpirationTimeMinutesInTheFuture(expirationTime);
|
||||||
|
}
|
||||||
claims.setNotBeforeMinutesInThePast(0);
|
claims.setNotBeforeMinutesInThePast(0);
|
||||||
claims.setSubject("login");
|
claims.setSubject("login");
|
||||||
claims.setAudience(AUDIENCE);
|
claims.setAudience(AUDIENCE);
|
||||||
//添加自定义参数,必须是字符串类型
|
//添加自定义参数,必须是字符串类型
|
||||||
claims.setClaim("userName", username);
|
claims.setClaim("userName", username);
|
||||||
|
if (extra != null) {
|
||||||
|
extra.forEach(claims::setClaim);
|
||||||
|
}
|
||||||
//jws
|
//jws
|
||||||
JsonWebSignature jws = new JsonWebSignature();
|
JsonWebSignature jws = new JsonWebSignature();
|
||||||
//签名算法RS256
|
//签名算法RS256
|
||||||
@ -104,10 +147,17 @@ public class JwtUtils implements InitializingBean {
|
|||||||
} catch (JoseException e) {
|
} catch (JoseException e) {
|
||||||
logger.error("[Token生成失败]: {}", e.getMessage());
|
logger.error("[Token生成失败]: {}", e.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String createToken(String username, Long expirationTime) {
|
||||||
|
return createToken(username, expirationTime, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String createToken(String username) {
|
||||||
|
return createToken(username, EXPIRATION_TIME);
|
||||||
|
}
|
||||||
|
|
||||||
public static String getHeader() {
|
public static String getHeader() {
|
||||||
return HEADER;
|
return HEADER;
|
||||||
}
|
}
|
||||||
@ -118,8 +168,8 @@ public class JwtUtils implements InitializingBean {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
JwtConsumer consumer = new JwtConsumerBuilder()
|
JwtConsumer consumer = new JwtConsumerBuilder()
|
||||||
.setRequireExpirationTime()
|
//.setRequireExpirationTime()
|
||||||
.setMaxFutureValidityInMinutes(5256000)
|
//.setMaxFutureValidityInMinutes(5256000)
|
||||||
.setAllowedClockSkewInSeconds(30)
|
.setAllowedClockSkewInSeconds(30)
|
||||||
.setRequireSubject()
|
.setRequireSubject()
|
||||||
//.setExpectedIssuer("")
|
//.setExpectedIssuer("")
|
||||||
@ -129,15 +179,27 @@ public class JwtUtils implements InitializingBean {
|
|||||||
|
|
||||||
JwtClaims claims = consumer.processToClaims(token);
|
JwtClaims claims = consumer.processToClaims(token);
|
||||||
NumericDate expirationTime = claims.getExpirationTime();
|
NumericDate expirationTime = claims.getExpirationTime();
|
||||||
// 判断是否即将过期, 默认剩余时间小于5分钟未即将过期
|
if (expirationTime != null) {
|
||||||
// 剩余时间 (秒)
|
// 判断是否即将过期, 默认剩余时间小于5分钟未即将过期
|
||||||
long timeRemaining = LocalDateTime.now().toEpochSecond(ZoneOffset.ofHours(8)) - expirationTime.getValue();
|
// 剩余时间 (秒)
|
||||||
if (timeRemaining < 5 * 60) {
|
long timeRemaining = LocalDateTime.now().toEpochSecond(ZoneOffset.ofHours(8)) - expirationTime.getValue();
|
||||||
jwtUser.setStatus(JwtUser.TokenStatus.EXPIRING_SOON);
|
if (timeRemaining < 5 * 60) {
|
||||||
|
jwtUser.setStatus(JwtUser.TokenStatus.EXPIRING_SOON);
|
||||||
|
} else {
|
||||||
|
jwtUser.setStatus(JwtUser.TokenStatus.NORMAL);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
jwtUser.setStatus(JwtUser.TokenStatus.NORMAL);
|
jwtUser.setStatus(JwtUser.TokenStatus.NORMAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Long apiKeyId = claims.getClaimValue("apiKeyId", Long.class);
|
||||||
|
if (apiKeyId != null) {
|
||||||
|
UserApiKey userApiKey = userApiKeyService.getUserApiKeyById(apiKeyId.intValue());
|
||||||
|
if (userApiKey == null || !userApiKey.isEnable()) {
|
||||||
|
jwtUser.setStatus(JwtUser.TokenStatus.EXPIRED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
String username = (String) claims.getClaimValue("userName");
|
String username = (String) claims.getClaimValue("userName");
|
||||||
User user = userService.getUserByUsername(username);
|
User user = userService.getUserByUsername(username);
|
||||||
|
|
||||||
|
|||||||
@ -117,7 +117,7 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
|
|||||||
.authorizeRequests()
|
.authorizeRequests()
|
||||||
.requestMatchers(CorsUtils::isPreFlightRequest).permitAll()
|
.requestMatchers(CorsUtils::isPreFlightRequest).permitAll()
|
||||||
.antMatchers(userSetting.getInterfaceAuthenticationExcludes().toArray(new String[0])).permitAll()
|
.antMatchers(userSetting.getInterfaceAuthenticationExcludes().toArray(new String[0])).permitAll()
|
||||||
.antMatchers("/api/user/login", "/index/hook/**", "/swagger-ui/**", "/doc.html").permitAll()
|
.antMatchers("/api/user/login", "/index/hook/**","/index/hook/abl/**", "/swagger-ui/**", "/doc.html").permitAll()
|
||||||
.anyRequest().authenticated()
|
.anyRequest().authenticated()
|
||||||
// 异常处理器
|
// 异常处理器
|
||||||
.and()
|
.and()
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
package com.genersoft.iot.vmp.gb28181.bean;
|
package com.genersoft.iot.vmp.gb28181.bean;
|
||||||
|
|
||||||
|
|
||||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
import com.genersoft.iot.vmp.media.bean.MediaServer;
|
||||||
import com.genersoft.iot.vmp.vmanager.gb28181.play.bean.AudioBroadcastEvent;
|
import com.genersoft.iot.vmp.vmanager.gb28181.play.bean.AudioBroadcastEvent;
|
||||||
import gov.nist.javax.sip.message.SIPResponse;
|
import gov.nist.javax.sip.message.SIPResponse;
|
||||||
|
|
||||||
@ -15,7 +15,7 @@ public class AudioBroadcastCatch {
|
|||||||
public AudioBroadcastCatch(
|
public AudioBroadcastCatch(
|
||||||
String deviceId,
|
String deviceId,
|
||||||
String channelId,
|
String channelId,
|
||||||
MediaServerItem mediaServerItem,
|
MediaServer mediaServerItem,
|
||||||
String app,
|
String app,
|
||||||
String stream,
|
String stream,
|
||||||
AudioBroadcastEvent event,
|
AudioBroadcastEvent event,
|
||||||
@ -48,7 +48,7 @@ public class AudioBroadcastCatch {
|
|||||||
/**
|
/**
|
||||||
* 流媒体信息
|
* 流媒体信息
|
||||||
*/
|
*/
|
||||||
private MediaServerItem mediaServerItem;
|
private MediaServer mediaServerItem;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 关联的流APP
|
* 关联的流APP
|
||||||
@ -109,11 +109,11 @@ public class AudioBroadcastCatch {
|
|||||||
return sipTransactionInfo;
|
return sipTransactionInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
public MediaServerItem getMediaServerItem() {
|
public MediaServer getMediaServerItem() {
|
||||||
return mediaServerItem;
|
return mediaServerItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setMediaServerItem(MediaServerItem mediaServerItem) {
|
public void setMediaServerItem(MediaServer mediaServerItem) {
|
||||||
this.mediaServerItem = mediaServerItem;
|
this.mediaServerItem = mediaServerItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,11 +1,11 @@
|
|||||||
package com.genersoft.iot.vmp.gb28181.bean;
|
package com.genersoft.iot.vmp.gb28181.bean;
|
||||||
|
|
||||||
import com.alibaba.fastjson2.JSONObject;
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
import com.genersoft.iot.vmp.media.bean.MediaServer;
|
||||||
|
|
||||||
public class InviteStreamInfo {
|
public class InviteStreamInfo {
|
||||||
|
|
||||||
public InviteStreamInfo(MediaServerItem mediaServerItem, JSONObject response, String callId, String app, String stream) {
|
public InviteStreamInfo(MediaServer mediaServerItem, JSONObject response, String callId, String app, String stream) {
|
||||||
this.mediaServerItem = mediaServerItem;
|
this.mediaServerItem = mediaServerItem;
|
||||||
this.response = response;
|
this.response = response;
|
||||||
this.callId = callId;
|
this.callId = callId;
|
||||||
@ -13,17 +13,17 @@ public class InviteStreamInfo {
|
|||||||
this.stream = stream;
|
this.stream = stream;
|
||||||
}
|
}
|
||||||
|
|
||||||
private MediaServerItem mediaServerItem;
|
private MediaServer mediaServerItem;
|
||||||
private JSONObject response;
|
private JSONObject response;
|
||||||
private String callId;
|
private String callId;
|
||||||
private String app;
|
private String app;
|
||||||
private String stream;
|
private String stream;
|
||||||
|
|
||||||
public MediaServerItem getMediaServerItem() {
|
public MediaServer getMediaServerItem() {
|
||||||
return mediaServerItem;
|
return mediaServerItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setMediaServerItem(MediaServerItem mediaServerItem) {
|
public void setMediaServerItem(MediaServer mediaServerItem) {
|
||||||
this.mediaServerItem = mediaServerItem;
|
this.mediaServerItem = mediaServerItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
package com.genersoft.iot.vmp.gb28181.bean;
|
package com.genersoft.iot.vmp.gb28181.bean;
|
||||||
|
|
||||||
|
import com.genersoft.iot.vmp.service.bean.RequestPushStreamMsg;
|
||||||
|
|
||||||
public class SendRtpItem {
|
public class SendRtpItem {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -122,6 +124,39 @@ public class SendRtpItem {
|
|||||||
*/
|
*/
|
||||||
private String receiveStream;
|
private String receiveStream;
|
||||||
|
|
||||||
|
public static SendRtpItem getInstance(RequestPushStreamMsg requestPushStreamMsg) {
|
||||||
|
SendRtpItem sendRtpItem = new SendRtpItem();
|
||||||
|
sendRtpItem.setMediaServerId(requestPushStreamMsg.getMediaServerId());
|
||||||
|
sendRtpItem.setApp(requestPushStreamMsg.getApp());
|
||||||
|
sendRtpItem.setStream(requestPushStreamMsg.getStream());
|
||||||
|
sendRtpItem.setIp(requestPushStreamMsg.getIp());
|
||||||
|
sendRtpItem.setPort(requestPushStreamMsg.getPort());
|
||||||
|
sendRtpItem.setSsrc(requestPushStreamMsg.getSsrc());
|
||||||
|
sendRtpItem.setTcp(requestPushStreamMsg.isTcp());
|
||||||
|
sendRtpItem.setLocalPort(requestPushStreamMsg.getSrcPort());
|
||||||
|
sendRtpItem.setPt(requestPushStreamMsg.getPt());
|
||||||
|
sendRtpItem.setUsePs(requestPushStreamMsg.isPs());
|
||||||
|
sendRtpItem.setOnlyAudio(requestPushStreamMsg.isOnlyAudio());
|
||||||
|
return sendRtpItem;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SendRtpItem getInstance(String app, String stream, String ssrc, String dstIp, Integer dstPort, boolean tcp, int sendLocalPort, Integer pt) {
|
||||||
|
SendRtpItem sendRtpItem = new SendRtpItem();
|
||||||
|
sendRtpItem.setApp(app);
|
||||||
|
sendRtpItem.setStream(stream);
|
||||||
|
sendRtpItem.setSsrc(ssrc);
|
||||||
|
sendRtpItem.setTcp(tcp);
|
||||||
|
sendRtpItem.setLocalPort(sendLocalPort);
|
||||||
|
sendRtpItem.setIp(dstIp);
|
||||||
|
sendRtpItem.setPort(dstPort);
|
||||||
|
if (pt != null) {
|
||||||
|
sendRtpItem.setPt(pt);
|
||||||
|
}
|
||||||
|
|
||||||
|
return sendRtpItem;
|
||||||
|
}
|
||||||
|
|
||||||
public String getIp() {
|
public String getIp() {
|
||||||
return ip;
|
return ip;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,18 +1,17 @@
|
|||||||
package com.genersoft.iot.vmp.gb28181.event;
|
package com.genersoft.iot.vmp.gb28181.event;
|
||||||
|
|
||||||
import com.genersoft.iot.vmp.gb28181.bean.*;
|
import com.genersoft.iot.vmp.gb28181.bean.*;
|
||||||
|
import com.genersoft.iot.vmp.gb28181.event.alarm.AlarmEvent;
|
||||||
import com.genersoft.iot.vmp.gb28181.event.device.RequestTimeoutEvent;
|
import com.genersoft.iot.vmp.gb28181.event.device.RequestTimeoutEvent;
|
||||||
import com.genersoft.iot.vmp.gb28181.event.record.RecordEndEvent;
|
import com.genersoft.iot.vmp.gb28181.event.record.RecordEndEvent;
|
||||||
import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent;
|
import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent;
|
||||||
import com.genersoft.iot.vmp.gb28181.event.subscribe.mobilePosition.MobilePositionEvent;
|
import com.genersoft.iot.vmp.gb28181.event.subscribe.mobilePosition.MobilePositionEvent;
|
||||||
import com.genersoft.iot.vmp.media.zlm.event.ZLMOfflineEvent;
|
import com.genersoft.iot.vmp.media.event.mediaServer.MediaServerOfflineEvent;
|
||||||
import com.genersoft.iot.vmp.media.zlm.event.ZLMOnlineEvent;
|
import com.genersoft.iot.vmp.media.event.mediaServer.MediaServerOnlineEvent;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.context.ApplicationEventPublisher;
|
import org.springframework.context.ApplicationEventPublisher;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import com.genersoft.iot.vmp.gb28181.event.alarm.AlarmEvent;
|
|
||||||
|
|
||||||
import javax.sip.TimeoutEvent;
|
import javax.sip.TimeoutEvent;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
@ -40,14 +39,14 @@ public class EventPublisher {
|
|||||||
applicationEventPublisher.publishEvent(alarmEvent);
|
applicationEventPublisher.publishEvent(alarmEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void zlmOfflineEventPublish(String mediaServerId){
|
public void mediaServerOfflineEventPublish(String mediaServerId){
|
||||||
ZLMOfflineEvent outEvent = new ZLMOfflineEvent(this);
|
MediaServerOfflineEvent outEvent = new MediaServerOfflineEvent(this);
|
||||||
outEvent.setMediaServerId(mediaServerId);
|
outEvent.setMediaServerId(mediaServerId);
|
||||||
applicationEventPublisher.publishEvent(outEvent);
|
applicationEventPublisher.publishEvent(outEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void zlmOnlineEventPublish(String mediaServerId) {
|
public void mediaServerOnlineEventPublish(String mediaServerId) {
|
||||||
ZLMOnlineEvent outEvent = new ZLMOnlineEvent(this);
|
MediaServerOnlineEvent outEvent = new MediaServerOnlineEvent(this);
|
||||||
outEvent.setMediaServerId(mediaServerId);
|
outEvent.setMediaServerId(mediaServerId);
|
||||||
applicationEventPublisher.publishEvent(outEvent);
|
applicationEventPublisher.publishEvent(outEvent);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,6 +3,8 @@ package com.genersoft.iot.vmp.gb28181.session;
|
|||||||
import com.genersoft.iot.vmp.conf.SipConfig;
|
import com.genersoft.iot.vmp.conf.SipConfig;
|
||||||
import com.genersoft.iot.vmp.gb28181.bean.AudioBroadcastCatch;
|
import com.genersoft.iot.vmp.gb28181.bean.AudioBroadcastCatch;
|
||||||
import com.genersoft.iot.vmp.gb28181.utils.SipUtils;
|
import com.genersoft.iot.vmp.gb28181.utils.SipUtils;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
@ -18,11 +20,14 @@ import java.util.stream.Stream;
|
|||||||
@Component
|
@Component
|
||||||
public class AudioBroadcastManager {
|
public class AudioBroadcastManager {
|
||||||
|
|
||||||
|
private final static Logger logger = LoggerFactory.getLogger(AudioBroadcastManager.class);
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private SipConfig config;
|
private SipConfig config;
|
||||||
|
|
||||||
public static Map<String, AudioBroadcastCatch> data = new ConcurrentHashMap<>();
|
public static Map<String, AudioBroadcastCatch> data = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
|
||||||
public void update(AudioBroadcastCatch audioBroadcastCatch) {
|
public void update(AudioBroadcastCatch audioBroadcastCatch) {
|
||||||
if (SipUtils.isFrontEnd(audioBroadcastCatch.getDeviceId())) {
|
if (SipUtils.isFrontEnd(audioBroadcastCatch.getDeviceId())) {
|
||||||
audioBroadcastCatch.setChannelId(audioBroadcastCatch.getDeviceId());
|
audioBroadcastCatch.setChannelId(audioBroadcastCatch.getDeviceId());
|
||||||
|
|||||||
@ -1,16 +1,14 @@
|
|||||||
package com.genersoft.iot.vmp.gb28181.task;
|
package com.genersoft.iot.vmp.gb28181.task;
|
||||||
|
|
||||||
import com.alibaba.fastjson2.JSONObject;
|
|
||||||
import com.genersoft.iot.vmp.conf.UserSetting;
|
import com.genersoft.iot.vmp.conf.UserSetting;
|
||||||
import com.genersoft.iot.vmp.gb28181.bean.Device;
|
import com.genersoft.iot.vmp.gb28181.bean.Device;
|
||||||
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
|
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
|
||||||
import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
|
import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
|
||||||
import com.genersoft.iot.vmp.gb28181.session.SSRCFactory;
|
import com.genersoft.iot.vmp.gb28181.session.SSRCFactory;
|
||||||
import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform;
|
import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform;
|
||||||
import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
|
import com.genersoft.iot.vmp.media.bean.MediaServer;
|
||||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
|
||||||
import com.genersoft.iot.vmp.service.IDeviceService;
|
import com.genersoft.iot.vmp.service.IDeviceService;
|
||||||
import com.genersoft.iot.vmp.service.IMediaServerService;
|
import com.genersoft.iot.vmp.media.service.IMediaServerService;
|
||||||
import com.genersoft.iot.vmp.service.IPlatformService;
|
import com.genersoft.iot.vmp.service.IPlatformService;
|
||||||
import com.genersoft.iot.vmp.service.impl.PlatformServiceImpl;
|
import com.genersoft.iot.vmp.service.impl.PlatformServiceImpl;
|
||||||
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
|
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
|
||||||
@ -53,9 +51,6 @@ public class SipRunner implements CommandLineRunner {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private IDeviceService deviceService;
|
private IDeviceService deviceService;
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private ZLMRESTfulUtils zlmresTfulUtils;
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private IMediaServerService mediaServerService;
|
private IMediaServerService mediaServerService;
|
||||||
|
|
||||||
@ -105,17 +100,12 @@ public class SipRunner implements CommandLineRunner {
|
|||||||
List<SendRtpItem> sendRtpItems = redisCatchStorage.queryAllSendRTPServer();
|
List<SendRtpItem> sendRtpItems = redisCatchStorage.queryAllSendRTPServer();
|
||||||
if (sendRtpItems.size() > 0) {
|
if (sendRtpItems.size() > 0) {
|
||||||
for (SendRtpItem sendRtpItem : sendRtpItems) {
|
for (SendRtpItem sendRtpItem : sendRtpItems) {
|
||||||
MediaServerItem mediaServerItem = mediaServerService.getOne(sendRtpItem.getMediaServerId());
|
MediaServer mediaServerItem = mediaServerService.getOne(sendRtpItem.getMediaServerId());
|
||||||
redisCatchStorage.deleteSendRTPServer(sendRtpItem.getPlatformId(),sendRtpItem.getChannelId(), sendRtpItem.getCallId(),sendRtpItem.getStream());
|
redisCatchStorage.deleteSendRTPServer(sendRtpItem.getPlatformId(),sendRtpItem.getChannelId(), sendRtpItem.getCallId(),sendRtpItem.getStream());
|
||||||
if (mediaServerItem != null) {
|
if (mediaServerItem != null) {
|
||||||
ssrcFactory.releaseSsrc(sendRtpItem.getMediaServerId(), sendRtpItem.getSsrc());
|
ssrcFactory.releaseSsrc(sendRtpItem.getMediaServerId(), sendRtpItem.getSsrc());
|
||||||
Map<String, Object> param = new HashMap<>();
|
boolean stopResult = mediaServerService.stopSendRtp(mediaServerItem, sendRtpItem.getApp(), sendRtpItem.getStream(), sendRtpItem.getSsrc());
|
||||||
param.put("vhost","__defaultVhost__");
|
if (stopResult) {
|
||||||
param.put("app",sendRtpItem.getApp());
|
|
||||||
param.put("stream",sendRtpItem.getStream());
|
|
||||||
param.put("ssrc",sendRtpItem.getSsrc());
|
|
||||||
JSONObject jsonObject = zlmresTfulUtils.stopSendRtp(mediaServerItem, param);
|
|
||||||
if (jsonObject != null && jsonObject.getInteger("code") == 0) {
|
|
||||||
ParentPlatform platform = platformService.queryPlatformByServerGBId(sendRtpItem.getPlatformId());
|
ParentPlatform platform = platformService.queryPlatformByServerGBId(sendRtpItem.getPlatformId());
|
||||||
if (platform != null) {
|
if (platform != null) {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@ -7,8 +7,8 @@ import com.genersoft.iot.vmp.gb28181.bean.Device;
|
|||||||
import com.genersoft.iot.vmp.gb28181.bean.DeviceAlarm;
|
import com.genersoft.iot.vmp.gb28181.bean.DeviceAlarm;
|
||||||
import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
|
import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
|
||||||
import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
|
import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
|
||||||
import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe;
|
import com.genersoft.iot.vmp.media.event.hook.HookSubscribe;
|
||||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
import com.genersoft.iot.vmp.media.bean.MediaServer;
|
||||||
import com.genersoft.iot.vmp.service.bean.SSRCInfo;
|
import com.genersoft.iot.vmp.service.bean.SSRCInfo;
|
||||||
import gov.nist.javax.sip.message.SIPRequest;
|
import gov.nist.javax.sip.message.SIPRequest;
|
||||||
|
|
||||||
@ -100,7 +100,7 @@ public interface ISIPCommander {
|
|||||||
* @param device 视频设备
|
* @param device 视频设备
|
||||||
* @param channel 预览通道
|
* @param channel 预览通道
|
||||||
*/
|
*/
|
||||||
void playStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, DeviceChannel channel, ZlmHttpHookSubscribe.Event event, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException;
|
void playStreamCmd(MediaServer mediaServerItem, SSRCInfo ssrcInfo, Device device, DeviceChannel channel, HookSubscribe.Event event, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 请求回放视频流
|
* 请求回放视频流
|
||||||
@ -110,7 +110,7 @@ public interface ISIPCommander {
|
|||||||
* @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss
|
* @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss
|
||||||
* @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss
|
* @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss
|
||||||
*/
|
*/
|
||||||
void playbackStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInf, Device device, String channelId, String startTime, String endTime,ZlmHttpHookSubscribe.Event event, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException;
|
void playbackStreamCmd(MediaServer mediaServerItem, SSRCInfo ssrcInf, Device device, String channelId, String startTime, String endTime, HookSubscribe.Event event, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 请求历史媒体下载
|
* 请求历史媒体下载
|
||||||
@ -121,9 +121,9 @@ public interface ISIPCommander {
|
|||||||
* @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss
|
* @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss
|
||||||
* @param downloadSpeed 下载倍速参数
|
* @param downloadSpeed 下载倍速参数
|
||||||
*/
|
*/
|
||||||
void downloadStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId,
|
void downloadStreamCmd(MediaServer mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId,
|
||||||
String startTime, String endTime, int downloadSpeed, ZlmHttpHookSubscribe.Event hookEvent,
|
String startTime, String endTime, int downloadSpeed, HookSubscribe.Event hookEvent,
|
||||||
SipSubscribe.Event errorEvent,SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException;
|
SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -131,7 +131,7 @@ public interface ISIPCommander {
|
|||||||
*/
|
*/
|
||||||
void streamByeCmd(Device device, String channelId, String stream, String callId, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException, SsrcTransactionNotFoundException;
|
void streamByeCmd(Device device, String channelId, String stream, String callId, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException, SsrcTransactionNotFoundException;
|
||||||
|
|
||||||
void talkStreamCmd(MediaServerItem mediaServerItem, SendRtpItem sendRtpItem, Device device, String channelId, String callId, ZlmHttpHookSubscribe.Event event, ZlmHttpHookSubscribe.Event eventForPush, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException;
|
void talkStreamCmd(MediaServer mediaServerItem, SendRtpItem sendRtpItem, Device device, String channelId, String callId, HookSubscribe.Event event, HookSubscribe.Event eventForPush, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException;
|
||||||
|
|
||||||
|
|
||||||
void streamByeCmd(Device device, String channelId, String stream, String callId) throws InvalidArgumentException, ParseException, SipException, SsrcTransactionNotFoundException;
|
void streamByeCmd(Device device, String channelId, String stream, String callId) throws InvalidArgumentException, ParseException, SipException, SsrcTransactionNotFoundException;
|
||||||
|
|||||||
@ -3,8 +3,8 @@ package com.genersoft.iot.vmp.gb28181.transmit.cmd;
|
|||||||
import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException;
|
import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException;
|
||||||
import com.genersoft.iot.vmp.gb28181.bean.*;
|
import com.genersoft.iot.vmp.gb28181.bean.*;
|
||||||
import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
|
import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
|
||||||
import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe;
|
import com.genersoft.iot.vmp.media.event.hook.HookSubscribe;
|
||||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
import com.genersoft.iot.vmp.media.bean.MediaServer;
|
||||||
import com.genersoft.iot.vmp.service.bean.GPSMsgInfo;
|
import com.genersoft.iot.vmp.service.bean.GPSMsgInfo;
|
||||||
import com.genersoft.iot.vmp.service.bean.SSRCInfo;
|
import com.genersoft.iot.vmp.service.bean.SSRCInfo;
|
||||||
|
|
||||||
@ -154,8 +154,8 @@ public interface ISIPCommanderForPlatform {
|
|||||||
|
|
||||||
void streamByeCmd(ParentPlatform platform, String channelId, String stream, String callId, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException, SsrcTransactionNotFoundException;
|
void streamByeCmd(ParentPlatform platform, String channelId, String stream, String callId, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException, SsrcTransactionNotFoundException;
|
||||||
|
|
||||||
void broadcastInviteCmd(ParentPlatform platform, String channelId, MediaServerItem mediaServerItem,
|
void broadcastInviteCmd(ParentPlatform platform, String channelId, MediaServer mediaServerItem,
|
||||||
SSRCInfo ssrcInfo, ZlmHttpHookSubscribe.Event event, SipSubscribe.Event okEvent,
|
SSRCInfo ssrcInfo, HookSubscribe.Event event, SipSubscribe.Event okEvent,
|
||||||
SipSubscribe.Event errorEvent) throws ParseException, SipException, InvalidArgumentException;
|
SipSubscribe.Event errorEvent) throws ParseException, SipException, InvalidArgumentException;
|
||||||
|
|
||||||
void broadcastResultCmd(ParentPlatform platform, DeviceChannel deviceChannel, String sn, boolean result, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException;
|
void broadcastResultCmd(ParentPlatform platform, DeviceChannel deviceChannel, String sn, boolean result, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException;
|
||||||
|
|||||||
@ -7,10 +7,6 @@ import com.genersoft.iot.vmp.conf.UserSetting;
|
|||||||
import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException;
|
import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException;
|
||||||
import com.genersoft.iot.vmp.gb28181.SipLayer;
|
import com.genersoft.iot.vmp.gb28181.SipLayer;
|
||||||
import com.genersoft.iot.vmp.gb28181.bean.*;
|
import com.genersoft.iot.vmp.gb28181.bean.*;
|
||||||
import com.genersoft.iot.vmp.gb28181.bean.Device;
|
|
||||||
import com.genersoft.iot.vmp.gb28181.bean.DeviceAlarm;
|
|
||||||
import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
|
|
||||||
import com.genersoft.iot.vmp.gb28181.bean.SsrcTransaction;
|
|
||||||
import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
|
import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
|
||||||
import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
|
import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
|
||||||
import com.genersoft.iot.vmp.gb28181.transmit.SIPSender;
|
import com.genersoft.iot.vmp.gb28181.transmit.SIPSender;
|
||||||
@ -18,14 +14,11 @@ import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander;
|
|||||||
import com.genersoft.iot.vmp.gb28181.transmit.cmd.SIPRequestHeaderProvider;
|
import com.genersoft.iot.vmp.gb28181.transmit.cmd.SIPRequestHeaderProvider;
|
||||||
import com.genersoft.iot.vmp.gb28181.utils.NumericUtil;
|
import com.genersoft.iot.vmp.gb28181.utils.NumericUtil;
|
||||||
import com.genersoft.iot.vmp.gb28181.utils.SipUtils;
|
import com.genersoft.iot.vmp.gb28181.utils.SipUtils;
|
||||||
import com.genersoft.iot.vmp.media.zlm.ZLMServerFactory;
|
import com.genersoft.iot.vmp.media.event.hook.Hook;
|
||||||
import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe;
|
import com.genersoft.iot.vmp.media.event.hook.HookSubscribe;
|
||||||
import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeFactory;
|
import com.genersoft.iot.vmp.media.event.hook.HookType;
|
||||||
import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForStreamChange;
|
import com.genersoft.iot.vmp.media.service.IMediaServerService;
|
||||||
import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForStreamPush;
|
import com.genersoft.iot.vmp.media.bean.MediaServer;
|
||||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
|
||||||
import com.genersoft.iot.vmp.media.zlm.dto.hook.HookParam;
|
|
||||||
import com.genersoft.iot.vmp.service.IMediaServerService;
|
|
||||||
import com.genersoft.iot.vmp.service.bean.SSRCInfo;
|
import com.genersoft.iot.vmp.service.bean.SSRCInfo;
|
||||||
import com.genersoft.iot.vmp.utils.DateUtil;
|
import com.genersoft.iot.vmp.utils.DateUtil;
|
||||||
import gov.nist.javax.sip.message.SIPRequest;
|
import gov.nist.javax.sip.message.SIPRequest;
|
||||||
@ -44,7 +37,6 @@ import javax.sip.SipFactory;
|
|||||||
import javax.sip.header.CallIdHeader;
|
import javax.sip.header.CallIdHeader;
|
||||||
import javax.sip.message.Request;
|
import javax.sip.message.Request;
|
||||||
import java.text.ParseException;
|
import java.text.ParseException;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -77,13 +69,11 @@ public class SIPCommander implements ISIPCommander {
|
|||||||
private UserSetting userSetting;
|
private UserSetting userSetting;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private ZlmHttpHookSubscribe subscribe;
|
private HookSubscribe subscribe;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private IMediaServerService mediaServerService;
|
private IMediaServerService mediaServerService;
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private ZLMServerFactory zlmServerFactory;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -275,8 +265,8 @@ public class SIPCommander implements ISIPCommander {
|
|||||||
* @param errorEvent sip错误订阅
|
* @param errorEvent sip错误订阅
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void playStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, DeviceChannel channel,
|
public void playStreamCmd(MediaServer mediaServerItem, SSRCInfo ssrcInfo, Device device, DeviceChannel channel,
|
||||||
ZlmHttpHookSubscribe.Event event, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException {
|
HookSubscribe.Event event, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException {
|
||||||
String stream = ssrcInfo.getStream();
|
String stream = ssrcInfo.getStream();
|
||||||
|
|
||||||
if (device == null) {
|
if (device == null) {
|
||||||
@ -284,11 +274,11 @@ public class SIPCommander implements ISIPCommander {
|
|||||||
}
|
}
|
||||||
|
|
||||||
logger.info("{} 分配的ZLM为: {} [{}:{}]", stream, mediaServerItem.getId(), mediaServerItem.getSdpIp(), ssrcInfo.getPort());
|
logger.info("{} 分配的ZLM为: {} [{}:{}]", stream, mediaServerItem.getId(), mediaServerItem.getSdpIp(), ssrcInfo.getPort());
|
||||||
HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", stream, true, "rtsp", mediaServerItem.getId());
|
Hook rtpHook = Hook.getInstance(HookType.on_media_arrival, "rtp", stream, mediaServerItem.getId());
|
||||||
subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, HookParam hookParam) -> {
|
subscribe.addSubscribe(rtpHook, (hookData) -> {
|
||||||
if (event != null) {
|
if (event != null) {
|
||||||
event.response(mediaServerItemInUse, hookParam);
|
event.response(hookData);
|
||||||
subscribe.removeSubscribe(hookSubscribe);
|
subscribe.removeSubscribe(rtpHook);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
String sdpIp;
|
String sdpIp;
|
||||||
@ -384,8 +374,8 @@ public class SIPCommander implements ISIPCommander {
|
|||||||
* @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss
|
* @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void playbackStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId,
|
public void playbackStreamCmd(MediaServer mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId,
|
||||||
String startTime, String endTime, ZlmHttpHookSubscribe.Event hookEvent,
|
String startTime, String endTime, HookSubscribe.Event hookEvent,
|
||||||
SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException {
|
SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException {
|
||||||
|
|
||||||
|
|
||||||
@ -458,13 +448,13 @@ public class SIPCommander implements ISIPCommander {
|
|||||||
//ssrc
|
//ssrc
|
||||||
content.append("y=" + ssrcInfo.getSsrc() + "\r\n");
|
content.append("y=" + ssrcInfo.getSsrc() + "\r\n");
|
||||||
|
|
||||||
HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", ssrcInfo.getStream(), true, "rtsp", mediaServerItem.getId());
|
Hook rtpHook = Hook.getInstance(HookType.on_media_arrival, "rtp", ssrcInfo.getStream(), mediaServerItem.getId());
|
||||||
// 添加订阅
|
// 添加订阅
|
||||||
subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, HookParam hookParam) -> {
|
subscribe.addSubscribe(rtpHook, (hookData) -> {
|
||||||
if (hookEvent != null) {
|
if (hookEvent != null) {
|
||||||
hookEvent.response(mediaServerItemInUse, hookParam);
|
hookEvent.response(hookData);
|
||||||
}
|
}
|
||||||
subscribe.removeSubscribe(hookSubscribe);
|
subscribe.removeSubscribe(rtpHook);
|
||||||
});
|
});
|
||||||
Request request = headerProvider.createPlaybackInviteRequest(device, channelId, content.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()), ssrcInfo.getSsrc());
|
Request request = headerProvider.createPlaybackInviteRequest(device, channelId, content.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()), ssrcInfo.getSsrc());
|
||||||
|
|
||||||
@ -486,10 +476,10 @@ public class SIPCommander implements ISIPCommander {
|
|||||||
* @param downloadSpeed 下载倍速参数
|
* @param downloadSpeed 下载倍速参数
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void downloadStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId,
|
public void downloadStreamCmd(MediaServer mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId,
|
||||||
String startTime, String endTime, int downloadSpeed,
|
String startTime, String endTime, int downloadSpeed,
|
||||||
ZlmHttpHookSubscribe.Event hookEvent,
|
HookSubscribe.Event hookEvent,
|
||||||
SipSubscribe.Event errorEvent,SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException {
|
SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException {
|
||||||
|
|
||||||
logger.info("{} 分配的ZLM为: {} [{}:{}]", ssrcInfo.getStream(), mediaServerItem.getId(), mediaServerItem.getSdpIp(), ssrcInfo.getPort());
|
logger.info("{} 分配的ZLM为: {} [{}:{}]", ssrcInfo.getStream(), mediaServerItem.getId(), mediaServerItem.getSdpIp(), ssrcInfo.getPort());
|
||||||
String sdpIp;
|
String sdpIp;
|
||||||
@ -559,19 +549,18 @@ public class SIPCommander implements ISIPCommander {
|
|||||||
|
|
||||||
content.append("y=" + ssrcInfo.getSsrc() + "\r\n");//ssrc
|
content.append("y=" + ssrcInfo.getSsrc() + "\r\n");//ssrc
|
||||||
logger.debug("此时请求下载信令的ssrc===>{}",ssrcInfo.getSsrc());
|
logger.debug("此时请求下载信令的ssrc===>{}",ssrcInfo.getSsrc());
|
||||||
HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", ssrcInfo.getStream(), true, "rtsp", mediaServerItem.getId());
|
Hook rtpHook = Hook.getInstance(HookType.on_media_arrival, "rtp", ssrcInfo.getStream(), mediaServerItem.getId());
|
||||||
// 添加订阅
|
// 添加订阅
|
||||||
CallIdHeader newCallIdHeader = sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()), device.getTransport());
|
CallIdHeader newCallIdHeader = sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()), device.getTransport());
|
||||||
String callId= newCallIdHeader.getCallId();
|
String callId= newCallIdHeader.getCallId();
|
||||||
subscribe.addSubscribe(hookSubscribe, (mediaServerItemInUse, hookParam) -> {
|
subscribe.addSubscribe(rtpHook, (hookData) -> {
|
||||||
logger.debug("sipc 添加订阅===callId {}",callId);
|
logger.debug("sipc 添加订阅===callId {}",callId);
|
||||||
hookEvent.response(mediaServerItemInUse, hookParam);
|
hookEvent.response(hookData);
|
||||||
subscribe.removeSubscribe(hookSubscribe);
|
subscribe.removeSubscribe(rtpHook);
|
||||||
hookSubscribe.getContent().put("regist", false);
|
|
||||||
hookSubscribe.getContent().put("schema", "rtsp");
|
|
||||||
// 添加流注销的订阅,注销了后向设备发送bye
|
// 添加流注销的订阅,注销了后向设备发送bye
|
||||||
subscribe.addSubscribe(hookSubscribe,
|
Hook departureHook = Hook.getInstance(HookType.on_media_departure, "rtp", ssrcInfo.getStream(), mediaServerItem.getId());
|
||||||
(mediaServerItemForEnd, hookParam1) -> {
|
subscribe.addSubscribe(departureHook,
|
||||||
|
(departureHookData) -> {
|
||||||
logger.info("[录像]下载结束, 发送BYE");
|
logger.info("[录像]下载结束, 发送BYE");
|
||||||
try {
|
try {
|
||||||
streamByeCmd(device, channelId, ssrcInfo.getStream(), callId);
|
streamByeCmd(device, channelId, ssrcInfo.getStream(), callId);
|
||||||
@ -595,7 +584,7 @@ public class SIPCommander implements ISIPCommander {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void talkStreamCmd(MediaServerItem mediaServerItem, SendRtpItem sendRtpItem, Device device, String channelId, String callId, ZlmHttpHookSubscribe.Event event, ZlmHttpHookSubscribe.Event eventForPush, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException {
|
public void talkStreamCmd(MediaServer mediaServerItem, SendRtpItem sendRtpItem, Device device, String channelId, String callId, HookSubscribe.Event event, HookSubscribe.Event eventForPush, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException {
|
||||||
|
|
||||||
String stream = sendRtpItem.getStream();
|
String stream = sendRtpItem.getStream();
|
||||||
|
|
||||||
@ -609,20 +598,20 @@ public class SIPCommander implements ISIPCommander {
|
|||||||
}
|
}
|
||||||
|
|
||||||
logger.info("[语音喊话] {} 分配的ZLM为: {} [{}:{}]", stream, mediaServerItem.getId(), mediaServerItem.getIp(), sendRtpItem.getPort());
|
logger.info("[语音喊话] {} 分配的ZLM为: {} [{}:{}]", stream, mediaServerItem.getId(), mediaServerItem.getIp(), sendRtpItem.getPort());
|
||||||
HookSubscribeForStreamChange hookSubscribeForStreamChange = HookSubscribeFactory.on_stream_changed("rtp", stream, true, "rtsp", mediaServerItem.getId());
|
Hook hook = Hook.getInstance(HookType.on_media_arrival, "rtp", stream, mediaServerItem.getId());
|
||||||
subscribe.addSubscribe(hookSubscribeForStreamChange, (mediaServerItemInUse, hookParam) -> {
|
subscribe.addSubscribe(hook, (hookData) -> {
|
||||||
if (event != null) {
|
if (event != null) {
|
||||||
event.response(mediaServerItemInUse, hookParam);
|
event.response(hookData);
|
||||||
subscribe.removeSubscribe(hookSubscribeForStreamChange);
|
subscribe.removeSubscribe(hook);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
CallIdHeader callIdHeader = sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()), device.getTransport());
|
CallIdHeader callIdHeader = sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()), device.getTransport());
|
||||||
callIdHeader.setCallId(callId);
|
callIdHeader.setCallId(callId);
|
||||||
HookSubscribeForStreamPush hookSubscribeForStreamPush = HookSubscribeFactory.on_publish("rtp", stream, null, mediaServerItem.getId());
|
Hook publishHook = Hook.getInstance(HookType.on_publish, "rtp", stream, mediaServerItem.getId());
|
||||||
subscribe.addSubscribe(hookSubscribeForStreamPush, (mediaServerItemInUse, hookParam) -> {
|
subscribe.addSubscribe(publishHook, (hookData) -> {
|
||||||
if (eventForPush != null) {
|
if (eventForPush != null) {
|
||||||
eventForPush.response(mediaServerItemInUse, hookParam);
|
eventForPush.response(hookData);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
//
|
//
|
||||||
@ -1265,7 +1254,6 @@ public class SIPCommander implements ISIPCommander {
|
|||||||
* @param startPriority 报警起始级别(可选)
|
* @param startPriority 报警起始级别(可选)
|
||||||
* @param endPriority 报警终止级别(可选)
|
* @param endPriority 报警终止级别(可选)
|
||||||
* @param alarmMethod 报警方式条件(可选)
|
* @param alarmMethod 报警方式条件(可选)
|
||||||
* @param alarmType 报警类型
|
|
||||||
* @param startTime 报警发生起始时间(可选)
|
* @param startTime 报警发生起始时间(可选)
|
||||||
* @param endTime 报警发生终止时间(可选)
|
* @param endTime 报警发生终止时间(可选)
|
||||||
* @return true = 命令发送成功
|
* @return true = 命令发送成功
|
||||||
|
|||||||
@ -13,13 +13,11 @@ import com.genersoft.iot.vmp.gb28181.transmit.SIPSender;
|
|||||||
import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform;
|
import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform;
|
||||||
import com.genersoft.iot.vmp.gb28181.transmit.cmd.SIPRequestHeaderPlarformProvider;
|
import com.genersoft.iot.vmp.gb28181.transmit.cmd.SIPRequestHeaderPlarformProvider;
|
||||||
import com.genersoft.iot.vmp.gb28181.utils.SipUtils;
|
import com.genersoft.iot.vmp.gb28181.utils.SipUtils;
|
||||||
import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe;
|
import com.genersoft.iot.vmp.media.bean.MediaServer;
|
||||||
import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeFactory;
|
import com.genersoft.iot.vmp.media.event.hook.Hook;
|
||||||
import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForStreamChange;
|
import com.genersoft.iot.vmp.media.event.hook.HookSubscribe;
|
||||||
import com.genersoft.iot.vmp.media.zlm.ZLMServerFactory;
|
import com.genersoft.iot.vmp.media.event.hook.HookType;
|
||||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
import com.genersoft.iot.vmp.media.service.IMediaServerService;
|
||||||
import com.genersoft.iot.vmp.media.zlm.dto.hook.HookParam;
|
|
||||||
import com.genersoft.iot.vmp.service.IMediaServerService;
|
|
||||||
import com.genersoft.iot.vmp.service.bean.GPSMsgInfo;
|
import com.genersoft.iot.vmp.service.bean.GPSMsgInfo;
|
||||||
import com.genersoft.iot.vmp.service.bean.SSRCInfo;
|
import com.genersoft.iot.vmp.service.bean.SSRCInfo;
|
||||||
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
|
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
|
||||||
@ -66,9 +64,6 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private SipSubscribe sipSubscribe;
|
private SipSubscribe sipSubscribe;
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private ZLMServerFactory zlmServerFactory;
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private SipLayer sipLayer;
|
private SipLayer sipLayer;
|
||||||
|
|
||||||
@ -76,7 +71,7 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform {
|
|||||||
private SIPSender sipSender;
|
private SIPSender sipSender;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private ZlmHttpHookSubscribe subscribe;
|
private HookSubscribe subscribe;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private UserSetting userSetting;
|
private UserSetting userSetting;
|
||||||
@ -844,10 +839,10 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform {
|
|||||||
}
|
}
|
||||||
logger.info("[向上级发送BYE], {}/{}", platform.getServerGBId(), sendRtpItem.getChannelId());
|
logger.info("[向上级发送BYE], {}/{}", platform.getServerGBId(), sendRtpItem.getChannelId());
|
||||||
String mediaServerId = sendRtpItem.getMediaServerId();
|
String mediaServerId = sendRtpItem.getMediaServerId();
|
||||||
MediaServerItem mediaServerItem = mediaServerService.getOne(mediaServerId);
|
MediaServer mediaServerItem = mediaServerService.getOne(mediaServerId);
|
||||||
if (mediaServerItem != null) {
|
if (mediaServerItem != null) {
|
||||||
mediaServerService.releaseSsrc(mediaServerItem.getId(), sendRtpItem.getSsrc());
|
mediaServerService.releaseSsrc(mediaServerItem.getId(), sendRtpItem.getSsrc());
|
||||||
zlmServerFactory.closeRtpServer(mediaServerItem, sendRtpItem.getStream());
|
mediaServerService.closeRTPServer(mediaServerItem, sendRtpItem.getStream());
|
||||||
}
|
}
|
||||||
SIPRequest byeRequest = headerProviderPlatformProvider.createByeRequest(platform, sendRtpItem);
|
SIPRequest byeRequest = headerProviderPlatformProvider.createByeRequest(platform, sendRtpItem);
|
||||||
if (byeRequest == null) {
|
if (byeRequest == null) {
|
||||||
@ -895,8 +890,8 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void broadcastInviteCmd(ParentPlatform platform, String channelId, MediaServerItem mediaServerItem,
|
public void broadcastInviteCmd(ParentPlatform platform, String channelId, MediaServer mediaServerItem,
|
||||||
SSRCInfo ssrcInfo, ZlmHttpHookSubscribe.Event event, SipSubscribe.Event okEvent,
|
SSRCInfo ssrcInfo, HookSubscribe.Event event, SipSubscribe.Event okEvent,
|
||||||
SipSubscribe.Event errorEvent) throws ParseException, SipException, InvalidArgumentException {
|
SipSubscribe.Event errorEvent) throws ParseException, SipException, InvalidArgumentException {
|
||||||
String stream = ssrcInfo.getStream();
|
String stream = ssrcInfo.getStream();
|
||||||
|
|
||||||
@ -905,11 +900,11 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform {
|
|||||||
}
|
}
|
||||||
|
|
||||||
logger.info("{} 分配的ZLM为: {} [{}:{}]", stream, mediaServerItem.getId(), mediaServerItem.getIp(), ssrcInfo.getPort());
|
logger.info("{} 分配的ZLM为: {} [{}:{}]", stream, mediaServerItem.getId(), mediaServerItem.getIp(), ssrcInfo.getPort());
|
||||||
HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", stream, true, "rtsp", mediaServerItem.getId());
|
Hook hook = Hook.getInstance(HookType.on_media_arrival, "rtp", stream, mediaServerItem.getId());
|
||||||
subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, HookParam hookParam) -> {
|
subscribe.addSubscribe(hook, (hookData) -> {
|
||||||
if (event != null) {
|
if (event != null) {
|
||||||
event.response(mediaServerItemInUse, hookParam);
|
event.response(hookData);
|
||||||
subscribe.removeSubscribe(hookSubscribe);
|
subscribe.removeSubscribe(hook);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
String sdpIp = mediaServerItem.getSdpIp();
|
String sdpIp = mediaServerItem.getSdpIp();
|
||||||
@ -949,7 +944,7 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform {
|
|||||||
sipSender.transmitRequest(sipLayer.getLocalIp(platform.getDeviceIp()), request, (e -> {
|
sipSender.transmitRequest(sipLayer.getLocalIp(platform.getDeviceIp()), request, (e -> {
|
||||||
streamSession.remove(platform.getServerGBId(), channelId, ssrcInfo.getStream());
|
streamSession.remove(platform.getServerGBId(), channelId, ssrcInfo.getStream());
|
||||||
mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
|
mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
|
||||||
subscribe.removeSubscribe(hookSubscribe);
|
subscribe.removeSubscribe(hook);
|
||||||
errorEvent.response(e);
|
errorEvent.response(e);
|
||||||
}), e -> {
|
}), e -> {
|
||||||
ResponseEvent responseEvent = (ResponseEvent) e.event;
|
ResponseEvent responseEvent = (ResponseEvent) e.event;
|
||||||
|
|||||||
@ -1,19 +1,17 @@
|
|||||||
package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl;
|
package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl;
|
||||||
|
|
||||||
import com.alibaba.fastjson2.JSONObject;
|
|
||||||
import com.genersoft.iot.vmp.conf.DynamicTask;
|
import com.genersoft.iot.vmp.conf.DynamicTask;
|
||||||
import com.genersoft.iot.vmp.conf.UserSetting;
|
import com.genersoft.iot.vmp.conf.UserSetting;
|
||||||
|
import com.genersoft.iot.vmp.conf.exception.ControllerException;
|
||||||
import com.genersoft.iot.vmp.gb28181.bean.Device;
|
import com.genersoft.iot.vmp.gb28181.bean.Device;
|
||||||
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
|
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
|
||||||
import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
|
import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
|
||||||
import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver;
|
import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver;
|
||||||
import com.genersoft.iot.vmp.gb28181.transmit.event.request.ISIPRequestProcessor;
|
import com.genersoft.iot.vmp.gb28181.transmit.event.request.ISIPRequestProcessor;
|
||||||
import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
|
import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
|
||||||
import com.genersoft.iot.vmp.media.zlm.ZLMServerFactory;
|
import com.genersoft.iot.vmp.media.bean.MediaServer;
|
||||||
import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe;
|
import com.genersoft.iot.vmp.media.service.IMediaServerService;
|
||||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
|
||||||
import com.genersoft.iot.vmp.service.IDeviceService;
|
import com.genersoft.iot.vmp.service.IDeviceService;
|
||||||
import com.genersoft.iot.vmp.service.IMediaServerService;
|
|
||||||
import com.genersoft.iot.vmp.service.IPlayService;
|
import com.genersoft.iot.vmp.service.IPlayService;
|
||||||
import com.genersoft.iot.vmp.service.bean.RequestPushStreamMsg;
|
import com.genersoft.iot.vmp.service.bean.RequestPushStreamMsg;
|
||||||
import com.genersoft.iot.vmp.service.redisMsg.RedisGbPlayMsgListener;
|
import com.genersoft.iot.vmp.service.redisMsg.RedisGbPlayMsgListener;
|
||||||
@ -31,8 +29,6 @@ import javax.sip.header.CallIdHeader;
|
|||||||
import javax.sip.header.FromHeader;
|
import javax.sip.header.FromHeader;
|
||||||
import javax.sip.header.HeaderAddress;
|
import javax.sip.header.HeaderAddress;
|
||||||
import javax.sip.header.ToHeader;
|
import javax.sip.header.ToHeader;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SIP命令类型: ACK请求
|
* SIP命令类型: ACK请求
|
||||||
@ -65,12 +61,6 @@ public class AckRequestProcessor extends SIPRequestProcessorParent implements In
|
|||||||
@Autowired
|
@Autowired
|
||||||
private IDeviceService deviceService;
|
private IDeviceService deviceService;
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private ZLMServerFactory zlmServerFactory;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private ZlmHttpHookSubscribe hookSubscribe;
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private IMediaServerService mediaServerService;
|
private IMediaServerService mediaServerService;
|
||||||
|
|
||||||
@ -104,7 +94,7 @@ public class AckRequestProcessor extends SIPRequestProcessorParent implements In
|
|||||||
logger.info("收到ACK,rtp/{} TCP主动方式后续处理", sendRtpItem.getStream());
|
logger.info("收到ACK,rtp/{} TCP主动方式后续处理", sendRtpItem.getStream());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId());
|
MediaServer mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId());
|
||||||
logger.info("收到ACK,rtp/{}开始向上级推流, 目标={}:{},SSRC={}, 协议:{}",
|
logger.info("收到ACK,rtp/{}开始向上级推流, 目标={}:{},SSRC={}, 协议:{}",
|
||||||
sendRtpItem.getStream(),
|
sendRtpItem.getStream(),
|
||||||
sendRtpItem.getIp(),
|
sendRtpItem.getIp(),
|
||||||
@ -115,19 +105,21 @@ public class AckRequestProcessor extends SIPRequestProcessorParent implements In
|
|||||||
ParentPlatform parentPlatform = storager.queryParentPlatByServerGBId(fromUserId);
|
ParentPlatform parentPlatform = storager.queryParentPlatByServerGBId(fromUserId);
|
||||||
|
|
||||||
if (parentPlatform != null) {
|
if (parentPlatform != null) {
|
||||||
Map<String, Object> param = getSendRtpParam(sendRtpItem);
|
|
||||||
if (!userSetting.getServerId().equals(sendRtpItem.getServerId())) {
|
if (!userSetting.getServerId().equals(sendRtpItem.getServerId())) {
|
||||||
RequestPushStreamMsg requestPushStreamMsg = RequestPushStreamMsg.getInstance(
|
RequestPushStreamMsg requestPushStreamMsg = RequestPushStreamMsg.getInstance(sendRtpItem);
|
||||||
sendRtpItem.getMediaServerId(), sendRtpItem.getApp(), sendRtpItem.getStream(),
|
redisGbPlayMsgListener.sendMsgForStartSendRtpStream(sendRtpItem.getServerId(), requestPushStreamMsg, () -> {
|
||||||
sendRtpItem.getIp(), sendRtpItem.getPort(), sendRtpItem.getSsrc(), sendRtpItem.isTcp(),
|
playService.startSendRtpStreamFailHand(sendRtpItem, parentPlatform, callIdHeader);
|
||||||
sendRtpItem.getLocalPort(), sendRtpItem.getPt(), sendRtpItem.isUsePs(), sendRtpItem.isOnlyAudio());
|
|
||||||
redisGbPlayMsgListener.sendMsgForStartSendRtpStream(sendRtpItem.getServerId(), requestPushStreamMsg, json -> {
|
|
||||||
playService.startSendRtpStreamHand(sendRtpItem, parentPlatform, json, param, callIdHeader);
|
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
JSONObject startSendRtpStreamResult = sendRtp(sendRtpItem, mediaInfo, param);
|
try {
|
||||||
if (startSendRtpStreamResult != null) {
|
if (sendRtpItem.isTcpActive()) {
|
||||||
playService.startSendRtpStreamHand(sendRtpItem, parentPlatform, startSendRtpStreamResult, param, callIdHeader);
|
mediaServerService.startSendRtpPassive(mediaInfo, parentPlatform, sendRtpItem, null);
|
||||||
|
} else {
|
||||||
|
mediaServerService.startSendRtp(mediaInfo, parentPlatform, sendRtpItem);
|
||||||
|
}
|
||||||
|
}catch (ControllerException e) {
|
||||||
|
logger.error("RTP推流失败: {}", e.getMessage());
|
||||||
|
playService.startSendRtpStreamFailHand(sendRtpItem, parentPlatform, callIdHeader);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}else {
|
}else {
|
||||||
@ -144,56 +136,17 @@ public class AckRequestProcessor extends SIPRequestProcessorParent implements In
|
|||||||
logger.warn("[收到ACK]:来自{},目标为({})的推流信息为找到流体服务[{}]信息",fromUserId, toUserId, sendRtpItem.getMediaServerId());
|
logger.warn("[收到ACK]:来自{},目标为({})的推流信息为找到流体服务[{}]信息",fromUserId, toUserId, sendRtpItem.getMediaServerId());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Map<String, Object> param = getSendRtpParam(sendRtpItem);
|
try {
|
||||||
JSONObject startSendRtpStreamResult = sendRtp(sendRtpItem, mediaInfo, param);
|
if (sendRtpItem.isTcpActive()) {
|
||||||
if (startSendRtpStreamResult != null) {
|
mediaServerService.startSendRtpPassive(mediaInfo, null, sendRtpItem, null);
|
||||||
playService.startSendRtpStreamHand(sendRtpItem, device, startSendRtpStreamResult, param, callIdHeader);
|
} else {
|
||||||
|
mediaServerService.startSendRtp(mediaInfo, null, sendRtpItem);
|
||||||
|
}
|
||||||
|
}catch (ControllerException e) {
|
||||||
|
logger.error("RTP推流失败: {}", e.getMessage());
|
||||||
|
playService.startSendRtpStreamFailHand(sendRtpItem, null, callIdHeader);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map<String, Object> getSendRtpParam(SendRtpItem sendRtpItem) {
|
|
||||||
String isUdp = sendRtpItem.isTcp() ? "0" : "1";
|
|
||||||
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("dst_url",sendRtpItem.getIp());
|
|
||||||
param.put("dst_port", sendRtpItem.getPort());
|
|
||||||
param.put("src_port", sendRtpItem.getLocalPort());
|
|
||||||
param.put("pt", sendRtpItem.getPt());
|
|
||||||
param.put("use_ps", sendRtpItem.isUsePs() ? "1" : "0");
|
|
||||||
param.put("only_audio", sendRtpItem.isOnlyAudio() ? "1" : "0");
|
|
||||||
param.put("is_udp", isUdp);
|
|
||||||
if (!sendRtpItem.isTcp()) {
|
|
||||||
// udp模式下开启rtcp保活
|
|
||||||
param.put("udp_rtcp_timeout", sendRtpItem.isRtcp()? "1":"0");
|
|
||||||
}
|
|
||||||
return param;
|
|
||||||
}
|
|
||||||
|
|
||||||
private JSONObject sendRtp(SendRtpItem sendRtpItem, MediaServerItem mediaInfo, Map<String, Object> param){
|
|
||||||
JSONObject startSendRtpStreamResult = null;
|
|
||||||
if (sendRtpItem.getLocalPort() != 0) {
|
|
||||||
if (sendRtpItem.isTcpActive()) {
|
|
||||||
startSendRtpStreamResult = zlmServerFactory.startSendRtpPassive(mediaInfo, param);
|
|
||||||
}else {
|
|
||||||
param.put("dst_url", sendRtpItem.getIp());
|
|
||||||
param.put("dst_port", sendRtpItem.getPort());
|
|
||||||
startSendRtpStreamResult = zlmServerFactory.startSendRtpStream(mediaInfo, param);
|
|
||||||
}
|
|
||||||
}else {
|
|
||||||
if (sendRtpItem.isTcpActive()) {
|
|
||||||
startSendRtpStreamResult = zlmServerFactory.startSendRtpPassive(mediaInfo, param);
|
|
||||||
}else {
|
|
||||||
param.put("dst_url", sendRtpItem.getIp());
|
|
||||||
param.put("dst_port", sendRtpItem.getPort());
|
|
||||||
startSendRtpStreamResult = zlmServerFactory.startSendRtpStream(mediaInfo, param);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return startSendRtpStreamResult;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,15 +6,15 @@ import com.genersoft.iot.vmp.conf.UserSetting;
|
|||||||
import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException;
|
import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException;
|
||||||
import com.genersoft.iot.vmp.gb28181.bean.*;
|
import com.genersoft.iot.vmp.gb28181.bean.*;
|
||||||
import com.genersoft.iot.vmp.gb28181.session.AudioBroadcastManager;
|
import com.genersoft.iot.vmp.gb28181.session.AudioBroadcastManager;
|
||||||
import com.genersoft.iot.vmp.gb28181.session.SSRCFactory;
|
|
||||||
import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
|
import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
|
||||||
import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver;
|
import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver;
|
||||||
import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander;
|
import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander;
|
||||||
import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform;
|
import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform;
|
||||||
import com.genersoft.iot.vmp.gb28181.transmit.event.request.ISIPRequestProcessor;
|
import com.genersoft.iot.vmp.gb28181.transmit.event.request.ISIPRequestProcessor;
|
||||||
import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
|
import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
|
||||||
import com.genersoft.iot.vmp.media.zlm.ZLMServerFactory;
|
import com.genersoft.iot.vmp.media.bean.MediaInfo;
|
||||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
import com.genersoft.iot.vmp.media.bean.MediaServer;
|
||||||
|
import com.genersoft.iot.vmp.media.service.IMediaServerService;
|
||||||
import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem;
|
import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem;
|
||||||
import com.genersoft.iot.vmp.service.*;
|
import com.genersoft.iot.vmp.service.*;
|
||||||
import com.genersoft.iot.vmp.service.bean.MessageForPushChannel;
|
import com.genersoft.iot.vmp.service.bean.MessageForPushChannel;
|
||||||
@ -35,8 +35,6 @@ import javax.sip.SipException;
|
|||||||
import javax.sip.header.CallIdHeader;
|
import javax.sip.header.CallIdHeader;
|
||||||
import javax.sip.message.Response;
|
import javax.sip.message.Response;
|
||||||
import java.text.ParseException;
|
import java.text.ParseException;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SIP命令类型: BYE请求
|
* SIP命令类型: BYE请求
|
||||||
@ -74,12 +72,6 @@ public class ByeRequestProcessor extends SIPRequestProcessorParent implements In
|
|||||||
@Autowired
|
@Autowired
|
||||||
private IVideoManagerStorage storager;
|
private IVideoManagerStorage storager;
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private ZLMServerFactory zlmServerFactory;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private SSRCFactory ssrcFactory;
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private IMediaServerService mediaServerService;
|
private IMediaServerService mediaServerService;
|
||||||
|
|
||||||
@ -109,7 +101,6 @@ public class ByeRequestProcessor extends SIPRequestProcessorParent implements In
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 处理BYE请求
|
* 处理BYE请求
|
||||||
* @param evt
|
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void process(RequestEvent evt) {
|
public void process(RequestEvent evt) {
|
||||||
@ -127,11 +118,6 @@ public class ByeRequestProcessor extends SIPRequestProcessorParent implements In
|
|||||||
logger.info("[收到bye] 来自{},停止通道:{}, 类型: {}, callId: {}", sendRtpItem.getPlatformId(), sendRtpItem.getChannelId(), sendRtpItem.getPlayType(), callIdHeader.getCallId());
|
logger.info("[收到bye] 来自{},停止通道:{}, 类型: {}, callId: {}", sendRtpItem.getPlatformId(), sendRtpItem.getChannelId(), sendRtpItem.getPlayType(), callIdHeader.getCallId());
|
||||||
|
|
||||||
String streamId = sendRtpItem.getStream();
|
String streamId = sendRtpItem.getStream();
|
||||||
Map<String, Object> param = new HashMap<>();
|
|
||||||
param.put("vhost","__defaultVhost__");
|
|
||||||
param.put("app",sendRtpItem.getApp());
|
|
||||||
param.put("stream",streamId);
|
|
||||||
param.put("ssrc",sendRtpItem.getSsrc());
|
|
||||||
logger.info("[收到bye] 停止推流:{}, 媒体节点: {}", streamId, sendRtpItem.getMediaServerId());
|
logger.info("[收到bye] 停止推流:{}, 媒体节点: {}", streamId, sendRtpItem.getMediaServerId());
|
||||||
|
|
||||||
if (sendRtpItem.getPlayType().equals(InviteStreamType.PUSH)) {
|
if (sendRtpItem.getPlayType().equals(InviteStreamType.PUSH)) {
|
||||||
@ -145,10 +131,10 @@ public class ByeRequestProcessor extends SIPRequestProcessorParent implements In
|
|||||||
redisGbPlayMsgListener.sendMsgForStopSendRtpStream(sendRtpItem.getServerId(), streamMsg);
|
redisGbPlayMsgListener.sendMsgForStopSendRtpStream(sendRtpItem.getServerId(), streamMsg);
|
||||||
}
|
}
|
||||||
}else {
|
}else {
|
||||||
MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId());
|
MediaServer mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId());
|
||||||
redisCatchStorage.deleteSendRTPServer(sendRtpItem.getPlatformId(), sendRtpItem.getChannelId(),
|
redisCatchStorage.deleteSendRTPServer(sendRtpItem.getPlatformId(), sendRtpItem.getChannelId(),
|
||||||
callIdHeader.getCallId(), null);
|
callIdHeader.getCallId(), null);
|
||||||
zlmServerFactory.stopSendRtpStream(mediaInfo, param);
|
mediaServerService.stopSendRtp(mediaInfo, sendRtpItem.getApp(), sendRtpItem.getStream(), sendRtpItem.getSsrc());
|
||||||
if (userSetting.getUseCustomSsrcForParentInvite()) {
|
if (userSetting.getUseCustomSsrcForParentInvite()) {
|
||||||
mediaServerService.releaseSsrc(mediaInfo.getId(), sendRtpItem.getSsrc());
|
mediaServerService.releaseSsrc(mediaInfo.getId(), sendRtpItem.getSsrc());
|
||||||
}
|
}
|
||||||
@ -165,16 +151,16 @@ public class ByeRequestProcessor extends SIPRequestProcessorParent implements In
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}else {
|
}else {
|
||||||
MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId());
|
MediaServer mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId());
|
||||||
redisCatchStorage.deleteSendRTPServer(sendRtpItem.getPlatformId(), sendRtpItem.getChannelId(),
|
redisCatchStorage.deleteSendRTPServer(sendRtpItem.getPlatformId(), sendRtpItem.getChannelId(),
|
||||||
callIdHeader.getCallId(), null);
|
callIdHeader.getCallId(), null);
|
||||||
zlmServerFactory.stopSendRtpStream(mediaInfo, param);
|
mediaServerService.stopSendRtp(mediaInfo, sendRtpItem.getApp(), sendRtpItem.getStream(), sendRtpItem.getSsrc());
|
||||||
if (userSetting.getUseCustomSsrcForParentInvite()) {
|
if (userSetting.getUseCustomSsrcForParentInvite()) {
|
||||||
mediaServerService.releaseSsrc(mediaInfo.getId(), sendRtpItem.getSsrc());
|
mediaServerService.releaseSsrc(mediaInfo.getId(), sendRtpItem.getSsrc());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId());
|
MediaServer mediaServer = mediaServerService.getOne(sendRtpItem.getMediaServerId());
|
||||||
if (mediaInfo != null) {
|
if (mediaServer != null) {
|
||||||
AudioBroadcastCatch audioBroadcastCatch = audioBroadcastManager.get(sendRtpItem.getDeviceId(), sendRtpItem.getChannelId());
|
AudioBroadcastCatch audioBroadcastCatch = audioBroadcastManager.get(sendRtpItem.getDeviceId(), sendRtpItem.getChannelId());
|
||||||
if (audioBroadcastCatch != null && audioBroadcastCatch.getSipTransactionInfo().getCallId().equals(callIdHeader.getCallId())) {
|
if (audioBroadcastCatch != null && audioBroadcastCatch.getSipTransactionInfo().getCallId().equals(callIdHeader.getCallId())) {
|
||||||
// 来自上级平台的停止对讲
|
// 来自上级平台的停止对讲
|
||||||
@ -182,8 +168,9 @@ public class ByeRequestProcessor extends SIPRequestProcessorParent implements In
|
|||||||
audioBroadcastManager.del(sendRtpItem.getDeviceId(), sendRtpItem.getChannelId());
|
audioBroadcastManager.del(sendRtpItem.getDeviceId(), sendRtpItem.getChannelId());
|
||||||
}
|
}
|
||||||
|
|
||||||
int totalReaderCount = zlmServerFactory.totalReaderCount(mediaInfo, sendRtpItem.getApp(), streamId);
|
MediaInfo mediaInfo = mediaServerService.getMediaInfo(mediaServer, sendRtpItem.getApp(), streamId);
|
||||||
if (totalReaderCount <= 0) {
|
|
||||||
|
if (mediaInfo.getReaderCount() <= 0) {
|
||||||
logger.info("[收到bye] {} 无其它观看者,通知设备停止推流", streamId);
|
logger.info("[收到bye] {} 无其它观看者,通知设备停止推流", streamId);
|
||||||
if (sendRtpItem.getPlayType().equals(InviteStreamType.PLAY)) {
|
if (sendRtpItem.getPlayType().equals(InviteStreamType.PLAY)) {
|
||||||
Device device = deviceService.getDevice(sendRtpItem.getDeviceId());
|
Device device = deviceService.getDevice(sendRtpItem.getDeviceId());
|
||||||
@ -245,7 +232,7 @@ public class ByeRequestProcessor extends SIPRequestProcessorParent implements In
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 释放ssrc
|
// 释放ssrc
|
||||||
MediaServerItem mediaServerItem = mediaServerService.getOne(ssrcTransaction.getMediaServerId());
|
MediaServer mediaServerItem = mediaServerService.getOne(ssrcTransaction.getMediaServerId());
|
||||||
if (mediaServerItem != null) {
|
if (mediaServerItem != null) {
|
||||||
mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcTransaction.getSsrc());
|
mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcTransaction.getSsrc());
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,6 +8,7 @@ import com.genersoft.iot.vmp.common.VideoManagerConstants;
|
|||||||
import com.genersoft.iot.vmp.conf.DynamicTask;
|
import com.genersoft.iot.vmp.conf.DynamicTask;
|
||||||
import com.genersoft.iot.vmp.conf.SipConfig;
|
import com.genersoft.iot.vmp.conf.SipConfig;
|
||||||
import com.genersoft.iot.vmp.conf.UserSetting;
|
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.bean.*;
|
||||||
import com.genersoft.iot.vmp.gb28181.session.AudioBroadcastManager;
|
import com.genersoft.iot.vmp.gb28181.session.AudioBroadcastManager;
|
||||||
import com.genersoft.iot.vmp.gb28181.session.SSRCFactory;
|
import com.genersoft.iot.vmp.gb28181.session.SSRCFactory;
|
||||||
@ -18,12 +19,18 @@ import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform;
|
|||||||
import com.genersoft.iot.vmp.gb28181.transmit.event.request.ISIPRequestProcessor;
|
import com.genersoft.iot.vmp.gb28181.transmit.event.request.ISIPRequestProcessor;
|
||||||
import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
|
import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
|
||||||
import com.genersoft.iot.vmp.gb28181.utils.SipUtils;
|
import com.genersoft.iot.vmp.gb28181.utils.SipUtils;
|
||||||
|
import com.genersoft.iot.vmp.media.bean.MediaServer;
|
||||||
|
import com.genersoft.iot.vmp.media.event.hook.Hook;
|
||||||
|
import com.genersoft.iot.vmp.media.event.hook.HookSubscribe;
|
||||||
|
import com.genersoft.iot.vmp.media.event.hook.HookType;
|
||||||
|
import com.genersoft.iot.vmp.media.service.IMediaServerService;
|
||||||
import com.genersoft.iot.vmp.media.zlm.ZLMMediaListManager;
|
import com.genersoft.iot.vmp.media.zlm.ZLMMediaListManager;
|
||||||
import com.genersoft.iot.vmp.media.zlm.ZLMServerFactory;
|
import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem;
|
||||||
import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe;
|
import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem;
|
||||||
import com.genersoft.iot.vmp.media.zlm.dto.*;
|
import com.genersoft.iot.vmp.service.IInviteStreamService;
|
||||||
import com.genersoft.iot.vmp.media.zlm.dto.hook.OnStreamChangedHookParam;
|
import com.genersoft.iot.vmp.service.IPlayService;
|
||||||
import com.genersoft.iot.vmp.service.*;
|
import com.genersoft.iot.vmp.service.IStreamProxyService;
|
||||||
|
import com.genersoft.iot.vmp.service.IStreamPushService;
|
||||||
import com.genersoft.iot.vmp.service.bean.ErrorCallback;
|
import com.genersoft.iot.vmp.service.bean.ErrorCallback;
|
||||||
import com.genersoft.iot.vmp.service.bean.InviteErrorCode;
|
import com.genersoft.iot.vmp.service.bean.InviteErrorCode;
|
||||||
import com.genersoft.iot.vmp.service.bean.MessageForPushChannel;
|
import com.genersoft.iot.vmp.service.bean.MessageForPushChannel;
|
||||||
@ -54,7 +61,6 @@ import javax.sip.header.CallIdHeader;
|
|||||||
import javax.sip.message.Response;
|
import javax.sip.message.Response;
|
||||||
import java.text.ParseException;
|
import java.text.ParseException;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
import java.util.Vector;
|
import java.util.Vector;
|
||||||
@ -106,14 +112,11 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
|
|||||||
@Autowired
|
@Autowired
|
||||||
private AudioBroadcastManager audioBroadcastManager;
|
private AudioBroadcastManager audioBroadcastManager;
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private ZLMServerFactory zlmServerFactory;
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private IMediaServerService mediaServerService;
|
private IMediaServerService mediaServerService;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private ZlmHttpHookSubscribe zlmHttpHookSubscribe;
|
private HookSubscribe hookSubscribe;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private SIPProcessorObserver sipProcessorObserver;
|
private SIPProcessorObserver sipProcessorObserver;
|
||||||
@ -192,7 +195,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
|
|||||||
GbStream gbStream = storager.queryStreamInParentPlatform(requesterId, channelId);
|
GbStream gbStream = storager.queryStreamInParentPlatform(requesterId, channelId);
|
||||||
PlatformCatalog catalog = storager.getCatalog(requesterId, channelId);
|
PlatformCatalog catalog = storager.getCatalog(requesterId, channelId);
|
||||||
|
|
||||||
MediaServerItem mediaServerItem = null;
|
MediaServer mediaServerItem = null;
|
||||||
StreamPushItem streamPushItem = null;
|
StreamPushItem streamPushItem = null;
|
||||||
StreamProxyItem proxyByAppAndStream = null;
|
StreamProxyItem proxyByAppAndStream = null;
|
||||||
// 不是通道可能是直播流
|
// 不是通道可能是直播流
|
||||||
@ -375,8 +378,9 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
|
|||||||
} else {
|
} else {
|
||||||
streamTypeStr = "UDP";
|
streamTypeStr = "UDP";
|
||||||
}
|
}
|
||||||
logger.info("[上级Invite] {}, 平台:{}, 通道:{}, 收流地址:{}:{},收流方式:{}, ssrc:{}", sessionName, username, channelId, addressStr, port, streamTypeStr, ssrc);
|
logger.info("[上级Invite] {}, 平台:{}, 通道:{}, 收流地址:{}:{},收流方式:{}, ssrc:{}",
|
||||||
SendRtpItem sendRtpItem = zlmServerFactory.createSendRtpItem(mediaServerItem, addressStr, port, ssrc, requesterId,
|
sessionName, username, channelId, addressStr, port, streamTypeStr, ssrc);
|
||||||
|
SendRtpItem sendRtpItem = mediaServerService.createSendRtpItem(mediaServerItem, addressStr, port, ssrc, requesterId,
|
||||||
device.getDeviceId(), channelId, mediaTransmissionTCP, platform.isRtcp());
|
device.getDeviceId(), channelId, mediaTransmissionTCP, platform.isRtcp());
|
||||||
|
|
||||||
if (tcpActive != null) {
|
if (tcpActive != null) {
|
||||||
@ -398,7 +402,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
|
|||||||
Long finalStopTime = stopTime;
|
Long finalStopTime = stopTime;
|
||||||
ErrorCallback<Object> hookEvent = (code, msg, data) -> {
|
ErrorCallback<Object> hookEvent = (code, msg, data) -> {
|
||||||
StreamInfo streamInfo = (StreamInfo)data;
|
StreamInfo streamInfo = (StreamInfo)data;
|
||||||
MediaServerItem mediaServerItemInUSe = mediaServerService.getOne(streamInfo.getMediaServerId());
|
MediaServer mediaServerItemInUSe = mediaServerService.getOne(streamInfo.getMediaServerId());
|
||||||
logger.info("[上级Invite]下级已经开始推流。 回复200OK(SDP), {}/{}", streamInfo.getApp(), streamInfo.getStream());
|
logger.info("[上级Invite]下级已经开始推流。 回复200OK(SDP), {}/{}", streamInfo.getApp(), streamInfo.getStream());
|
||||||
// * 0 等待设备推流上来
|
// * 0 等待设备推流上来
|
||||||
// * 1 下级已经推流,等待上级平台回复ack
|
// * 1 下级已经推流,等待上级平台回复ack
|
||||||
@ -455,42 +459,21 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
|
|||||||
responseSdpAck(request, content.toString(), platform);
|
responseSdpAck(request, content.toString(), platform);
|
||||||
// tcp主动模式,回复sdp后开启监听
|
// tcp主动模式,回复sdp后开启监听
|
||||||
if (sendRtpItem.isTcpActive()) {
|
if (sendRtpItem.isTcpActive()) {
|
||||||
MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId());
|
MediaServer mediaServer = mediaServerService.getOne(sendRtpItem.getMediaServerId());
|
||||||
Map<String, Object> param = new HashMap<>(12);
|
try {
|
||||||
param.put("vhost","__defaultVhost__");
|
mediaServerService.startSendRtpPassive(mediaServer, platform, sendRtpItem, 5);
|
||||||
param.put("app",sendRtpItem.getApp());
|
}catch (ControllerException e) {}
|
||||||
param.put("stream",sendRtpItem.getStream());
|
|
||||||
param.put("ssrc", sendRtpItem.getSsrc());
|
|
||||||
if (!sendRtpItem.isTcpActive()) {
|
|
||||||
param.put("dst_url",sendRtpItem.getIp());
|
|
||||||
param.put("dst_port", sendRtpItem.getPort());
|
|
||||||
}
|
|
||||||
String is_Udp = sendRtpItem.isTcp() ? "0" : "1";
|
|
||||||
param.put("is_udp", is_Udp);
|
|
||||||
param.put("src_port", localPort);
|
|
||||||
param.put("pt", sendRtpItem.getPt());
|
|
||||||
param.put("use_ps", sendRtpItem.isUsePs() ? "1" : "0");
|
|
||||||
param.put("only_audio", sendRtpItem.isOnlyAudio() ? "1" : "0");
|
|
||||||
if (!sendRtpItem.isTcp()) {
|
|
||||||
// 开启rtcp保活
|
|
||||||
param.put("udp_rtcp_timeout", sendRtpItem.isRtcp()? "1":"0");
|
|
||||||
}
|
|
||||||
JSONObject startSendRtpStreamResult = zlmServerFactory.startSendRtpPassive(mediaInfo, param);
|
|
||||||
if (startSendRtpStreamResult != null) {
|
|
||||||
startSendRtpStreamHand(evt, sendRtpItem, null, startSendRtpStreamResult, param, callIdHeader);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} catch (SipException | InvalidArgumentException | ParseException e) {
|
} catch (SipException | InvalidArgumentException | ParseException e) {
|
||||||
logger.error("[命令发送失败] 国标级联 回复SdpAck", e);
|
logger.error("[命令发送失败] 国标级联 回复SdpAck", e);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
ErrorCallback<Object> errorEvent = ((statusCode, msg, data) -> {
|
ErrorCallback<Object> errorEvent = ((statusCode, msg, data) -> {
|
||||||
|
logger.info("[上级Invite] {}, 失败, 平台:{}, 通道:{}, code: {}, msg;{}", sessionName, username, channelId, statusCode, msg);
|
||||||
// 未知错误。直接转发设备点播的错误
|
// 未知错误。直接转发设备点播的错误
|
||||||
try {
|
try {
|
||||||
if (statusCode > 0) {
|
Response response = getMessageFactory().createResponse(statusCode, evt.getRequest());
|
||||||
Response response = getMessageFactory().createResponse(statusCode, evt.getRequest());
|
sipSender.transmitRequest(request.getLocalAddress().getHostAddress(), response);
|
||||||
sipSender.transmitRequest(request.getLocalAddress().getHostAddress(), response);
|
|
||||||
}
|
|
||||||
} catch (ParseException | SipException e) {
|
} catch (ParseException | SipException e) {
|
||||||
logger.error("未处理的异常 ", e);
|
logger.error("未处理的异常 ", e);
|
||||||
}
|
}
|
||||||
@ -501,7 +484,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
|
|||||||
String startTimeStr = DateUtil.urlFormatter.format(start);
|
String startTimeStr = DateUtil.urlFormatter.format(start);
|
||||||
String endTimeStr = DateUtil.urlFormatter.format(end);
|
String endTimeStr = DateUtil.urlFormatter.format(end);
|
||||||
String stream = device.getDeviceId() + "_" + channelId + "_" + startTimeStr + "_" + endTimeStr;
|
String stream = device.getDeviceId() + "_" + channelId + "_" + startTimeStr + "_" + endTimeStr;
|
||||||
SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, stream, null, device.isSsrcCheck(), true, 0,false, false, device.getStreamModeForParam());
|
SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, stream, null, device.isSsrcCheck(), true, 0,false,!channel.isHasAudio(), false, device.getStreamModeForParam());
|
||||||
sendRtpItem.setStream(stream);
|
sendRtpItem.setStream(stream);
|
||||||
// 写入redis, 超时时回复
|
// 写入redis, 超时时回复
|
||||||
redisCatchStorage.updateSendRTPSever(sendRtpItem);
|
redisCatchStorage.updateSendRTPSever(sendRtpItem);
|
||||||
@ -531,7 +514,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
|
|||||||
}
|
}
|
||||||
|
|
||||||
sendRtpItem.setPlayType(InviteStreamType.DOWNLOAD);
|
sendRtpItem.setPlayType(InviteStreamType.DOWNLOAD);
|
||||||
SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, null, null, device.isSsrcCheck(), true, 0, false, false, device.getStreamModeForParam());
|
SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, null, null, device.isSsrcCheck(), true, 0, false,!channel.isHasAudio(), false, device.getStreamModeForParam());
|
||||||
sendRtpItem.setStream(ssrcInfo.getStream());
|
sendRtpItem.setStream(ssrcInfo.getStream());
|
||||||
// 写入redis, 超时时回复
|
// 写入redis, 超时时回复
|
||||||
redisCatchStorage.updateSendRTPSever(sendRtpItem);
|
redisCatchStorage.updateSendRTPSever(sendRtpItem);
|
||||||
@ -581,12 +564,11 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
|
|||||||
if ("push".equals(gbStream.getStreamType())) {
|
if ("push".equals(gbStream.getStreamType())) {
|
||||||
if (streamPushItem != null) {
|
if (streamPushItem != null) {
|
||||||
// 从redis查询是否正在接收这个推流
|
// 从redis查询是否正在接收这个推流
|
||||||
OnStreamChangedHookParam pushListItem = redisCatchStorage.getPushListItem(gbStream.getApp(), gbStream.getStream());
|
StreamPushItem pushListItem = redisCatchStorage.getPushListItem(gbStream.getApp(), gbStream.getStream());
|
||||||
if (pushListItem != null) {
|
if (pushListItem != null) {
|
||||||
StreamPushItem transform = streamPushService.transform(pushListItem);
|
pushListItem.setSelf(userSetting.getServerId().equals(pushListItem.getServerId()));
|
||||||
transform.setSelf(userSetting.getServerId().equals(pushListItem.getSeverId()));
|
|
||||||
// 推流状态
|
// 推流状态
|
||||||
pushStream(evt, request, gbStream, transform, platform, callIdHeader, mediaServerItem, port, tcpActive,
|
pushStream(evt, request, gbStream, pushListItem, platform, callIdHeader, mediaServerItem, port, tcpActive,
|
||||||
mediaTransmissionTCP, channelId, addressStr, ssrc, requesterId);
|
mediaTransmissionTCP, channelId, addressStr, ssrc, requesterId);
|
||||||
}else {
|
}else {
|
||||||
// 未推流 拉起
|
// 未推流 拉起
|
||||||
@ -633,13 +615,14 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
|
|||||||
* 安排推流
|
* 安排推流
|
||||||
*/
|
*/
|
||||||
private void pushProxyStream(RequestEvent evt, SIPRequest request, GbStream gbStream, ParentPlatform platform,
|
private void pushProxyStream(RequestEvent evt, SIPRequest request, GbStream gbStream, ParentPlatform platform,
|
||||||
CallIdHeader callIdHeader, MediaServerItem mediaServerItem,
|
CallIdHeader callIdHeader, MediaServer mediaServer,
|
||||||
int port, Boolean tcpActive, boolean mediaTransmissionTCP,
|
int port, Boolean tcpActive, boolean mediaTransmissionTCP,
|
||||||
String channelId, String addressStr, String ssrc, String requesterId) {
|
String channelId, String addressStr, String ssrc, String requesterId) {
|
||||||
Boolean streamReady = zlmServerFactory.isStreamReady(mediaServerItem, gbStream.getApp(), gbStream.getStream());
|
Boolean streamReady = mediaServerService.isStreamReady(mediaServer, gbStream.getApp(), gbStream.getStream());
|
||||||
if (streamReady != null && streamReady) {
|
if (streamReady != null && streamReady) {
|
||||||
|
|
||||||
// 自平台内容
|
// 自平台内容
|
||||||
SendRtpItem sendRtpItem = zlmServerFactory.createSendRtpItem(mediaServerItem, addressStr, port, ssrc, requesterId,
|
SendRtpItem sendRtpItem = mediaServerService.createSendRtpItem(mediaServer, addressStr, port, ssrc, requesterId,
|
||||||
gbStream.getApp(), gbStream.getStream(), channelId, mediaTransmissionTCP, platform.isRtcp());
|
gbStream.getApp(), gbStream.getStream(), channelId, mediaTransmissionTCP, platform.isRtcp());
|
||||||
|
|
||||||
if (sendRtpItem == null) {
|
if (sendRtpItem == null) {
|
||||||
@ -660,7 +643,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
|
|||||||
sendRtpItem.setCallId(callIdHeader.getCallId());
|
sendRtpItem.setCallId(callIdHeader.getCallId());
|
||||||
sendRtpItem.setFromTag(request.getFromTag());
|
sendRtpItem.setFromTag(request.getFromTag());
|
||||||
|
|
||||||
SIPResponse response = sendStreamAck(mediaServerItem, request, sendRtpItem, platform, evt);
|
SIPResponse response = sendStreamAck(mediaServer, request, sendRtpItem, platform, evt);
|
||||||
if (response != null) {
|
if (response != null) {
|
||||||
sendRtpItem.setToTag(response.getToTag());
|
sendRtpItem.setToTag(response.getToTag());
|
||||||
}
|
}
|
||||||
@ -671,15 +654,15 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void pushStream(RequestEvent evt, SIPRequest request, GbStream gbStream, StreamPushItem streamPushItem, ParentPlatform platform,
|
private void pushStream(RequestEvent evt, SIPRequest request, GbStream gbStream, StreamPushItem streamPushItem, ParentPlatform platform,
|
||||||
CallIdHeader callIdHeader, MediaServerItem mediaServerItem,
|
CallIdHeader callIdHeader, MediaServer mediaServerItem,
|
||||||
int port, Boolean tcpActive, boolean mediaTransmissionTCP,
|
int port, Boolean tcpActive, boolean mediaTransmissionTCP,
|
||||||
String channelId, String addressStr, String ssrc, String requesterId) {
|
String channelId, String addressStr, String ssrc, String requesterId) {
|
||||||
// 推流
|
// 推流
|
||||||
if (streamPushItem.isSelf()) {
|
if (streamPushItem.isSelf()) {
|
||||||
Boolean streamReady = zlmServerFactory.isStreamReady(mediaServerItem, gbStream.getApp(), gbStream.getStream());
|
Boolean streamReady = mediaServerService.isStreamReady(mediaServerItem, gbStream.getApp(), gbStream.getStream());
|
||||||
if (streamReady != null && streamReady) {
|
if (streamReady != null && streamReady) {
|
||||||
// 自平台内容
|
// 自平台内容
|
||||||
SendRtpItem sendRtpItem = zlmServerFactory.createSendRtpItem(mediaServerItem, addressStr, port, ssrc, requesterId,
|
SendRtpItem sendRtpItem = mediaServerService.createSendRtpItem(mediaServerItem, addressStr, port, ssrc, requesterId,
|
||||||
gbStream.getApp(), gbStream.getStream(), channelId, mediaTransmissionTCP, platform.isRtcp());
|
gbStream.getApp(), gbStream.getStream(), channelId, mediaTransmissionTCP, platform.isRtcp());
|
||||||
|
|
||||||
if (sendRtpItem == null) {
|
if (sendRtpItem == null) {
|
||||||
@ -723,24 +706,23 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
|
|||||||
* 通知流上线
|
* 通知流上线
|
||||||
*/
|
*/
|
||||||
private void notifyStreamOnline(RequestEvent evt, SIPRequest request, GbStream gbStream, StreamPushItem streamPushItem, ParentPlatform platform,
|
private void notifyStreamOnline(RequestEvent evt, SIPRequest request, GbStream gbStream, StreamPushItem streamPushItem, ParentPlatform platform,
|
||||||
CallIdHeader callIdHeader, MediaServerItem mediaServerItem,
|
CallIdHeader callIdHeader, MediaServer mediaServerItem,
|
||||||
int port, Boolean tcpActive, boolean mediaTransmissionTCP,
|
int port, Boolean tcpActive, boolean mediaTransmissionTCP,
|
||||||
String channelId, String addressStr, String ssrc, String requesterId) {
|
String channelId, String addressStr, String ssrc, String requesterId) {
|
||||||
if ("proxy".equals(gbStream.getStreamType())) {
|
if ("proxy".equals(gbStream.getStreamType())) {
|
||||||
// TODO 控制启用以使设备上线
|
// TODO 控制启用以使设备上线
|
||||||
logger.info("[ app={}, stream={} ]通道未推流,启用流后开始推流", gbStream.getApp(), gbStream.getStream());
|
logger.info("[ app={}, stream={} ]通道未推流,启用流后开始推流", gbStream.getApp(), gbStream.getStream());
|
||||||
// 监听流上线
|
// 监听流上线
|
||||||
HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed(gbStream.getApp(), gbStream.getStream(), true, "rtsp", mediaServerItem.getId());
|
Hook hook = Hook.getInstance(HookType.on_media_arrival, gbStream.getApp(), gbStream.getStream(), mediaServerItem.getId());
|
||||||
zlmHttpHookSubscribe.addSubscribe(hookSubscribe, (mediaServerItemInUSe, hookParam) -> {
|
this.hookSubscribe.addSubscribe(hook, (hookData) -> {
|
||||||
OnStreamChangedHookParam streamChangedHookParam = (OnStreamChangedHookParam)hookParam;
|
logger.info("[上级点播]拉流代理已经就绪, {}/{}", hookData.getApp(), hookData.getStream());
|
||||||
logger.info("[上级点播]拉流代理已经就绪, {}/{}", streamChangedHookParam.getApp(), streamChangedHookParam.getStream());
|
|
||||||
dynamicTask.stop(callIdHeader.getCallId());
|
dynamicTask.stop(callIdHeader.getCallId());
|
||||||
pushProxyStream(evt, request, gbStream, platform, callIdHeader, mediaServerItem, port, tcpActive,
|
pushProxyStream(evt, request, gbStream, platform, callIdHeader, mediaServerItem, port, tcpActive,
|
||||||
mediaTransmissionTCP, channelId, addressStr, ssrc, requesterId);
|
mediaTransmissionTCP, channelId, addressStr, ssrc, requesterId);
|
||||||
});
|
});
|
||||||
dynamicTask.startDelay(callIdHeader.getCallId(), () -> {
|
dynamicTask.startDelay(callIdHeader.getCallId(), () -> {
|
||||||
logger.info("[ app={}, stream={} ] 等待拉流代理流超时", gbStream.getApp(), gbStream.getStream());
|
logger.info("[ app={}, stream={} ] 等待拉流代理流超时", gbStream.getApp(), gbStream.getStream());
|
||||||
zlmHttpHookSubscribe.removeSubscribe(hookSubscribe);
|
this.hookSubscribe.removeSubscribe(hook);
|
||||||
}, userSetting.getPlatformPlayTimeout());
|
}, userSetting.getPlatformPlayTimeout());
|
||||||
boolean start = streamProxyService.start(gbStream.getApp(), gbStream.getStream());
|
boolean start = streamProxyService.start(gbStream.getApp(), gbStream.getStream());
|
||||||
if (!start) {
|
if (!start) {
|
||||||
@ -749,7 +731,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
|
|||||||
} catch (SipException | InvalidArgumentException | ParseException e) {
|
} catch (SipException | InvalidArgumentException | ParseException e) {
|
||||||
logger.error("[命令发送失败] invite 通道未推流: {}", e.getMessage());
|
logger.error("[命令发送失败] invite 通道未推流: {}", e.getMessage());
|
||||||
}
|
}
|
||||||
zlmHttpHookSubscribe.removeSubscribe(hookSubscribe);
|
this.hookSubscribe.removeSubscribe(hook);
|
||||||
dynamicTask.stop(callIdHeader.getCallId());
|
dynamicTask.stop(callIdHeader.getCallId());
|
||||||
}
|
}
|
||||||
} else if ("push".equals(gbStream.getStreamType())) {
|
} else if ("push".equals(gbStream.getStreamType())) {
|
||||||
@ -790,7 +772,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
|
|||||||
dynamicTask.stop(callIdHeader.getCallId());
|
dynamicTask.stop(callIdHeader.getCallId());
|
||||||
redisPushStreamResponseListener.removeEvent(gbStream.getApp(), gbStream.getStream());
|
redisPushStreamResponseListener.removeEvent(gbStream.getApp(), gbStream.getStream());
|
||||||
if (serverId.equals(userSetting.getServerId())) {
|
if (serverId.equals(userSetting.getServerId())) {
|
||||||
SendRtpItem sendRtpItem = zlmServerFactory.createSendRtpItem(mediaServerItem, addressStr, finalPort, ssrc, requesterId,
|
SendRtpItem sendRtpItem = mediaServerService.createSendRtpItem(mediaServerItem, addressStr, finalPort, ssrc, requesterId,
|
||||||
app, stream, channelId, mediaTransmissionTCP, platform.isRtcp());
|
app, stream, channelId, mediaTransmissionTCP, platform.isRtcp());
|
||||||
|
|
||||||
if (sendRtpItem == null) {
|
if (sendRtpItem == null) {
|
||||||
@ -846,7 +828,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
|
|||||||
* 来自其他wvp的推流
|
* 来自其他wvp的推流
|
||||||
*/
|
*/
|
||||||
private void otherWvpPushStream(RequestEvent evt, SIPRequest request, GbStream gbStream, StreamPushItem streamPushItem, ParentPlatform platform,
|
private void otherWvpPushStream(RequestEvent evt, SIPRequest request, GbStream gbStream, StreamPushItem streamPushItem, ParentPlatform platform,
|
||||||
CallIdHeader callIdHeader, MediaServerItem mediaServerItem,
|
CallIdHeader callIdHeader, MediaServer mediaServerItem,
|
||||||
int port, Boolean tcpActive, boolean mediaTransmissionTCP,
|
int port, Boolean tcpActive, boolean mediaTransmissionTCP,
|
||||||
String channelId, String addressStr, String ssrc, String requesterId) {
|
String channelId, String addressStr, String ssrc, String requesterId) {
|
||||||
logger.info("[级联点播]直播流来自其他平台,发送redis消息");
|
logger.info("[级联点播]直播流来自其他平台,发送redis消息");
|
||||||
@ -909,7 +891,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public SIPResponse sendStreamAck(MediaServerItem mediaServerItem, SIPRequest request, SendRtpItem sendRtpItem, ParentPlatform platform, RequestEvent evt) {
|
public SIPResponse sendStreamAck(MediaServer mediaServerItem, SIPRequest request, SendRtpItem sendRtpItem, ParentPlatform platform, RequestEvent evt) {
|
||||||
|
|
||||||
String sdpIp = mediaServerItem.getSdpIp();
|
String sdpIp = mediaServerItem.getSdpIp();
|
||||||
if (!ObjectUtils.isEmpty(platform.getSendStreamIp())) {
|
if (!ObjectUtils.isEmpty(platform.getSendStreamIp())) {
|
||||||
@ -1055,7 +1037,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
|
|||||||
logger.info("设备{}请求语音流,地址:{}:{},ssrc:{}, {}", requesterId, addressStr, port, gb28181Sdp.getSsrc(),
|
logger.info("设备{}请求语音流,地址:{}:{},ssrc:{}, {}", requesterId, addressStr, port, gb28181Sdp.getSsrc(),
|
||||||
mediaTransmissionTCP ? (tcpActive ? "TCP主动" : "TCP被动") : "UDP");
|
mediaTransmissionTCP ? (tcpActive ? "TCP主动" : "TCP被动") : "UDP");
|
||||||
|
|
||||||
MediaServerItem mediaServerItem = broadcastCatch.getMediaServerItem();
|
MediaServer mediaServerItem = broadcastCatch.getMediaServerItem();
|
||||||
if (mediaServerItem == null) {
|
if (mediaServerItem == null) {
|
||||||
logger.warn("未找到语音喊话使用的zlm");
|
logger.warn("未找到语音喊话使用的zlm");
|
||||||
try {
|
try {
|
||||||
@ -1070,7 +1052,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
|
|||||||
mediaTransmissionTCP ? (tcpActive ? "TCP主动" : "TCP被动") : "UDP", sdp.getSessionName().getValue());
|
mediaTransmissionTCP ? (tcpActive ? "TCP主动" : "TCP被动") : "UDP", sdp.getSessionName().getValue());
|
||||||
CallIdHeader callIdHeader = (CallIdHeader) request.getHeader(CallIdHeader.NAME);
|
CallIdHeader callIdHeader = (CallIdHeader) request.getHeader(CallIdHeader.NAME);
|
||||||
|
|
||||||
SendRtpItem sendRtpItem = zlmServerFactory.createSendRtpItem(mediaServerItem, addressStr, port, gb28181Sdp.getSsrc(), requesterId,
|
SendRtpItem sendRtpItem = mediaServerService.createSendRtpItem(mediaServerItem, addressStr, port, gb28181Sdp.getSsrc(), requesterId,
|
||||||
device.getDeviceId(), broadcastCatch.getChannelId(),
|
device.getDeviceId(), broadcastCatch.getChannelId(),
|
||||||
mediaTransmissionTCP, false);
|
mediaTransmissionTCP, false);
|
||||||
|
|
||||||
@ -1104,7 +1086,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
|
|||||||
|
|
||||||
redisCatchStorage.updateSendRTPSever(sendRtpItem);
|
redisCatchStorage.updateSendRTPSever(sendRtpItem);
|
||||||
|
|
||||||
Boolean streamReady = zlmServerFactory.isStreamReady(mediaServerItem, broadcastCatch.getApp(), broadcastCatch.getStream());
|
Boolean streamReady = mediaServerService.isStreamReady(mediaServerItem, broadcastCatch.getApp(), broadcastCatch.getStream());
|
||||||
if (streamReady) {
|
if (streamReady) {
|
||||||
sendOk(device, sendRtpItem, sdp, request, mediaServerItem, mediaTransmissionTCP, gb28181Sdp.getSsrc());
|
sendOk(device, sendRtpItem, sdp, request, mediaServerItem, mediaTransmissionTCP, gb28181Sdp.getSsrc());
|
||||||
} else {
|
} else {
|
||||||
@ -1132,7 +1114,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SIPResponse sendOk(Device device, SendRtpItem sendRtpItem, SessionDescription sdp, SIPRequest request, MediaServerItem mediaServerItem, boolean mediaTransmissionTCP, String ssrc) {
|
SIPResponse sendOk(Device device, SendRtpItem sendRtpItem, SessionDescription sdp, SIPRequest request, MediaServer mediaServerItem, boolean mediaTransmissionTCP, String ssrc) {
|
||||||
SIPResponse sipResponse = null;
|
SIPResponse sipResponse = null;
|
||||||
try {
|
try {
|
||||||
sendRtpItem.setStatus(2);
|
sendRtpItem.setStatus(2);
|
||||||
|
|||||||
@ -37,7 +37,7 @@ public class MessageRequestProcessor extends SIPRequestProcessorParent implement
|
|||||||
|
|
||||||
private final String method = "MESSAGE";
|
private final String method = "MESSAGE";
|
||||||
|
|
||||||
private static Map<String, IMessageHandler> messageHandlerMap = new ConcurrentHashMap<>();
|
private static final Map<String, IMessageHandler> messageHandlerMap = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private SIPProcessorObserver sipProcessorObserver;
|
private SIPProcessorObserver sipProcessorObserver;
|
||||||
@ -100,9 +100,9 @@ public class MessageRequestProcessor extends SIPRequestProcessorParent implement
|
|||||||
deviceNotFoundEvent.setCallId(callIdHeader.getCallId());
|
deviceNotFoundEvent.setCallId(callIdHeader.getCallId());
|
||||||
SipSubscribe.EventResult eventResult = new SipSubscribe.EventResult(deviceNotFoundEvent);
|
SipSubscribe.EventResult eventResult = new SipSubscribe.EventResult(deviceNotFoundEvent);
|
||||||
sipSubscribe.getErrorSubscribe(callIdHeader.getCallId()).response(eventResult);
|
sipSubscribe.getErrorSubscribe(callIdHeader.getCallId()).response(eventResult);
|
||||||
};
|
}
|
||||||
}else {
|
}else {
|
||||||
Element rootElement = null;
|
Element rootElement;
|
||||||
try {
|
try {
|
||||||
rootElement = getRootElement(evt);
|
rootElement = getRootElement(evt);
|
||||||
if (rootElement == null) {
|
if (rootElement == null) {
|
||||||
@ -110,24 +110,24 @@ public class MessageRequestProcessor extends SIPRequestProcessorParent implement
|
|||||||
responseAck(request, Response.BAD_REQUEST, "content is null");
|
responseAck(request, Response.BAD_REQUEST, "content is null");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
String name = rootElement.getName();
|
||||||
|
IMessageHandler messageHandler = messageHandlerMap.get(name);
|
||||||
|
if (messageHandler != null) {
|
||||||
|
if (device != null) {
|
||||||
|
messageHandler.handForDevice(evt, device, rootElement);
|
||||||
|
}else { // 由于上面已经判断都为null则直接返回,所以这里device和parentPlatform必有一个不为null
|
||||||
|
messageHandler.handForPlatform(evt, parentPlatform, rootElement);
|
||||||
|
}
|
||||||
|
}else {
|
||||||
|
// 不支持的message
|
||||||
|
// 不存在则回复415
|
||||||
|
responseAck(request, Response.UNSUPPORTED_MEDIA_TYPE, "Unsupported message type, must Control/Notify/Query/Response");
|
||||||
|
}
|
||||||
} catch (DocumentException e) {
|
} catch (DocumentException e) {
|
||||||
logger.warn("解析XML消息内容异常", e);
|
logger.warn("解析XML消息内容异常", e);
|
||||||
// 不存在则回复404
|
// 不存在则回复404
|
||||||
responseAck(request, Response.BAD_REQUEST, e.getMessage());
|
responseAck(request, Response.BAD_REQUEST, e.getMessage());
|
||||||
}
|
}
|
||||||
String name = rootElement.getName();
|
|
||||||
IMessageHandler messageHandler = messageHandlerMap.get(name);
|
|
||||||
if (messageHandler != null) {
|
|
||||||
if (device != null) {
|
|
||||||
messageHandler.handForDevice(evt, device, rootElement);
|
|
||||||
}else { // 由于上面已经判断都为null则直接返回,所以这里device和parentPlatform必有一个不为null
|
|
||||||
messageHandler.handForPlatform(evt, parentPlatform, rootElement);
|
|
||||||
}
|
|
||||||
}else {
|
|
||||||
// 不支持的message
|
|
||||||
// 不存在则回复415
|
|
||||||
responseAck(request, Response.UNSUPPORTED_MEDIA_TYPE, "Unsupported message type, must Control/Notify/Query/Response");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} catch (SipException e) {
|
} catch (SipException e) {
|
||||||
logger.warn("SIP 回复错误", e);
|
logger.warn("SIP 回复错误", e);
|
||||||
|
|||||||
@ -1,18 +1,15 @@
|
|||||||
package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.notify.cmd;
|
package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.notify.cmd;
|
||||||
|
|
||||||
import com.alibaba.fastjson2.JSONObject;
|
import com.genersoft.iot.vmp.conf.exception.ControllerException;
|
||||||
import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException;
|
|
||||||
import com.genersoft.iot.vmp.gb28181.bean.*;
|
import com.genersoft.iot.vmp.gb28181.bean.*;
|
||||||
import com.genersoft.iot.vmp.gb28181.session.AudioBroadcastManager;
|
import com.genersoft.iot.vmp.gb28181.session.AudioBroadcastManager;
|
||||||
import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform;
|
import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform;
|
||||||
import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
|
import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
|
||||||
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler;
|
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler;
|
||||||
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.notify.NotifyMessageHandler;
|
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.notify.NotifyMessageHandler;
|
||||||
import com.genersoft.iot.vmp.media.zlm.ZLMServerFactory;
|
import com.genersoft.iot.vmp.media.bean.MediaServer;
|
||||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
import com.genersoft.iot.vmp.media.service.IMediaServerService;
|
||||||
import com.genersoft.iot.vmp.media.zlm.dto.hook.OnStreamChangedHookParam;
|
|
||||||
import com.genersoft.iot.vmp.service.IDeviceService;
|
import com.genersoft.iot.vmp.service.IDeviceService;
|
||||||
import com.genersoft.iot.vmp.service.IMediaServerService;
|
|
||||||
import com.genersoft.iot.vmp.service.IPlatformService;
|
import com.genersoft.iot.vmp.service.IPlatformService;
|
||||||
import com.genersoft.iot.vmp.service.IPlayService;
|
import com.genersoft.iot.vmp.service.IPlayService;
|
||||||
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
|
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
|
||||||
@ -64,9 +61,6 @@ public class BroadcastNotifyMessageHandler extends SIPRequestProcessorParent imp
|
|||||||
@Autowired
|
@Autowired
|
||||||
private AudioBroadcastManager audioBroadcastManager;
|
private AudioBroadcastManager audioBroadcastManager;
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private ZLMServerFactory zlmServerFactory;
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private IRedisCatchStorage redisCatchStorage;
|
private IRedisCatchStorage redisCatchStorage;
|
||||||
|
|
||||||
@ -121,15 +115,14 @@ public class BroadcastNotifyMessageHandler extends SIPRequestProcessorParent imp
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
MediaServerItem mediaServerForMinimumLoad = mediaServerService.getMediaServerForMinimumLoad(null);
|
MediaServer mediaServerForMinimumLoad = mediaServerService.getMediaServerForMinimumLoad(null);
|
||||||
commanderForPlatform.broadcastResultCmd(platform, deviceChannel, sn, true, eventResult->{
|
commanderForPlatform.broadcastResultCmd(platform, deviceChannel, sn, true, eventResult->{
|
||||||
logger.info("[国标级联] 语音喊话 回复失败 platform: {}, 错误:{}/{}", platform.getServerGBId(), eventResult.statusCode, eventResult.msg);
|
logger.info("[国标级联] 语音喊话 回复失败 platform: {}, 错误:{}/{}", platform.getServerGBId(), eventResult.statusCode, eventResult.msg);
|
||||||
}, eventResult->{
|
}, eventResult->{
|
||||||
|
|
||||||
// 消息发送成功, 向上级发送invite,获取推流
|
// 消息发送成功, 向上级发送invite,获取推流
|
||||||
try {
|
try {
|
||||||
platformService.broadcastInvite(platform, deviceChannel.getChannelId(), mediaServerForMinimumLoad, (mediaServerItem, hookParam)->{
|
platformService.broadcastInvite(platform, deviceChannel.getChannelId(), mediaServerForMinimumLoad, (hookData)->{
|
||||||
OnStreamChangedHookParam streamChangedHookParam = (OnStreamChangedHookParam)hookParam;
|
|
||||||
// 上级平台推流成功
|
// 上级平台推流成功
|
||||||
AudioBroadcastCatch broadcastCatch = audioBroadcastManager.get(device.getDeviceId(), targetId);
|
AudioBroadcastCatch broadcastCatch = audioBroadcastManager.get(device.getDeviceId(), targetId);
|
||||||
if (broadcastCatch != null ) {
|
if (broadcastCatch != null ) {
|
||||||
@ -137,20 +130,20 @@ public class BroadcastNotifyMessageHandler extends SIPRequestProcessorParent imp
|
|||||||
logger.info("[国标级联] 语音喊话 设备正在使用中 platform: {}, channel: {}",
|
logger.info("[国标级联] 语音喊话 设备正在使用中 platform: {}, channel: {}",
|
||||||
platform.getServerGBId(), deviceChannel.getChannelId());
|
platform.getServerGBId(), deviceChannel.getChannelId());
|
||||||
// 查看语音通道已经建立且已经占用 回复BYE
|
// 查看语音通道已经建立且已经占用 回复BYE
|
||||||
platformService.stopBroadcast(platform, deviceChannel, streamChangedHookParam.getStream(), true, mediaServerItem);
|
platformService.stopBroadcast(platform, deviceChannel, hookData.getStream(), true, hookData.getMediaServer());
|
||||||
}else {
|
}else {
|
||||||
// 查看语音通道已经建立但是未占用
|
// 查看语音通道已经建立但是未占用
|
||||||
broadcastCatch.setApp(streamChangedHookParam.getApp());
|
broadcastCatch.setApp(hookData.getApp());
|
||||||
broadcastCatch.setStream(streamChangedHookParam.getStream());
|
broadcastCatch.setStream(hookData.getStream());
|
||||||
broadcastCatch.setMediaServerItem(mediaServerItem);
|
broadcastCatch.setMediaServerItem(hookData.getMediaServer());
|
||||||
audioBroadcastManager.update(broadcastCatch);
|
audioBroadcastManager.update(broadcastCatch);
|
||||||
// 推流到设备
|
// 推流到设备
|
||||||
SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(null, targetId, streamChangedHookParam.getStream(), null);
|
SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(null, targetId, hookData.getStream(), null);
|
||||||
if (sendRtpItem == null) {
|
if (sendRtpItem == null) {
|
||||||
logger.warn("[国标级联] 语音喊话 异常,未找到发流信息, channelId: {}, stream: {}", targetId, streamChangedHookParam.getStream());
|
logger.warn("[国标级联] 语音喊话 异常,未找到发流信息, channelId: {}, stream: {}", targetId, hookData.getStream());
|
||||||
logger.info("[国标级联] 语音喊话 重新开始,channelId: {}, stream: {}", targetId, streamChangedHookParam.getStream());
|
logger.info("[国标级联] 语音喊话 重新开始,channelId: {}, stream: {}", targetId, hookData.getStream());
|
||||||
try {
|
try {
|
||||||
playService.audioBroadcastCmd(device, targetId, mediaServerItem, streamChangedHookParam.getApp(), streamChangedHookParam.getStream(), 60, true, msg -> {
|
playService.audioBroadcastCmd(device, targetId, hookData.getMediaServer(), hookData.getApp(), hookData.getStream(), 60, true, msg -> {
|
||||||
logger.info("[语音喊话] 通道建立成功, device: {}, channel: {}", device.getDeviceId(), targetId);
|
logger.info("[语音喊话] 通道建立成功, device: {}, channel: {}", device.getDeviceId(), targetId);
|
||||||
});
|
});
|
||||||
} catch (SipException | InvalidArgumentException | ParseException e) {
|
} catch (SipException | InvalidArgumentException | ParseException e) {
|
||||||
@ -158,17 +151,18 @@ public class BroadcastNotifyMessageHandler extends SIPRequestProcessorParent imp
|
|||||||
}
|
}
|
||||||
}else {
|
}else {
|
||||||
// 发流
|
// 发流
|
||||||
JSONObject jsonObject = zlmServerFactory.startSendRtp(mediaServerItem, sendRtpItem);
|
try {
|
||||||
if (jsonObject != null && jsonObject.getInteger("code") == 0 ) {
|
mediaServerService.startSendRtp(hookData.getMediaServer(),null, sendRtpItem);
|
||||||
logger.info("[语音喊话] 自动推流成功, device: {}, channel: {}", device.getDeviceId(), targetId);
|
}catch (ControllerException e) {
|
||||||
}else {
|
logger.info("[语音喊话] 推流失败, 结果: {}", e.getMessage());
|
||||||
logger.info("[语音喊话] 推流失败, 结果: {}", jsonObject);
|
return;
|
||||||
}
|
}
|
||||||
|
logger.info("[语音喊话] 自动推流成功, device: {}, channel: {}", device.getDeviceId(), targetId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}else {
|
}else {
|
||||||
try {
|
try {
|
||||||
playService.audioBroadcastCmd(device, targetId, mediaServerItem, streamChangedHookParam.getApp(), streamChangedHookParam.getStream(), 60, true, msg -> {
|
playService.audioBroadcastCmd(device, targetId, hookData.getMediaServer(), hookData.getApp(), hookData.getStream(), 60, true, msg -> {
|
||||||
logger.info("[语音喊话] 通道建立成功, device: {}, channel: {}", device.getDeviceId(), targetId);
|
logger.info("[语音喊话] 通道建立成功, device: {}, channel: {}", device.getDeviceId(), targetId);
|
||||||
});
|
});
|
||||||
} catch (SipException | InvalidArgumentException | ParseException e) {
|
} catch (SipException | InvalidArgumentException | ParseException e) {
|
||||||
|
|||||||
@ -13,9 +13,9 @@ import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform;
|
|||||||
import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
|
import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
|
||||||
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler;
|
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler;
|
||||||
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.notify.NotifyMessageHandler;
|
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.notify.NotifyMessageHandler;
|
||||||
import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe;
|
import com.genersoft.iot.vmp.media.event.hook.Hook;
|
||||||
import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeFactory;
|
import com.genersoft.iot.vmp.media.event.hook.HookSubscribe;
|
||||||
import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForStreamChange;
|
import com.genersoft.iot.vmp.media.event.hook.HookType;
|
||||||
import com.genersoft.iot.vmp.service.IInviteStreamService;
|
import com.genersoft.iot.vmp.service.IInviteStreamService;
|
||||||
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
|
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
|
||||||
import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
|
import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
|
||||||
@ -64,7 +64,7 @@ public class MediaStatusNotifyMessageHandler extends SIPRequestProcessorParent i
|
|||||||
private VideoStreamSessionManager sessionManager;
|
private VideoStreamSessionManager sessionManager;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private ZlmHttpHookSubscribe subscribe;
|
private HookSubscribe subscribe;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private IInviteStreamService inviteStreamService;
|
private IInviteStreamService inviteStreamService;
|
||||||
@ -106,9 +106,8 @@ public class MediaStatusNotifyMessageHandler extends SIPRequestProcessorParent i
|
|||||||
logger.error("[录像流]推送完毕,收到关流通知, 发送BYE失败 {}", e.getMessage());
|
logger.error("[录像流]推送完毕,收到关流通知, 发送BYE失败 {}", e.getMessage());
|
||||||
}
|
}
|
||||||
// 去除监听流注销自动停止下载的监听
|
// 去除监听流注销自动停止下载的监听
|
||||||
HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", ssrcTransaction.getStream(), false, "rtsp", ssrcTransaction.getMediaServerId());
|
Hook hook = Hook.getInstance(HookType.on_media_arrival, "rtp", ssrcTransaction.getStream(), ssrcTransaction.getMediaServerId());
|
||||||
subscribe.removeSubscribe(hookSubscribe);
|
subscribe.removeSubscribe(hook);
|
||||||
|
|
||||||
// 如果级联播放,需要给上级发送此通知 TODO 多个上级同时观看一个下级 可能存在停错的问题,需要将点播CallId进行上下级绑定
|
// 如果级联播放,需要给上级发送此通知 TODO 多个上级同时观看一个下级 可能存在停错的问题,需要将点播CallId进行上下级绑定
|
||||||
SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(null, ssrcTransaction.getChannelId(), null, null);
|
SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(null, ssrcTransaction.getChannelId(), null, null);
|
||||||
if (sendRtpItem != null) {
|
if (sendRtpItem != null) {
|
||||||
|
|||||||
64
src/main/java/com/genersoft/iot/vmp/media/MediaServerConfig.java
Executable file
64
src/main/java/com/genersoft/iot/vmp/media/MediaServerConfig.java
Executable file
@ -0,0 +1,64 @@
|
|||||||
|
package com.genersoft.iot.vmp.media;
|
||||||
|
|
||||||
|
import com.genersoft.iot.vmp.conf.MediaConfig;
|
||||||
|
import com.genersoft.iot.vmp.media.event.mediaServer.MediaServerChangeEvent;
|
||||||
|
import com.genersoft.iot.vmp.media.service.IMediaServerService;
|
||||||
|
import com.genersoft.iot.vmp.media.bean.MediaServer;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.CommandLineRunner;
|
||||||
|
import org.springframework.context.ApplicationEventPublisher;
|
||||||
|
import org.springframework.core.annotation.Order;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 启动是从配置文件加载节点信息,以及发送个节点状态管理去控制节点状态
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
@Order(value=12)
|
||||||
|
public class MediaServerConfig implements CommandLineRunner {
|
||||||
|
|
||||||
|
private final static Logger logger = LoggerFactory.getLogger(MediaServerConfig.class);
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ApplicationEventPublisher applicationEventPublisher;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IMediaServerService mediaServerService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private MediaConfig mediaConfig;
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run(String... strings) throws Exception {
|
||||||
|
// 清理所有在线节点的缓存信息
|
||||||
|
mediaServerService.clearMediaServerForOnline();
|
||||||
|
MediaServer defaultMediaServer = mediaServerService.getDefaultMediaServer();
|
||||||
|
MediaServer mediaSerItemInConfig = mediaConfig.getMediaSerItem();
|
||||||
|
if (defaultMediaServer != null && mediaSerItemInConfig.getId().equals(defaultMediaServer.getId())) {
|
||||||
|
mediaServerService.update(mediaSerItemInConfig);
|
||||||
|
}else {
|
||||||
|
if (defaultMediaServer != null) {
|
||||||
|
mediaServerService.delete(defaultMediaServer.getId());
|
||||||
|
}
|
||||||
|
MediaServer mediaServerItem = mediaServerService.getOneFromDatabase(mediaSerItemInConfig.getId());
|
||||||
|
if (mediaServerItem == null) {
|
||||||
|
mediaServerService.add(mediaSerItemInConfig);
|
||||||
|
}else {
|
||||||
|
mediaServerService.update(mediaSerItemInConfig);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 发送媒体节点变化事件
|
||||||
|
mediaServerService.syncCatchFromDatabase();
|
||||||
|
// 获取所有的zlm, 并开启主动连接
|
||||||
|
List<MediaServer> all = mediaServerService.getAllFromDatabase();
|
||||||
|
logger.info("[媒体节点] 加载节点列表, 共{}个节点", all.size());
|
||||||
|
MediaServerChangeEvent event = new MediaServerChangeEvent(this);
|
||||||
|
event.setMediaServerItemList(all);
|
||||||
|
applicationEventPublisher.publishEvent(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
306
src/main/java/com/genersoft/iot/vmp/media/bean/MediaInfo.java
Normal file
306
src/main/java/com/genersoft/iot/vmp/media/bean/MediaInfo.java
Normal file
@ -0,0 +1,306 @@
|
|||||||
|
package com.genersoft.iot.vmp.media.bean;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSONArray;
|
||||||
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
|
import com.genersoft.iot.vmp.media.zlm.dto.hook.OnStreamChangedHookParam;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 视频信息
|
||||||
|
*/
|
||||||
|
@Schema(description = "视频信息")
|
||||||
|
public class MediaInfo {
|
||||||
|
@Schema(description = "应用名")
|
||||||
|
private String app;
|
||||||
|
@Schema(description = "流ID")
|
||||||
|
private String stream;
|
||||||
|
@Schema(description = "流媒体节点")
|
||||||
|
private MediaServer mediaServer;
|
||||||
|
@Schema(description = "协议")
|
||||||
|
private String schema;
|
||||||
|
|
||||||
|
@Schema(description = "观看人数")
|
||||||
|
private Integer readerCount;
|
||||||
|
@Schema(description = "视频编码类型")
|
||||||
|
private String videoCodec;
|
||||||
|
@Schema(description = "视频宽度")
|
||||||
|
private Integer width;
|
||||||
|
@Schema(description = "视频高度")
|
||||||
|
private Integer height;
|
||||||
|
@Schema(description = "音频编码类型")
|
||||||
|
private String audioCodec;
|
||||||
|
@Schema(description = "音频通道数")
|
||||||
|
private Integer audioChannels;
|
||||||
|
@Schema(description = "音频采样率")
|
||||||
|
private Integer audioSampleRate;
|
||||||
|
@Schema(description = "音频采样率")
|
||||||
|
private Long duration;
|
||||||
|
@Schema(description = "在线")
|
||||||
|
private Boolean online;
|
||||||
|
@Schema(description = "unknown = 0,rtmp_push=1,rtsp_push=2,rtp_push=3,pull=4,ffmpeg_pull=5,mp4_vod=6,device_chn=7")
|
||||||
|
private Integer originType;
|
||||||
|
@Schema(description = "存活时间,单位秒")
|
||||||
|
private Long aliveSecond;
|
||||||
|
@Schema(description = "数据产生速度,单位byte/s")
|
||||||
|
private Long bytesSpeed;
|
||||||
|
|
||||||
|
public static MediaInfo getInstance(JSONObject jsonObject, MediaServer mediaServer) {
|
||||||
|
MediaInfo mediaInfo = new MediaInfo();
|
||||||
|
mediaInfo.setMediaServer(mediaServer);
|
||||||
|
String app = jsonObject.getString("app");
|
||||||
|
mediaInfo.setApp(app);
|
||||||
|
String stream = jsonObject.getString("stream");
|
||||||
|
mediaInfo.setStream(stream);
|
||||||
|
String schema = jsonObject.getString("schema");
|
||||||
|
mediaInfo.setSchema(schema);
|
||||||
|
Integer totalReaderCount = jsonObject.getInteger("totalReaderCount");
|
||||||
|
Boolean online = jsonObject.getBoolean("online");
|
||||||
|
Integer originType = jsonObject.getInteger("originType");
|
||||||
|
Long aliveSecond = jsonObject.getLong("aliveSecond");
|
||||||
|
Long bytesSpeed = jsonObject.getLong("bytesSpeed");
|
||||||
|
if (totalReaderCount != null) {
|
||||||
|
mediaInfo.setReaderCount(totalReaderCount);
|
||||||
|
}
|
||||||
|
if (online != null) {
|
||||||
|
mediaInfo.setOnline(online);
|
||||||
|
}
|
||||||
|
if (originType != null) {
|
||||||
|
mediaInfo.setOriginType(originType);
|
||||||
|
}
|
||||||
|
if (aliveSecond != null) {
|
||||||
|
mediaInfo.setAliveSecond(aliveSecond);
|
||||||
|
}
|
||||||
|
if (bytesSpeed != null) {
|
||||||
|
mediaInfo.setBytesSpeed(bytesSpeed);
|
||||||
|
}
|
||||||
|
JSONArray jsonArray = jsonObject.getJSONArray("tracks");
|
||||||
|
if (jsonArray.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < jsonArray.size(); i++) {
|
||||||
|
JSONObject trackJson = jsonArray.getJSONObject(i);
|
||||||
|
Integer channels = trackJson.getInteger("channels");
|
||||||
|
Integer codecId = trackJson.getInteger("codec_id");
|
||||||
|
Integer codecType = trackJson.getInteger("codec_type");
|
||||||
|
Integer sampleRate = trackJson.getInteger("sample_rate");
|
||||||
|
Integer height = trackJson.getInteger("height");
|
||||||
|
Integer width = trackJson.getInteger("height");
|
||||||
|
Long duration = trackJson.getLongValue("duration");
|
||||||
|
if (channels != null) {
|
||||||
|
mediaInfo.setAudioChannels(channels);
|
||||||
|
}
|
||||||
|
if (sampleRate != null) {
|
||||||
|
mediaInfo.setAudioSampleRate(sampleRate);
|
||||||
|
}
|
||||||
|
if (height != null) {
|
||||||
|
mediaInfo.setHeight(height);
|
||||||
|
}
|
||||||
|
if (width != null) {
|
||||||
|
mediaInfo.setWidth(width);
|
||||||
|
}
|
||||||
|
if (duration > 0L) {
|
||||||
|
mediaInfo.setDuration(duration);
|
||||||
|
}
|
||||||
|
if (codecId != null) {
|
||||||
|
switch (codecId) {
|
||||||
|
case 0:
|
||||||
|
mediaInfo.setVideoCodec("H264");
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
mediaInfo.setVideoCodec("H265");
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
mediaInfo.setAudioCodec("AAC");
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
mediaInfo.setAudioCodec("G711A");
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
mediaInfo.setAudioCodec("G711U");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return mediaInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MediaInfo getInstance(OnStreamChangedHookParam param, MediaServer mediaServer) {
|
||||||
|
|
||||||
|
MediaInfo mediaInfo = new MediaInfo();
|
||||||
|
mediaInfo.setApp(param.getApp());
|
||||||
|
mediaInfo.setStream(param.getStream());
|
||||||
|
mediaInfo.setSchema(param.getSchema());
|
||||||
|
mediaInfo.setMediaServer(mediaServer);
|
||||||
|
mediaInfo.setReaderCount(param.getTotalReaderCount());
|
||||||
|
mediaInfo.setOnline(param.isRegist());
|
||||||
|
mediaInfo.setOriginType(param.getOriginType());
|
||||||
|
mediaInfo.setAliveSecond(param.getAliveSecond());
|
||||||
|
mediaInfo.setBytesSpeed(param.getBytesSpeed());
|
||||||
|
List<OnStreamChangedHookParam.MediaTrack> tracks = param.getTracks();
|
||||||
|
if (tracks == null || tracks.isEmpty()) {
|
||||||
|
return mediaInfo;
|
||||||
|
}
|
||||||
|
for (OnStreamChangedHookParam.MediaTrack mediaTrack : tracks) {
|
||||||
|
switch (mediaTrack.getCodec_id()) {
|
||||||
|
case 0:
|
||||||
|
mediaInfo.setVideoCodec("H264");
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
mediaInfo.setVideoCodec("H265");
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
mediaInfo.setAudioCodec("AAC");
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
mediaInfo.setAudioCodec("G711A");
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
mediaInfo.setAudioCodec("G711U");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (mediaTrack.getSample_rate() > 0) {
|
||||||
|
mediaInfo.setAudioSampleRate(mediaTrack.getSample_rate());
|
||||||
|
}
|
||||||
|
if (mediaTrack.getChannels() > 0) {
|
||||||
|
mediaInfo.setAudioChannels(mediaTrack.getChannels());
|
||||||
|
}
|
||||||
|
if (mediaTrack.getHeight() > 0) {
|
||||||
|
mediaInfo.setHeight(mediaTrack.getHeight());
|
||||||
|
}
|
||||||
|
if (mediaTrack.getWidth() > 0) {
|
||||||
|
mediaInfo.setWidth(mediaTrack.getWidth());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return mediaInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getReaderCount() {
|
||||||
|
return readerCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setReaderCount(Integer readerCount) {
|
||||||
|
this.readerCount = readerCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getVideoCodec() {
|
||||||
|
return videoCodec;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setVideoCodec(String videoCodec) {
|
||||||
|
this.videoCodec = videoCodec;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getWidth() {
|
||||||
|
return width;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setWidth(Integer width) {
|
||||||
|
this.width = width;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getHeight() {
|
||||||
|
return height;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHeight(Integer height) {
|
||||||
|
this.height = height;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAudioCodec() {
|
||||||
|
return audioCodec;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAudioCodec(String audioCodec) {
|
||||||
|
this.audioCodec = audioCodec;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getAudioChannels() {
|
||||||
|
return audioChannels;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAudioChannels(Integer audioChannels) {
|
||||||
|
this.audioChannels = audioChannels;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getAudioSampleRate() {
|
||||||
|
return audioSampleRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAudioSampleRate(Integer audioSampleRate) {
|
||||||
|
this.audioSampleRate = audioSampleRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getDuration() {
|
||||||
|
return duration;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDuration(Long duration) {
|
||||||
|
this.duration = duration;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean getOnline() {
|
||||||
|
return online;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOnline(Boolean online) {
|
||||||
|
this.online = online;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getOriginType() {
|
||||||
|
return originType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOriginType(Integer originType) {
|
||||||
|
this.originType = originType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getAliveSecond() {
|
||||||
|
return aliveSecond;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAliveSecond(Long aliveSecond) {
|
||||||
|
this.aliveSecond = aliveSecond;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getBytesSpeed() {
|
||||||
|
return bytesSpeed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBytesSpeed(Long bytesSpeed) {
|
||||||
|
this.bytesSpeed = bytesSpeed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getApp() {
|
||||||
|
return app;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setApp(String app) {
|
||||||
|
this.app = app;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getStream() {
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStream(String stream) {
|
||||||
|
this.stream = stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MediaServer getMediaServer() {
|
||||||
|
return mediaServer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMediaServer(MediaServer mediaServer) {
|
||||||
|
this.mediaServer = mediaServer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSchema() {
|
||||||
|
return schema;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSchema(String schema) {
|
||||||
|
this.schema = schema;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,12 +1,12 @@
|
|||||||
package com.genersoft.iot.vmp.media.zlm.dto;
|
package com.genersoft.iot.vmp.media.bean;
|
||||||
|
|
||||||
|
|
||||||
import com.genersoft.iot.vmp.media.zlm.ZLMServerConfig;
|
import com.genersoft.iot.vmp.media.zlm.dto.ZLMServerConfig;
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
import org.springframework.util.ObjectUtils;
|
import org.springframework.util.ObjectUtils;
|
||||||
|
|
||||||
@Schema(description = "流媒体服务信息")
|
@Schema(description = "流媒体服务信息")
|
||||||
public class MediaServerItem{
|
public class MediaServer {
|
||||||
|
|
||||||
@Schema(description = "ID")
|
@Schema(description = "ID")
|
||||||
private String id;
|
private String id;
|
||||||
@ -32,6 +32,18 @@ public class MediaServerItem{
|
|||||||
@Schema(description = "RTMP端口")
|
@Schema(description = "RTMP端口")
|
||||||
private int rtmpPort;
|
private int rtmpPort;
|
||||||
|
|
||||||
|
@Schema(description = "flv端口")
|
||||||
|
private int flvPort;
|
||||||
|
|
||||||
|
@Schema(description = "https-flv端口")
|
||||||
|
private int flvSSLPort;
|
||||||
|
|
||||||
|
@Schema(description = "ws-flv端口")
|
||||||
|
private int wsFlvPort;
|
||||||
|
|
||||||
|
@Schema(description = "wss-flv端口")
|
||||||
|
private int wsFlvSSLPort;
|
||||||
|
|
||||||
@Schema(description = "RTMPS端口")
|
@Schema(description = "RTMPS端口")
|
||||||
private int rtmpSSlPort;
|
private int rtmpSSlPort;
|
||||||
|
|
||||||
@ -85,18 +97,24 @@ public class MediaServerItem{
|
|||||||
|
|
||||||
@Schema(description = "录像存储路径")
|
@Schema(description = "录像存储路径")
|
||||||
private String recordPath;
|
private String recordPath;
|
||||||
|
@Schema(description = "类型: zlm/abl")
|
||||||
|
private String type;
|
||||||
|
|
||||||
public MediaServerItem() {
|
public MediaServer() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public MediaServerItem(ZLMServerConfig zlmServerConfig, String sipIp) {
|
public MediaServer(ZLMServerConfig zlmServerConfig, String sipIp) {
|
||||||
id = zlmServerConfig.getGeneralMediaServerId();
|
id = zlmServerConfig.getGeneralMediaServerId();
|
||||||
ip = zlmServerConfig.getIp();
|
ip = zlmServerConfig.getIp();
|
||||||
hookIp = ObjectUtils.isEmpty(zlmServerConfig.getHookIp())? sipIp: zlmServerConfig.getHookIp();
|
hookIp = ObjectUtils.isEmpty(zlmServerConfig.getHookIp())? sipIp: zlmServerConfig.getHookIp();
|
||||||
sdpIp = ObjectUtils.isEmpty(zlmServerConfig.getSdpIp())? zlmServerConfig.getIp(): zlmServerConfig.getSdpIp();
|
sdpIp = ObjectUtils.isEmpty(zlmServerConfig.getSdpIp())? zlmServerConfig.getIp(): zlmServerConfig.getSdpIp();
|
||||||
streamIp = ObjectUtils.isEmpty(zlmServerConfig.getStreamIp())? zlmServerConfig.getIp(): zlmServerConfig.getStreamIp();
|
streamIp = ObjectUtils.isEmpty(zlmServerConfig.getStreamIp())? zlmServerConfig.getIp(): zlmServerConfig.getStreamIp();
|
||||||
httpPort = zlmServerConfig.getHttpPort();
|
httpPort = zlmServerConfig.getHttpPort();
|
||||||
|
flvPort = zlmServerConfig.getHttpPort();
|
||||||
|
wsFlvPort = zlmServerConfig.getHttpPort();
|
||||||
httpSSlPort = zlmServerConfig.getHttpSSLport();
|
httpSSlPort = zlmServerConfig.getHttpSSLport();
|
||||||
|
flvSSLPort = zlmServerConfig.getHttpSSLport();
|
||||||
|
wsFlvSSLPort = zlmServerConfig.getHttpSSLport();
|
||||||
rtmpPort = zlmServerConfig.getRtmpPort();
|
rtmpPort = zlmServerConfig.getRtmpPort();
|
||||||
rtmpSSlPort = zlmServerConfig.getRtmpSslPort();
|
rtmpSSlPort = zlmServerConfig.getRtmpSslPort();
|
||||||
rtpProxyPort = zlmServerConfig.getRtpProxyPort();
|
rtpProxyPort = zlmServerConfig.getRtpProxyPort();
|
||||||
@ -318,4 +336,44 @@ public class MediaServerItem{
|
|||||||
public void setRecordPath(String recordPath) {
|
public void setRecordPath(String recordPath) {
|
||||||
this.recordPath = recordPath;
|
this.recordPath = recordPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setType(String type) {
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getFlvPort() {
|
||||||
|
return flvPort;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFlvPort(int flvPort) {
|
||||||
|
this.flvPort = flvPort;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getFlvSSLPort() {
|
||||||
|
return flvSSLPort;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFlvSSLPort(int flvSSLPort) {
|
||||||
|
this.flvSSLPort = flvSSLPort;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getWsFlvPort() {
|
||||||
|
return wsFlvPort;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setWsFlvPort(int wsFlvPort) {
|
||||||
|
this.wsFlvPort = wsFlvPort;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getWsFlvSSLPort() {
|
||||||
|
return wsFlvSSLPort;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setWsFlvSSLPort(int wsFlvSSLPort) {
|
||||||
|
this.wsFlvSSLPort = wsFlvSSLPort;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -0,0 +1,92 @@
|
|||||||
|
package com.genersoft.iot.vmp.media.bean;
|
||||||
|
|
||||||
|
import com.genersoft.iot.vmp.media.zlm.dto.hook.OnRecordMp4HookParam;
|
||||||
|
|
||||||
|
public class RecordInfo {
|
||||||
|
private String fileName;
|
||||||
|
private String filePath;
|
||||||
|
private long fileSize;
|
||||||
|
private String folder;
|
||||||
|
private String url;
|
||||||
|
private long startTime;
|
||||||
|
private double timeLen;
|
||||||
|
|
||||||
|
public static RecordInfo getInstance(OnRecordMp4HookParam hookParam) {
|
||||||
|
RecordInfo recordInfo = new RecordInfo();
|
||||||
|
recordInfo.setFileName(hookParam.getFile_name());
|
||||||
|
recordInfo.setUrl(hookParam.getUrl());
|
||||||
|
recordInfo.setFolder(hookParam.getFolder());
|
||||||
|
recordInfo.setFilePath(hookParam.getFile_path());
|
||||||
|
recordInfo.setFileSize(hookParam.getFile_size());
|
||||||
|
recordInfo.setStartTime(hookParam.getStart_time());
|
||||||
|
recordInfo.setTimeLen(hookParam.getTime_len());
|
||||||
|
return recordInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFileName() {
|
||||||
|
return fileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFileName(String fileName) {
|
||||||
|
this.fileName = fileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFilePath() {
|
||||||
|
return filePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFilePath(String filePath) {
|
||||||
|
this.filePath = filePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getFileSize() {
|
||||||
|
return fileSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFileSize(long fileSize) {
|
||||||
|
this.fileSize = fileSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFolder() {
|
||||||
|
return folder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFolder(String folder) {
|
||||||
|
this.folder = folder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUrl() {
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUrl(String url) {
|
||||||
|
this.url = url;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getStartTime() {
|
||||||
|
return startTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStartTime(long startTime) {
|
||||||
|
this.startTime = startTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getTimeLen() {
|
||||||
|
return timeLen;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTimeLen(double timeLen) {
|
||||||
|
this.timeLen = timeLen;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "RecordInfo{" +
|
||||||
|
"文件名称='" + fileName + '\'' +
|
||||||
|
", 文件路径='" + filePath + '\'' +
|
||||||
|
", 文件大小=" + fileSize +
|
||||||
|
", 开始时间=" + startTime +
|
||||||
|
", 时长=" + timeLen +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,59 @@
|
|||||||
|
package com.genersoft.iot.vmp.media.bean;
|
||||||
|
|
||||||
|
public class ResultForOnPublish {
|
||||||
|
|
||||||
|
private boolean enable_audio;
|
||||||
|
private boolean enable_mp4;
|
||||||
|
private int mp4_max_second;
|
||||||
|
private String mp4_save_path;
|
||||||
|
private String stream_replace;
|
||||||
|
private Integer modify_stamp;
|
||||||
|
|
||||||
|
public boolean isEnable_audio() {
|
||||||
|
return enable_audio;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEnable_audio(boolean enable_audio) {
|
||||||
|
this.enable_audio = enable_audio;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isEnable_mp4() {
|
||||||
|
return enable_mp4;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEnable_mp4(boolean enable_mp4) {
|
||||||
|
this.enable_mp4 = enable_mp4;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getMp4_max_second() {
|
||||||
|
return mp4_max_second;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMp4_max_second(int mp4_max_second) {
|
||||||
|
this.mp4_max_second = mp4_max_second;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMp4_save_path() {
|
||||||
|
return mp4_save_path;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMp4_save_path(String mp4_save_path) {
|
||||||
|
this.mp4_save_path = mp4_save_path;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getStream_replace() {
|
||||||
|
return stream_replace;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStream_replace(String stream_replace) {
|
||||||
|
this.stream_replace = stream_replace;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getModify_stamp() {
|
||||||
|
return modify_stamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setModify_stamp(Integer modify_stamp) {
|
||||||
|
this.modify_stamp = modify_stamp;
|
||||||
|
}
|
||||||
|
}
|
||||||
86
src/main/java/com/genersoft/iot/vmp/media/event/hook/Hook.java
Executable file
86
src/main/java/com/genersoft/iot/vmp/media/event/hook/Hook.java
Executable file
@ -0,0 +1,86 @@
|
|||||||
|
package com.genersoft.iot.vmp.media.event.hook;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* zlm hook事件的参数
|
||||||
|
* @author lin
|
||||||
|
*/
|
||||||
|
public class Hook {
|
||||||
|
|
||||||
|
private HookType hookType;
|
||||||
|
|
||||||
|
private String app;
|
||||||
|
|
||||||
|
private String stream;
|
||||||
|
|
||||||
|
private String mediaServerId;
|
||||||
|
|
||||||
|
private Long createTime;
|
||||||
|
|
||||||
|
public static Hook getInstance(HookType hookType, String app, String stream, String mediaServerId) {
|
||||||
|
Hook hookSubscribe = new Hook();
|
||||||
|
hookSubscribe.setApp(app);
|
||||||
|
hookSubscribe.setStream(stream);
|
||||||
|
hookSubscribe.setHookType(hookType);
|
||||||
|
hookSubscribe.setMediaServerId(mediaServerId);
|
||||||
|
hookSubscribe.setCreateTime(System.currentTimeMillis());
|
||||||
|
return hookSubscribe;
|
||||||
|
}
|
||||||
|
|
||||||
|
public HookType getHookType() {
|
||||||
|
return hookType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHookType(HookType hookType) {
|
||||||
|
this.hookType = hookType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getApp() {
|
||||||
|
return app;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setApp(String app) {
|
||||||
|
this.app = app;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getStream() {
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStream(String stream) {
|
||||||
|
this.stream = stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getCreateTime() {
|
||||||
|
return createTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCreateTime(Long createTime) {
|
||||||
|
this.createTime = createTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMediaServerId() {
|
||||||
|
return mediaServerId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMediaServerId(String mediaServerId) {
|
||||||
|
this.mediaServerId = mediaServerId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (obj instanceof Hook) {
|
||||||
|
Hook param = (Hook) obj;
|
||||||
|
return param.getHookType().equals(this.hookType)
|
||||||
|
&& param.getApp().equals(this.app)
|
||||||
|
&& param.getStream().equals(this.stream)
|
||||||
|
&& param.getMediaServerId().equals(this.mediaServerId);
|
||||||
|
}else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return this.getHookType() + this.getApp() + this.getStream() + this.getMediaServerId();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,132 @@
|
|||||||
|
package com.genersoft.iot.vmp.media.event.hook;
|
||||||
|
|
||||||
|
import com.genersoft.iot.vmp.media.bean.MediaInfo;
|
||||||
|
import com.genersoft.iot.vmp.media.bean.RecordInfo;
|
||||||
|
import com.genersoft.iot.vmp.media.event.media.MediaArrivalEvent;
|
||||||
|
import com.genersoft.iot.vmp.media.event.media.MediaEvent;
|
||||||
|
import com.genersoft.iot.vmp.media.event.media.MediaPublishEvent;
|
||||||
|
import com.genersoft.iot.vmp.media.event.media.MediaRecordMp4Event;
|
||||||
|
import com.genersoft.iot.vmp.media.bean.MediaServer;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hook返回的内容
|
||||||
|
*/
|
||||||
|
public class HookData {
|
||||||
|
/**
|
||||||
|
* 应用名
|
||||||
|
*/
|
||||||
|
private String app;
|
||||||
|
/**
|
||||||
|
* 流ID
|
||||||
|
*/
|
||||||
|
private String stream;
|
||||||
|
/**
|
||||||
|
* 流媒体节点
|
||||||
|
*/
|
||||||
|
private MediaServer mediaServer;
|
||||||
|
/**
|
||||||
|
* 协议
|
||||||
|
*/
|
||||||
|
private String schema;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 流信息
|
||||||
|
*/
|
||||||
|
private MediaInfo mediaInfo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 录像信息
|
||||||
|
*/
|
||||||
|
private RecordInfo recordInfo;
|
||||||
|
|
||||||
|
@Schema(description = "推流的额外参数")
|
||||||
|
private String params;
|
||||||
|
public static HookData getInstance(MediaEvent mediaEvent) {
|
||||||
|
HookData hookData = new HookData();
|
||||||
|
if (mediaEvent instanceof MediaPublishEvent) {
|
||||||
|
MediaPublishEvent event = (MediaPublishEvent) mediaEvent;
|
||||||
|
hookData.setApp(event.getApp());
|
||||||
|
hookData.setStream(event.getStream());
|
||||||
|
hookData.setSchema(event.getSchema());
|
||||||
|
hookData.setMediaServer(event.getMediaServer());
|
||||||
|
hookData.setParams(event.getParams());
|
||||||
|
}else if (mediaEvent instanceof MediaArrivalEvent) {
|
||||||
|
MediaArrivalEvent event = (MediaArrivalEvent) mediaEvent;
|
||||||
|
hookData.setApp(event.getApp());
|
||||||
|
hookData.setStream(event.getStream());
|
||||||
|
hookData.setSchema(event.getSchema());
|
||||||
|
hookData.setMediaServer(event.getMediaServer());
|
||||||
|
hookData.setMediaInfo(event.getMediaInfo());
|
||||||
|
}else if (mediaEvent instanceof MediaRecordMp4Event) {
|
||||||
|
MediaRecordMp4Event event = (MediaRecordMp4Event) mediaEvent;
|
||||||
|
hookData.setApp(event.getApp());
|
||||||
|
hookData.setStream(event.getStream());
|
||||||
|
hookData.setSchema(event.getSchema());
|
||||||
|
hookData.setMediaServer(event.getMediaServer());
|
||||||
|
hookData.setRecordInfo(event.getRecordInfo());
|
||||||
|
}else {
|
||||||
|
hookData.setApp(mediaEvent.getApp());
|
||||||
|
hookData.setStream(mediaEvent.getStream());
|
||||||
|
hookData.setSchema(mediaEvent.getSchema());
|
||||||
|
hookData.setMediaServer(mediaEvent.getMediaServer());
|
||||||
|
}
|
||||||
|
return hookData;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getApp() {
|
||||||
|
return app;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setApp(String app) {
|
||||||
|
this.app = app;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getStream() {
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStream(String stream) {
|
||||||
|
this.stream = stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MediaServer getMediaServer() {
|
||||||
|
return mediaServer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMediaServer(MediaServer mediaServer) {
|
||||||
|
this.mediaServer = mediaServer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSchema() {
|
||||||
|
return schema;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSchema(String schema) {
|
||||||
|
this.schema = schema;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MediaInfo getMediaInfo() {
|
||||||
|
return mediaInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMediaInfo(MediaInfo mediaInfo) {
|
||||||
|
this.mediaInfo = mediaInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getParams() {
|
||||||
|
return params;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setParams(String params) {
|
||||||
|
this.params = params;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RecordInfo getRecordInfo() {
|
||||||
|
return recordInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRecordInfo(RecordInfo recordInfo) {
|
||||||
|
this.recordInfo = recordInfo;
|
||||||
|
}
|
||||||
|
}
|
||||||
107
src/main/java/com/genersoft/iot/vmp/media/event/hook/HookSubscribe.java
Executable file
107
src/main/java/com/genersoft/iot/vmp/media/event/hook/HookSubscribe.java
Executable file
@ -0,0 +1,107 @@
|
|||||||
|
package com.genersoft.iot.vmp.media.event.hook;
|
||||||
|
|
||||||
|
import com.genersoft.iot.vmp.media.event.media.*;
|
||||||
|
import org.springframework.context.event.EventListener;
|
||||||
|
import org.springframework.scheduling.annotation.Async;
|
||||||
|
import org.springframework.scheduling.annotation.Scheduled;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* zlm hook事件的参数
|
||||||
|
* @author lin
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class HookSubscribe {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 订阅数据过期时间
|
||||||
|
*/
|
||||||
|
private final long subscribeExpire = 5 * 60 * 1000;
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface Event{
|
||||||
|
void response(HookData data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 流到来的处理
|
||||||
|
*/
|
||||||
|
@Async("taskExecutor")
|
||||||
|
@EventListener
|
||||||
|
public void onApplicationEvent(MediaArrivalEvent event) {
|
||||||
|
if (event.getSchema() == null || "rtsp".equals(event.getSchema())) {
|
||||||
|
sendNotify(HookType.on_media_arrival, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 流结束事件
|
||||||
|
*/
|
||||||
|
@Async("taskExecutor")
|
||||||
|
@EventListener
|
||||||
|
public void onApplicationEvent(MediaDepartureEvent event) {
|
||||||
|
if (event.getSchema() == null || "rtsp".equals(event.getSchema())) {
|
||||||
|
sendNotify(HookType.on_media_departure, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 推流鉴权事件
|
||||||
|
*/
|
||||||
|
@Async("taskExecutor")
|
||||||
|
@EventListener
|
||||||
|
public void onApplicationEvent(MediaPublishEvent event) {
|
||||||
|
sendNotify(HookType.on_publish, event);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 推流鉴权事件
|
||||||
|
*/
|
||||||
|
@Async("taskExecutor")
|
||||||
|
@EventListener
|
||||||
|
public void onApplicationEvent(MediaRecordMp4Event event) {
|
||||||
|
sendNotify(HookType.on_record_mp4, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
private final Map<String, Event> allSubscribes = new ConcurrentHashMap<>();
|
||||||
|
private final Map<String, Hook> allHook = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
private void sendNotify(HookType hookType, MediaEvent event) {
|
||||||
|
Hook paramHook = Hook.getInstance(hookType, event.getApp(), event.getStream(), event.getMediaServer().getId());
|
||||||
|
Event hookSubscribeEvent = allSubscribes.get(paramHook.toString());
|
||||||
|
if (hookSubscribeEvent != null) {
|
||||||
|
HookData data = HookData.getInstance(event);
|
||||||
|
hookSubscribeEvent.response(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addSubscribe(Hook hook, HookSubscribe.Event event) {
|
||||||
|
if (hook.getCreateTime() == null) {
|
||||||
|
hook.setCreateTime(System.currentTimeMillis());
|
||||||
|
}
|
||||||
|
allSubscribes.put(hook.toString(), event);
|
||||||
|
allHook.put(hook.toString(), hook);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeSubscribe(Hook hook) {
|
||||||
|
allSubscribes.remove(hook.toString());
|
||||||
|
allHook.remove(hook.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对订阅数据进行过期清理
|
||||||
|
*/
|
||||||
|
@Scheduled(fixedRate=subscribeExpire) //每5分钟执行一次
|
||||||
|
public void execute(){
|
||||||
|
long expireTime = System.currentTimeMillis() - subscribeExpire;
|
||||||
|
for (Hook hook : allHook.values()) {
|
||||||
|
if (hook.getCreateTime() < expireTime) {
|
||||||
|
allSubscribes.remove(hook.toString());
|
||||||
|
allHook.remove(hook.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
15
src/main/java/com/genersoft/iot/vmp/media/event/hook/HookType.java
Executable file
15
src/main/java/com/genersoft/iot/vmp/media/event/hook/HookType.java
Executable file
@ -0,0 +1,15 @@
|
|||||||
|
package com.genersoft.iot.vmp.media.event.hook;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hook类型
|
||||||
|
* @author lin
|
||||||
|
*/
|
||||||
|
|
||||||
|
public enum HookType {
|
||||||
|
|
||||||
|
on_publish,
|
||||||
|
on_record_mp4,
|
||||||
|
on_media_arrival,
|
||||||
|
on_media_departure,
|
||||||
|
on_rtp_server_timeout,
|
||||||
|
}
|
||||||
@ -0,0 +1,46 @@
|
|||||||
|
package com.genersoft.iot.vmp.media.event.media;
|
||||||
|
|
||||||
|
import com.genersoft.iot.vmp.media.bean.MediaInfo;
|
||||||
|
import com.genersoft.iot.vmp.media.bean.MediaServer;
|
||||||
|
import com.genersoft.iot.vmp.media.zlm.dto.hook.OnStreamChangedHookParam;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 流到来事件
|
||||||
|
*/
|
||||||
|
public class MediaArrivalEvent extends MediaEvent {
|
||||||
|
public MediaArrivalEvent(Object source) {
|
||||||
|
super(source);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MediaArrivalEvent getInstance(Object source, OnStreamChangedHookParam hookParam, MediaServer mediaServer){
|
||||||
|
MediaArrivalEvent mediaArrivalEvent = new MediaArrivalEvent(source);
|
||||||
|
mediaArrivalEvent.setMediaInfo(MediaInfo.getInstance(hookParam, mediaServer));
|
||||||
|
mediaArrivalEvent.setApp(hookParam.getApp());
|
||||||
|
mediaArrivalEvent.setStream(hookParam.getStream());
|
||||||
|
mediaArrivalEvent.setMediaServer(mediaServer);
|
||||||
|
mediaArrivalEvent.setSchema(hookParam.getSchema());
|
||||||
|
mediaArrivalEvent.setCallId(hookParam.getCallId());
|
||||||
|
return mediaArrivalEvent;
|
||||||
|
}
|
||||||
|
|
||||||
|
private MediaInfo mediaInfo;
|
||||||
|
|
||||||
|
private String callId;
|
||||||
|
|
||||||
|
public MediaInfo getMediaInfo() {
|
||||||
|
return mediaInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMediaInfo(MediaInfo mediaInfo) {
|
||||||
|
this.mediaInfo = mediaInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public String getCallId() {
|
||||||
|
return callId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCallId(String callId) {
|
||||||
|
this.callId = callId;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,22 @@
|
|||||||
|
package com.genersoft.iot.vmp.media.event.media;
|
||||||
|
|
||||||
|
import com.genersoft.iot.vmp.media.bean.MediaServer;
|
||||||
|
import com.genersoft.iot.vmp.media.zlm.dto.hook.OnStreamChangedHookParam;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 流离开事件
|
||||||
|
*/
|
||||||
|
public class MediaDepartureEvent extends MediaEvent {
|
||||||
|
public MediaDepartureEvent(Object source) {
|
||||||
|
super(source);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MediaDepartureEvent getInstance(Object source, OnStreamChangedHookParam hookParam, MediaServer mediaServer){
|
||||||
|
MediaDepartureEvent mediaDepartureEven = new MediaDepartureEvent(source);
|
||||||
|
mediaDepartureEven.setApp(hookParam.getApp());
|
||||||
|
mediaDepartureEven.setStream(hookParam.getStream());
|
||||||
|
mediaDepartureEven.setSchema(hookParam.getSchema());
|
||||||
|
mediaDepartureEven.setMediaServer(mediaServer);
|
||||||
|
return mediaDepartureEven;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,56 @@
|
|||||||
|
package com.genersoft.iot.vmp.media.event.media;
|
||||||
|
|
||||||
|
import com.genersoft.iot.vmp.media.bean.MediaServer;
|
||||||
|
import org.springframework.context.ApplicationEvent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 流到来事件
|
||||||
|
*/
|
||||||
|
public class MediaEvent extends ApplicationEvent {
|
||||||
|
|
||||||
|
public MediaEvent(Object source) {
|
||||||
|
super(source);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String app;
|
||||||
|
|
||||||
|
private String stream;
|
||||||
|
|
||||||
|
private MediaServer mediaServer;
|
||||||
|
|
||||||
|
private String schema;
|
||||||
|
|
||||||
|
|
||||||
|
public String getApp() {
|
||||||
|
return app;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setApp(String app) {
|
||||||
|
this.app = app;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getStream() {
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStream(String stream) {
|
||||||
|
this.stream = stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MediaServer getMediaServer() {
|
||||||
|
return mediaServer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMediaServer(MediaServer mediaServer) {
|
||||||
|
this.mediaServer = mediaServer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSchema() {
|
||||||
|
return schema;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSchema(String schema) {
|
||||||
|
this.schema = schema;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,22 @@
|
|||||||
|
package com.genersoft.iot.vmp.media.event.media;
|
||||||
|
|
||||||
|
import com.genersoft.iot.vmp.media.bean.MediaServer;
|
||||||
|
import com.genersoft.iot.vmp.media.zlm.dto.hook.OnStreamNotFoundHookParam;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 流未找到
|
||||||
|
*/
|
||||||
|
public class MediaNotFoundEvent extends MediaEvent {
|
||||||
|
public MediaNotFoundEvent(Object source) {
|
||||||
|
super(source);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MediaNotFoundEvent getInstance(Object source, OnStreamNotFoundHookParam hookParam, MediaServer mediaServer){
|
||||||
|
MediaNotFoundEvent mediaDepartureEven = new MediaNotFoundEvent(source);
|
||||||
|
mediaDepartureEven.setApp(hookParam.getApp());
|
||||||
|
mediaDepartureEven.setStream(hookParam.getStream());
|
||||||
|
mediaDepartureEven.setSchema(hookParam.getSchema());
|
||||||
|
mediaDepartureEven.setMediaServer(mediaServer);
|
||||||
|
return mediaDepartureEven;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,33 @@
|
|||||||
|
package com.genersoft.iot.vmp.media.event.media;
|
||||||
|
|
||||||
|
import com.genersoft.iot.vmp.media.bean.MediaServer;
|
||||||
|
import com.genersoft.iot.vmp.media.zlm.dto.hook.OnPublishHookParam;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 推流鉴权事件
|
||||||
|
*/
|
||||||
|
public class MediaPublishEvent extends MediaEvent {
|
||||||
|
public MediaPublishEvent(Object source) {
|
||||||
|
super(source);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MediaPublishEvent getInstance(Object source, OnPublishHookParam hookParam, MediaServer mediaServer){
|
||||||
|
MediaPublishEvent mediaPublishEvent = new MediaPublishEvent(source);
|
||||||
|
mediaPublishEvent.setApp(hookParam.getApp());
|
||||||
|
mediaPublishEvent.setStream(hookParam.getStream());
|
||||||
|
mediaPublishEvent.setMediaServer(mediaServer);
|
||||||
|
mediaPublishEvent.setSchema(hookParam.getSchema());
|
||||||
|
mediaPublishEvent.setParams(hookParam.getParams());
|
||||||
|
return mediaPublishEvent;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String params;
|
||||||
|
|
||||||
|
public String getParams() {
|
||||||
|
return params;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setParams(String params) {
|
||||||
|
this.params = params;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,35 @@
|
|||||||
|
package com.genersoft.iot.vmp.media.event.media;
|
||||||
|
|
||||||
|
import com.genersoft.iot.vmp.media.bean.RecordInfo;
|
||||||
|
import com.genersoft.iot.vmp.media.bean.MediaServer;
|
||||||
|
import com.genersoft.iot.vmp.media.zlm.dto.hook.OnRecordMp4HookParam;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 录像文件生成事件
|
||||||
|
*/
|
||||||
|
public class MediaRecordMp4Event extends MediaEvent {
|
||||||
|
public MediaRecordMp4Event(Object source) {
|
||||||
|
super(source);
|
||||||
|
}
|
||||||
|
|
||||||
|
private RecordInfo recordInfo;
|
||||||
|
|
||||||
|
public static MediaRecordMp4Event getInstance(Object source, OnRecordMp4HookParam hookParam, MediaServer mediaServer){
|
||||||
|
MediaRecordMp4Event mediaRecordMp4Event = new MediaRecordMp4Event(source);
|
||||||
|
mediaRecordMp4Event.setApp(hookParam.getApp());
|
||||||
|
mediaRecordMp4Event.setStream(hookParam.getStream());
|
||||||
|
RecordInfo recordInfo = RecordInfo.getInstance(hookParam);
|
||||||
|
mediaRecordMp4Event.setRecordInfo(recordInfo);
|
||||||
|
mediaRecordMp4Event.setMediaServer(mediaServer);
|
||||||
|
return mediaRecordMp4Event;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RecordInfo getRecordInfo() {
|
||||||
|
return recordInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRecordInfo(RecordInfo recordInfo) {
|
||||||
|
this.recordInfo = recordInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,22 @@
|
|||||||
|
package com.genersoft.iot.vmp.media.event.media;
|
||||||
|
|
||||||
|
import com.genersoft.iot.vmp.media.bean.MediaServer;
|
||||||
|
import com.genersoft.iot.vmp.media.zlm.dto.hook.OnStreamChangedHookParam;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RtpServer收流超时事件
|
||||||
|
*/
|
||||||
|
public class MediaRtpServerTimeoutEvent extends MediaEvent {
|
||||||
|
public MediaRtpServerTimeoutEvent(Object source) {
|
||||||
|
super(source);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MediaRtpServerTimeoutEvent getInstance(Object source, OnStreamChangedHookParam hookParam, MediaServer mediaServer){
|
||||||
|
MediaRtpServerTimeoutEvent mediaDepartureEven = new MediaRtpServerTimeoutEvent(source);
|
||||||
|
mediaDepartureEven.setApp(hookParam.getApp());
|
||||||
|
mediaDepartureEven.setStream(hookParam.getStream());
|
||||||
|
mediaDepartureEven.setSchema(hookParam.getSchema());
|
||||||
|
mediaDepartureEven.setMediaServer(mediaServer);
|
||||||
|
return mediaDepartureEven;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,52 @@
|
|||||||
|
package com.genersoft.iot.vmp.media.event.mediaServer;
|
||||||
|
|
||||||
|
import com.genersoft.iot.vmp.media.bean.MediaServer;
|
||||||
|
import com.genersoft.iot.vmp.media.zlm.dto.hook.OnStreamNotFoundHookParam;
|
||||||
|
import org.springframework.context.ApplicationEvent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送流停止事件
|
||||||
|
*/
|
||||||
|
public class MediaSendRtpStoppedEvent extends ApplicationEvent {
|
||||||
|
public MediaSendRtpStoppedEvent(Object source) {
|
||||||
|
super(source);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String app;
|
||||||
|
|
||||||
|
private String stream;
|
||||||
|
|
||||||
|
private MediaServer mediaServer;
|
||||||
|
|
||||||
|
public static MediaSendRtpStoppedEvent getInstance(Object source, OnStreamNotFoundHookParam hookParam, MediaServer mediaServer){
|
||||||
|
MediaSendRtpStoppedEvent mediaDepartureEven = new MediaSendRtpStoppedEvent(source);
|
||||||
|
mediaDepartureEven.setApp(hookParam.getApp());
|
||||||
|
mediaDepartureEven.setStream(hookParam.getStream());
|
||||||
|
mediaDepartureEven.setMediaServer(mediaServer);
|
||||||
|
return mediaDepartureEven;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getApp() {
|
||||||
|
return app;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setApp(String app) {
|
||||||
|
this.app = app;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getStream() {
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStream(String stream) {
|
||||||
|
this.stream = stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MediaServer getMediaServer() {
|
||||||
|
return mediaServer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMediaServer(MediaServer mediaServer) {
|
||||||
|
this.mediaServer = mediaServer;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,34 @@
|
|||||||
|
package com.genersoft.iot.vmp.media.event.mediaServer;
|
||||||
|
|
||||||
|
import com.genersoft.iot.vmp.media.bean.MediaServer;
|
||||||
|
import org.springframework.context.ApplicationEvent;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class MediaServerChangeEvent extends ApplicationEvent {
|
||||||
|
|
||||||
|
public MediaServerChangeEvent(Object source) {
|
||||||
|
super(source);
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<MediaServer> mediaServerItemList;
|
||||||
|
|
||||||
|
public List<MediaServer> getMediaServerItemList() {
|
||||||
|
return mediaServerItemList;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMediaServerItemList(List<MediaServer> mediaServerItemList) {
|
||||||
|
this.mediaServerItemList = mediaServerItemList;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMediaServerItemList(MediaServer... mediaServerItemArray) {
|
||||||
|
this.mediaServerItemList = new ArrayList<>();
|
||||||
|
this.mediaServerItemList.addAll(Arrays.asList(mediaServerItemArray));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMediaServerItem(List<MediaServer> mediaServerItemList) {
|
||||||
|
this.mediaServerItemList = mediaServerItemList;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
package com.genersoft.iot.vmp.media.event.mediaServer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* zlm在线事件
|
||||||
|
*/
|
||||||
|
public class MediaServerDeleteEvent extends MediaServerEventAbstract {
|
||||||
|
|
||||||
|
public MediaServerDeleteEvent(Object source) {
|
||||||
|
super(source);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,9 +1,8 @@
|
|||||||
package com.genersoft.iot.vmp.media.zlm.event;
|
package com.genersoft.iot.vmp.media.event.mediaServer;
|
||||||
|
|
||||||
import com.genersoft.iot.vmp.media.zlm.ZLMServerConfig;
|
|
||||||
import org.springframework.context.ApplicationEvent;
|
import org.springframework.context.ApplicationEvent;
|
||||||
|
|
||||||
public abstract class ZLMEventAbstract extends ApplicationEvent {
|
public abstract class MediaServerEventAbstract extends ApplicationEvent {
|
||||||
|
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
@ -11,7 +10,7 @@ public abstract class ZLMEventAbstract extends ApplicationEvent {
|
|||||||
private String mediaServerId;
|
private String mediaServerId;
|
||||||
|
|
||||||
|
|
||||||
public ZLMEventAbstract(Object source) {
|
public MediaServerEventAbstract(Object source) {
|
||||||
super(source);
|
super(source);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
package com.genersoft.iot.vmp.media.event.mediaServer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* zlm离线事件类
|
||||||
|
*/
|
||||||
|
public class MediaServerOfflineEvent extends MediaServerEventAbstract {
|
||||||
|
|
||||||
|
public MediaServerOfflineEvent(Object source) {
|
||||||
|
super(source);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
package com.genersoft.iot.vmp.media.event.mediaServer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* zlm在线事件
|
||||||
|
*/
|
||||||
|
public class MediaServerOnlineEvent extends MediaServerEventAbstract {
|
||||||
|
|
||||||
|
public MediaServerOnlineEvent(Object source) {
|
||||||
|
super(source);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,6 +1,5 @@
|
|||||||
package com.genersoft.iot.vmp.media.zlm.event;
|
package com.genersoft.iot.vmp.media.event.mediaServer;
|
||||||
|
|
||||||
import com.genersoft.iot.vmp.service.IMediaServerService;
|
|
||||||
import com.genersoft.iot.vmp.service.IPlayService;
|
import com.genersoft.iot.vmp.service.IPlayService;
|
||||||
import com.genersoft.iot.vmp.service.IStreamProxyService;
|
import com.genersoft.iot.vmp.service.IStreamProxyService;
|
||||||
import com.genersoft.iot.vmp.service.IStreamPushService;
|
import com.genersoft.iot.vmp.service.IStreamPushService;
|
||||||
@ -20,9 +19,9 @@ import org.springframework.stereotype.Component;
|
|||||||
* @date: 2020年5月6日 下午1:51:23
|
* @date: 2020年5月6日 下午1:51:23
|
||||||
*/
|
*/
|
||||||
@Component
|
@Component
|
||||||
public class ZLMStatusEventListener {
|
public class MediaServerStatusEventListener {
|
||||||
|
|
||||||
private final static Logger logger = LoggerFactory.getLogger(ZLMStatusEventListener.class);
|
private final static Logger logger = LoggerFactory.getLogger(MediaServerStatusEventListener.class);
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private IStreamPushService streamPushService;
|
private IStreamPushService streamPushService;
|
||||||
@ -30,16 +29,13 @@ public class ZLMStatusEventListener {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private IStreamProxyService streamProxyService;
|
private IStreamProxyService streamProxyService;
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private IMediaServerService mediaServerService;
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private IPlayService playService;
|
private IPlayService playService;
|
||||||
|
|
||||||
@Async("taskExecutor")
|
@Async("taskExecutor")
|
||||||
@EventListener
|
@EventListener
|
||||||
public void onApplicationEvent(ZLMOnlineEvent event) {
|
public void onApplicationEvent(MediaServerOnlineEvent event) {
|
||||||
logger.info("[ZLM] 上线 ID:" + event.getMediaServerId());
|
logger.info("[媒体节点] 上线 ID:" + event.getMediaServerId());
|
||||||
streamPushService.zlmServerOnline(event.getMediaServerId());
|
streamPushService.zlmServerOnline(event.getMediaServerId());
|
||||||
streamProxyService.zlmServerOnline(event.getMediaServerId());
|
streamProxyService.zlmServerOnline(event.getMediaServerId());
|
||||||
playService.zlmServerOnline(event.getMediaServerId());
|
playService.zlmServerOnline(event.getMediaServerId());
|
||||||
@ -47,11 +43,10 @@ public class ZLMStatusEventListener {
|
|||||||
|
|
||||||
@Async("taskExecutor")
|
@Async("taskExecutor")
|
||||||
@EventListener
|
@EventListener
|
||||||
public void onApplicationEvent(ZLMOfflineEvent event) {
|
public void onApplicationEvent(MediaServerOfflineEvent event) {
|
||||||
|
|
||||||
logger.info("[ZLM] 离线,ID:" + event.getMediaServerId());
|
logger.info("[媒体节点] 离线,ID:" + event.getMediaServerId());
|
||||||
// 处理ZLM离线
|
// 处理ZLM离线
|
||||||
mediaServerService.zlmServerOffline(event.getMediaServerId());
|
|
||||||
streamProxyService.zlmServerOffline(event.getMediaServerId());
|
streamProxyService.zlmServerOffline(event.getMediaServerId());
|
||||||
streamPushService.zlmServerOffline(event.getMediaServerId());
|
streamPushService.zlmServerOffline(event.getMediaServerId());
|
||||||
playService.zlmServerOffline(event.getMediaServerId());
|
playService.zlmServerOffline(event.getMediaServerId());
|
||||||
@ -0,0 +1,61 @@
|
|||||||
|
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.SendRtpItem;
|
||||||
|
import com.genersoft.iot.vmp.media.bean.MediaInfo;
|
||||||
|
import com.genersoft.iot.vmp.media.bean.MediaServer;
|
||||||
|
import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public interface IMediaNodeServerService {
|
||||||
|
int createRTPServer(MediaServer mediaServer, String streamId, long ssrc, Integer port, Boolean onlyAuto, Boolean disableAudio, Boolean reUsePort, Integer tcpMode);
|
||||||
|
|
||||||
|
void closeRtpServer(MediaServer mediaServer, String streamId);
|
||||||
|
|
||||||
|
void closeRtpServer(MediaServer mediaServer, String streamId, CommonCallback<Boolean> callback);
|
||||||
|
|
||||||
|
void closeStreams(MediaServer mediaServer, String app, String stream);
|
||||||
|
|
||||||
|
Boolean updateRtpServerSSRC(MediaServer mediaServer, String stream, String ssrc);
|
||||||
|
|
||||||
|
boolean checkNodeId(MediaServer mediaServer);
|
||||||
|
|
||||||
|
void online(MediaServer mediaServer);
|
||||||
|
|
||||||
|
MediaServer checkMediaServer(String ip, int port, String secret);
|
||||||
|
|
||||||
|
boolean stopSendRtp(MediaServer mediaInfo, String app, String stream, String ssrc);
|
||||||
|
|
||||||
|
boolean deleteRecordDirectory(MediaServer mediaServer, String app, String stream, String date, String fileName);
|
||||||
|
|
||||||
|
List<StreamInfo> getMediaList(MediaServer mediaServer, String app, String stream, String callId);
|
||||||
|
|
||||||
|
Boolean connectRtpServer(MediaServer mediaServer, String address, int port, String stream);
|
||||||
|
|
||||||
|
void getSnap(MediaServer mediaServer, String streamUrl, int timeoutSec, int expireSec, String path, String fileName);
|
||||||
|
|
||||||
|
MediaInfo getMediaInfo(MediaServer mediaServer, String app, String stream);
|
||||||
|
|
||||||
|
Boolean pauseRtpCheck(MediaServer mediaServer, String streamKey);
|
||||||
|
|
||||||
|
Boolean resumeRtpCheck(MediaServer mediaServer, String streamKey);
|
||||||
|
|
||||||
|
String getFfmpegCmd(MediaServer mediaServer, String cmdKey);
|
||||||
|
|
||||||
|
WVPResult<String> addFFmpegSource(MediaServer mediaServer, String srcUrl, String dstUrl, int timeoutMs, boolean enableAudio, boolean enableMp4, String ffmpegCmdKey);
|
||||||
|
|
||||||
|
WVPResult<String> addStreamProxy(MediaServer mediaServer, String app, String stream, String url, boolean enableAudio, boolean enableMp4, String rtpType);
|
||||||
|
|
||||||
|
Boolean delFFmpegSource(MediaServer mediaServer, String streamKey);
|
||||||
|
|
||||||
|
Boolean delStreamProxy(MediaServer mediaServer, String streamKey);
|
||||||
|
|
||||||
|
Map<String, String> getFFmpegCMDs(MediaServer mediaServer);
|
||||||
|
|
||||||
|
void startSendRtpPassive(MediaServer mediaServer, SendRtpItem sendRtpItem, Integer timeout);
|
||||||
|
|
||||||
|
void startSendRtpStream(MediaServer mediaServer, SendRtpItem sendRtpItem);
|
||||||
|
}
|
||||||
150
src/main/java/com/genersoft/iot/vmp/media/service/IMediaServerService.java
Executable file
150
src/main/java/com/genersoft/iot/vmp/media/service/IMediaServerService.java
Executable file
@ -0,0 +1,150 @@
|
|||||||
|
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.ParentPlatform;
|
||||||
|
import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
|
||||||
|
import com.genersoft.iot.vmp.media.bean.MediaInfo;
|
||||||
|
import com.genersoft.iot.vmp.media.bean.MediaServer;
|
||||||
|
import com.genersoft.iot.vmp.service.bean.MediaServerLoad;
|
||||||
|
import com.genersoft.iot.vmp.service.bean.SSRCInfo;
|
||||||
|
import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 媒体服务节点
|
||||||
|
*/
|
||||||
|
public interface IMediaServerService {
|
||||||
|
|
||||||
|
List<MediaServer> getAllOnlineList();
|
||||||
|
|
||||||
|
List<MediaServer> getAll();
|
||||||
|
|
||||||
|
List<MediaServer> getAllFromDatabase();
|
||||||
|
|
||||||
|
List<MediaServer> getAllOnline();
|
||||||
|
|
||||||
|
MediaServer getOne(String generalMediaServerId);
|
||||||
|
|
||||||
|
void syncCatchFromDatabase();
|
||||||
|
|
||||||
|
MediaServer getMediaServerForMinimumLoad(Boolean hasAssist);
|
||||||
|
|
||||||
|
void updateVmServer(List<MediaServer> mediaServerItemList);
|
||||||
|
|
||||||
|
SSRCInfo openRTPServer(MediaServer mediaServerItem, String streamId, String presetSsrc, boolean ssrcCheck,
|
||||||
|
boolean isPlayback, Integer port, Boolean onlyAuto, Boolean disableAudio, Boolean reUsePort, Integer tcpMode);
|
||||||
|
|
||||||
|
void closeRTPServer(MediaServer mediaServerItem, String streamId);
|
||||||
|
|
||||||
|
void closeRTPServer(MediaServer mediaServerItem, String streamId, CommonCallback<Boolean> callback);
|
||||||
|
Boolean updateRtpServerSSRC(MediaServer mediaServerItem, String streamId, String ssrc);
|
||||||
|
|
||||||
|
void closeRTPServer(String mediaServerId, String streamId);
|
||||||
|
|
||||||
|
void clearRTPServer(MediaServer mediaServerItem);
|
||||||
|
|
||||||
|
void update(MediaServer mediaSerItem);
|
||||||
|
|
||||||
|
void addCount(String mediaServerId);
|
||||||
|
|
||||||
|
void removeCount(String mediaServerId);
|
||||||
|
|
||||||
|
void releaseSsrc(String mediaServerItemId, String ssrc);
|
||||||
|
|
||||||
|
void clearMediaServerForOnline();
|
||||||
|
|
||||||
|
void add(MediaServer mediaSerItem);
|
||||||
|
|
||||||
|
void resetOnlineServerItem(MediaServer serverItem);
|
||||||
|
|
||||||
|
MediaServer checkMediaServer(String ip, int port, String secret, String type);
|
||||||
|
|
||||||
|
boolean checkMediaRecordServer(String ip, int port);
|
||||||
|
|
||||||
|
void delete(String id);
|
||||||
|
|
||||||
|
MediaServer getDefaultMediaServer();
|
||||||
|
|
||||||
|
MediaServerLoad getLoad(MediaServer mediaServerItem);
|
||||||
|
|
||||||
|
List<MediaServer> getAllWithAssistPort();
|
||||||
|
|
||||||
|
MediaServer getOneFromDatabase(String id);
|
||||||
|
|
||||||
|
boolean stopSendRtp(MediaServer mediaInfo, String app, String stream, String ssrc);
|
||||||
|
|
||||||
|
boolean deleteRecordDirectory(MediaServer mediaServerItem, String app, String stream, String date, String fileName);
|
||||||
|
|
||||||
|
List<StreamInfo> getMediaList(MediaServer mediaInfo, String app, String stream, String callId);
|
||||||
|
|
||||||
|
Boolean connectRtpServer(MediaServer mediaServerItem, String address, int port, String stream);
|
||||||
|
|
||||||
|
void getSnap(MediaServer mediaServerItemInuse, String streamUrl, int timeoutSec, int expireSec, String path, String fileName);
|
||||||
|
|
||||||
|
MediaInfo getMediaInfo(MediaServer mediaServerItem, String app, String stream);
|
||||||
|
|
||||||
|
Boolean pauseRtpCheck(MediaServer mediaServerItem, String streamKey);
|
||||||
|
|
||||||
|
boolean resumeRtpCheck(MediaServer mediaServerItem, String streamKey);
|
||||||
|
|
||||||
|
String getFfmpegCmd(MediaServer mediaServer, String cmdKey);
|
||||||
|
|
||||||
|
void closeStreams(MediaServer mediaServerItem, String app, String stream);
|
||||||
|
|
||||||
|
WVPResult<String> addFFmpegSource(MediaServer mediaServerItem, String srcUrl, String dstUrl, int timeoutMs, boolean enableAudio, boolean enableMp4, String ffmpegCmdKey);
|
||||||
|
|
||||||
|
WVPResult<String> addStreamProxy(MediaServer mediaServerItem, String app, String stream, String url, boolean enableAudio, boolean enableMp4, String rtpType);
|
||||||
|
|
||||||
|
Boolean delFFmpegSource(MediaServer mediaServerItem, String streamKey);
|
||||||
|
|
||||||
|
Boolean delStreamProxy(MediaServer mediaServerItem, String streamKey);
|
||||||
|
|
||||||
|
Map<String, String> getFFmpegCMDs(MediaServer mediaServer);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据应用名和流ID获取播放地址, 通过zlm接口检查是否存在
|
||||||
|
* @param app
|
||||||
|
* @param stream
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
StreamInfo getStreamInfoByAppAndStreamWithCheck(String app, String stream, String mediaServerId,String addr, boolean authority);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据应用名和流ID获取播放地址, 通过zlm接口检查是否存在, 返回的ip使用远程访问ip,适用与zlm与wvp在一台主机的情况
|
||||||
|
* @param app
|
||||||
|
* @param stream
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
StreamInfo getStreamInfoByAppAndStreamWithCheck(String app, String stream, String mediaServerId, boolean authority);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据应用名和流ID获取播放地址, 只是地址拼接
|
||||||
|
* @param app
|
||||||
|
* @param stream
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
StreamInfo getStreamInfoByAppAndStream(MediaServer mediaServerItem, String app, String stream, MediaInfo mediaInfo, String callId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据应用名和流ID获取播放地址, 只是地址拼接,返回的ip使用远程访问ip,适用与zlm与wvp在一台主机的情况
|
||||||
|
* @param app
|
||||||
|
* @param stream
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
StreamInfo getStreamInfoByAppAndStream(MediaServer mediaServer, String app, String stream, MediaInfo mediaInfo, String addr, String callId, boolean isPlay);
|
||||||
|
|
||||||
|
Boolean isStreamReady(MediaServer mediaServer, String rtp, String streamId);
|
||||||
|
|
||||||
|
void startSendRtpPassive(MediaServer mediaServer, ParentPlatform platform, SendRtpItem sendRtpItem, Integer timeout);
|
||||||
|
|
||||||
|
void startSendRtp(MediaServer mediaServer, ParentPlatform platform, SendRtpItem sendRtpItem);
|
||||||
|
|
||||||
|
SendRtpItem createSendRtpItem(MediaServer mediaServerItem, String addressStr, int port, String ssrc, String requesterId, String deviceId, String channelId, boolean mediaTransmissionTCP, boolean rtcp);
|
||||||
|
|
||||||
|
SendRtpItem createSendRtpItem(MediaServer serverItem, String ip, int port, String ssrc, String platformId,
|
||||||
|
String app, String stream, String channelId, boolean tcp, boolean rtcp);
|
||||||
|
}
|
||||||
@ -0,0 +1,890 @@
|
|||||||
|
package com.genersoft.iot.vmp.media.service.impl;
|
||||||
|
|
||||||
|
import com.baomidou.dynamic.datasource.annotation.DS;
|
||||||
|
import com.genersoft.iot.vmp.common.CommonCallback;
|
||||||
|
import com.genersoft.iot.vmp.common.StreamInfo;
|
||||||
|
import com.genersoft.iot.vmp.common.VideoManagerConstants;
|
||||||
|
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.InviteStreamType;
|
||||||
|
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
|
||||||
|
import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
|
||||||
|
import com.genersoft.iot.vmp.gb28181.session.SSRCFactory;
|
||||||
|
import com.genersoft.iot.vmp.media.bean.MediaInfo;
|
||||||
|
import com.genersoft.iot.vmp.media.event.media.MediaArrivalEvent;
|
||||||
|
import com.genersoft.iot.vmp.media.event.media.MediaDepartureEvent;
|
||||||
|
import com.genersoft.iot.vmp.media.event.mediaServer.MediaServerChangeEvent;
|
||||||
|
import com.genersoft.iot.vmp.media.event.mediaServer.MediaServerDeleteEvent;
|
||||||
|
import com.genersoft.iot.vmp.media.service.IMediaNodeServerService;
|
||||||
|
import com.genersoft.iot.vmp.media.service.IMediaServerService;
|
||||||
|
import com.genersoft.iot.vmp.media.bean.MediaServer;
|
||||||
|
import com.genersoft.iot.vmp.media.zlm.SendRtpPortManager;
|
||||||
|
import com.genersoft.iot.vmp.media.zlm.dto.StreamAuthorityInfo;
|
||||||
|
import com.genersoft.iot.vmp.service.IInviteStreamService;
|
||||||
|
import com.genersoft.iot.vmp.service.bean.MediaServerLoad;
|
||||||
|
import com.genersoft.iot.vmp.service.bean.MessageForPushChannel;
|
||||||
|
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.utils.DateUtil;
|
||||||
|
import com.genersoft.iot.vmp.utils.JsonUtil;
|
||||||
|
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 okhttp3.OkHttpClient;
|
||||||
|
import okhttp3.Request;
|
||||||
|
import okhttp3.Response;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.context.ApplicationEventPublisher;
|
||||||
|
import org.springframework.context.event.EventListener;
|
||||||
|
import org.springframework.data.redis.core.RedisTemplate;
|
||||||
|
import org.springframework.scheduling.annotation.Async;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.util.ObjectUtils;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 媒体服务器节点管理
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
@DS("master")
|
||||||
|
public class MediaServerServiceImpl implements IMediaServerService {
|
||||||
|
|
||||||
|
private final static Logger logger = LoggerFactory.getLogger(MediaServerServiceImpl.class);
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private SSRCFactory ssrcFactory;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private UserSetting userSetting;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private MediaServerMapper mediaServerMapper;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IRedisCatchStorage redisCatchStorage;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IInviteStreamService inviteStreamService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private RedisTemplate<Object, Object> redisTemplate;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private Map<String, IMediaNodeServerService> nodeServerServiceMap;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ApplicationEventPublisher applicationEventPublisher;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private MediaConfig mediaConfig;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private SendRtpPortManager sendRtpPortManager;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 流到来的处理
|
||||||
|
*/
|
||||||
|
@Async("taskExecutor")
|
||||||
|
@org.springframework.context.event.EventListener
|
||||||
|
public void onApplicationEvent(MediaArrivalEvent event) {
|
||||||
|
if ("rtsp".equals(event.getSchema())) {
|
||||||
|
logger.info("流变化:注册 app->{}, stream->{}", event.getApp(), event.getStream());
|
||||||
|
addCount(event.getMediaServer().getId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 流离开的处理
|
||||||
|
*/
|
||||||
|
@Async("taskExecutor")
|
||||||
|
@EventListener
|
||||||
|
public void onApplicationEvent(MediaDepartureEvent event) {
|
||||||
|
if ("rtsp".equals(event.getSchema())) {
|
||||||
|
logger.info("流变化:注销, app->{}, stream->{}", event.getApp(), event.getStream());
|
||||||
|
removeCount(event.getMediaServer().getId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void updateVmServer(List<MediaServer> mediaServerList) {
|
||||||
|
logger.info("[媒体服务节点] 缓存初始化 ");
|
||||||
|
for (MediaServer mediaServer : mediaServerList) {
|
||||||
|
if (ObjectUtils.isEmpty(mediaServer.getId())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// 更新
|
||||||
|
if (!ssrcFactory.hasMediaServerSSRC(mediaServer.getId())) {
|
||||||
|
ssrcFactory.initMediaServerSSRC(mediaServer.getId(), null);
|
||||||
|
}
|
||||||
|
// 查询redis是否存在此mediaServer
|
||||||
|
String key = VideoManagerConstants.MEDIA_SERVER_PREFIX + userSetting.getServerId() + ":" + mediaServer.getId();
|
||||||
|
Boolean hasKey = redisTemplate.hasKey(key);
|
||||||
|
if (hasKey != null && ! hasKey) {
|
||||||
|
redisTemplate.opsForValue().set(key, mediaServer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SSRCInfo openRTPServer(MediaServer mediaServer, String streamId, String presetSsrc, boolean ssrcCheck,
|
||||||
|
boolean isPlayback, Integer port, Boolean onlyAuto, Boolean disableAudio, Boolean reUsePort, Integer tcpMode) {
|
||||||
|
if (mediaServer == null || mediaServer.getId() == null) {
|
||||||
|
logger.info("[openRTPServer] 失败, mediaServer == null || mediaServer.getId() == null");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
// 获取mediaServer可用的ssrc
|
||||||
|
String ssrc;
|
||||||
|
if (presetSsrc != null) {
|
||||||
|
ssrc = presetSsrc;
|
||||||
|
}else {
|
||||||
|
if (isPlayback) {
|
||||||
|
ssrc = ssrcFactory.getPlayBackSsrc(mediaServer.getId());
|
||||||
|
}else {
|
||||||
|
ssrc = ssrcFactory.getPlaySsrc(mediaServer.getId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (streamId == null) {
|
||||||
|
streamId = String.format("%08x", Long.parseLong(ssrc)).toUpperCase();
|
||||||
|
}
|
||||||
|
if (ssrcCheck && tcpMode > 0) {
|
||||||
|
// 目前zlm不支持 tcp模式更新ssrc,暂时关闭ssrc校验
|
||||||
|
logger.warn("[openRTPServer] 平台对接时下级可能自定义ssrc,但是tcp模式zlm收流目前无法更新ssrc,可能收流超时,此时请使用udp收流或者关闭ssrc校验");
|
||||||
|
}
|
||||||
|
int rtpServerPort;
|
||||||
|
if (mediaServer.isRtpEnable()) {
|
||||||
|
IMediaNodeServerService mediaNodeServerService = nodeServerServiceMap.get(mediaServer.getType());
|
||||||
|
if (mediaNodeServerService == null) {
|
||||||
|
logger.info("[openRTPServer] 失败, mediaServer的类型: {},未找到对应的实现类", mediaServer.getType());
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
rtpServerPort = mediaNodeServerService.createRTPServer(mediaServer, streamId, ssrcCheck ? Long.parseLong(ssrc) : 0, port, onlyAuto, disableAudio, reUsePort, tcpMode);
|
||||||
|
} else {
|
||||||
|
rtpServerPort = mediaServer.getRtpProxyPort();
|
||||||
|
}
|
||||||
|
return new SSRCInfo(rtpServerPort, ssrc, streamId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void closeRTPServer(MediaServer mediaServer, String streamId) {
|
||||||
|
if (mediaServer == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
IMediaNodeServerService mediaNodeServerService = nodeServerServiceMap.get(mediaServer.getType());
|
||||||
|
if (mediaNodeServerService == null) {
|
||||||
|
logger.info("[closeRTPServer] 失败, mediaServer的类型: {},未找到对应的实现类", mediaServer.getType());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mediaNodeServerService.closeRtpServer(mediaServer, streamId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void closeRTPServer(MediaServer mediaServer, String streamId, CommonCallback<Boolean> callback) {
|
||||||
|
if (mediaServer == null) {
|
||||||
|
callback.run(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
IMediaNodeServerService mediaNodeServerService = nodeServerServiceMap.get(mediaServer.getType());
|
||||||
|
if (mediaNodeServerService == null) {
|
||||||
|
logger.info("[closeRTPServer] 失败, mediaServer的类型: {},未找到对应的实现类", mediaServer.getType());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mediaNodeServerService.closeRtpServer(mediaServer, streamId, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void closeRTPServer(String mediaServerId, String streamId) {
|
||||||
|
MediaServer mediaServer = this.getOne(mediaServerId);
|
||||||
|
if (mediaServer == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (mediaServer.isRtpEnable()) {
|
||||||
|
closeRTPServer(mediaServer, streamId);
|
||||||
|
}
|
||||||
|
IMediaNodeServerService mediaNodeServerService = nodeServerServiceMap.get(mediaServer.getType());
|
||||||
|
if (mediaNodeServerService == null) {
|
||||||
|
logger.info("[closeRTPServer] 失败, mediaServer的类型: {},未找到对应的实现类", mediaServer.getType());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mediaNodeServerService.closeStreams(mediaServer, "rtp", streamId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Boolean updateRtpServerSSRC(MediaServer mediaServer, String streamId, String ssrc) {
|
||||||
|
if (mediaServer == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
IMediaNodeServerService mediaNodeServerService = nodeServerServiceMap.get(mediaServer.getType());
|
||||||
|
if (mediaNodeServerService == null) {
|
||||||
|
logger.info("[updateRtpServerSSRC] 失败, mediaServer的类型: {},未找到对应的实现类", mediaServer.getType());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return mediaNodeServerService.updateRtpServerSSRC(mediaServer, streamId, ssrc);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void releaseSsrc(String mediaServerId, String ssrc) {
|
||||||
|
MediaServer mediaServer = getOne(mediaServerId);
|
||||||
|
if (mediaServer == null || ssrc == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ssrcFactory.releaseSsrc(mediaServerId, ssrc);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 媒体服务节点 重启后重置他的推流信息, TODO 给正在使用的设备发送停止命令
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void clearRTPServer(MediaServer mediaServer) {
|
||||||
|
ssrcFactory.reset(mediaServer.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void update(MediaServer mediaSerItem) {
|
||||||
|
mediaServerMapper.update(mediaSerItem);
|
||||||
|
MediaServer mediaServerInRedis = getOne(mediaSerItem.getId());
|
||||||
|
MediaServer mediaServerInDataBase = mediaServerMapper.queryOne(mediaSerItem.getId());
|
||||||
|
if (mediaServerInDataBase == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mediaServerInDataBase.setStatus(mediaSerItem.isStatus());
|
||||||
|
if (mediaServerInRedis == null || !ssrcFactory.hasMediaServerSSRC(mediaServerInDataBase.getId())) {
|
||||||
|
ssrcFactory.initMediaServerSSRC(mediaServerInDataBase.getId(),null);
|
||||||
|
}
|
||||||
|
String key = VideoManagerConstants.MEDIA_SERVER_PREFIX + userSetting.getServerId() + ":" + mediaServerInDataBase.getId();
|
||||||
|
redisTemplate.opsForValue().set(key, mediaServerInDataBase);
|
||||||
|
if (mediaServerInDataBase.isStatus()) {
|
||||||
|
resetOnlineServerItem(mediaServerInDataBase);
|
||||||
|
}else {
|
||||||
|
// 发送事件
|
||||||
|
MediaServerChangeEvent event = new MediaServerChangeEvent(this);
|
||||||
|
event.setMediaServerItemList(mediaServerInDataBase);
|
||||||
|
applicationEventPublisher.publishEvent(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<MediaServer> getAllOnlineList() {
|
||||||
|
List<MediaServer> result = new ArrayList<>();
|
||||||
|
List<Object> mediaServerKeys = RedisUtil.scan(redisTemplate, String.format("%S*", VideoManagerConstants.MEDIA_SERVER_PREFIX+ userSetting.getServerId() + ":" ));
|
||||||
|
String onlineKey = VideoManagerConstants.ONLINE_MEDIA_SERVERS_PREFIX + userSetting.getServerId();
|
||||||
|
for (Object mediaServerKey : mediaServerKeys) {
|
||||||
|
String key = (String) mediaServerKey;
|
||||||
|
MediaServer mediaServer = JsonUtil.redisJsonToObject(redisTemplate, key, MediaServer.class);
|
||||||
|
if (Objects.isNull(mediaServer)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// 检查状态
|
||||||
|
Double aDouble = redisTemplate.opsForZSet().score(onlineKey, mediaServer.getId());
|
||||||
|
if (aDouble != null) {
|
||||||
|
mediaServer.setStatus(true);
|
||||||
|
}
|
||||||
|
result.add(mediaServer);
|
||||||
|
}
|
||||||
|
result.sort((serverItem1, serverItem2)->{
|
||||||
|
int sortResult = 0;
|
||||||
|
LocalDateTime localDateTime1 = LocalDateTime.parse(serverItem1.getCreateTime(), DateUtil.formatter);
|
||||||
|
LocalDateTime localDateTime2 = LocalDateTime.parse(serverItem2.getCreateTime(), DateUtil.formatter);
|
||||||
|
|
||||||
|
sortResult = localDateTime1.compareTo(localDateTime2);
|
||||||
|
return sortResult;
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<MediaServer> getAll() {
|
||||||
|
List<MediaServer> mediaServerList = mediaServerMapper.queryAll();
|
||||||
|
if (mediaServerList.isEmpty()) {
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
for (MediaServer mediaServer : mediaServerList) {
|
||||||
|
MediaServer mediaServerInRedis = getOne(mediaServer.getId());
|
||||||
|
if (mediaServerInRedis != null) {
|
||||||
|
mediaServer.setStatus(mediaServerInRedis.isStatus());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return mediaServerList;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<MediaServer> getAllFromDatabase() {
|
||||||
|
return mediaServerMapper.queryAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<MediaServer> getAllOnline() {
|
||||||
|
String key = VideoManagerConstants.ONLINE_MEDIA_SERVERS_PREFIX + userSetting.getServerId();
|
||||||
|
Set<Object> mediaServerIdSet = redisTemplate.opsForZSet().reverseRange(key, 0, -1);
|
||||||
|
|
||||||
|
List<MediaServer> result = new ArrayList<>();
|
||||||
|
if (mediaServerIdSet != null && mediaServerIdSet.size() > 0) {
|
||||||
|
for (Object mediaServerId : mediaServerIdSet) {
|
||||||
|
String mediaServerIdStr = (String) mediaServerId;
|
||||||
|
String serverKey = VideoManagerConstants.MEDIA_SERVER_PREFIX + userSetting.getServerId() + ":" + mediaServerIdStr;
|
||||||
|
result.add((MediaServer) redisTemplate.opsForValue().get(serverKey));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Collections.reverse(result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取单个媒体服务节点服务器
|
||||||
|
* @param mediaServerId 服务id
|
||||||
|
* @return mediaServer
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public MediaServer getOne(String mediaServerId) {
|
||||||
|
if (mediaServerId == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
String key = VideoManagerConstants.MEDIA_SERVER_PREFIX + userSetting.getServerId() + ":" + mediaServerId;
|
||||||
|
return JsonUtil.redisJsonToObject(redisTemplate, key, MediaServer.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MediaServer getDefaultMediaServer() {
|
||||||
|
return mediaServerMapper.queryDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void clearMediaServerForOnline() {
|
||||||
|
String key = VideoManagerConstants.ONLINE_MEDIA_SERVERS_PREFIX + userSetting.getServerId();
|
||||||
|
redisTemplate.delete(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void add(MediaServer mediaServer) {
|
||||||
|
mediaServer.setCreateTime(DateUtil.getNow());
|
||||||
|
mediaServer.setUpdateTime(DateUtil.getNow());
|
||||||
|
if (mediaServer.getHookAliveInterval() == null || mediaServer.getHookAliveInterval() == 0F) {
|
||||||
|
mediaServer.setHookAliveInterval(10F);
|
||||||
|
}
|
||||||
|
if (mediaServer.getType() == null) {
|
||||||
|
logger.info("[添加媒体节点] 失败, mediaServer的类型:为空");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (mediaServerMapper.queryOne(mediaServer.getId()) != null) {
|
||||||
|
logger.info("[添加媒体节点] 失败, 媒体服务ID已存在,请修改媒体服务器配置, {}", mediaServer.getId());
|
||||||
|
throw new ControllerException(ErrorCode.ERROR100.getCode(),"保存失败,媒体服务ID [ " + mediaServer.getId() + " ] 已存在,请修改媒体服务器配置");
|
||||||
|
}
|
||||||
|
IMediaNodeServerService mediaNodeServerService = nodeServerServiceMap.get(mediaServer.getType());
|
||||||
|
if (mediaNodeServerService == null) {
|
||||||
|
logger.info("[添加媒体节点] 失败, mediaServer的类型: {},未找到对应的实现类", mediaServer.getType());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mediaServerMapper.add(mediaServer);
|
||||||
|
if (mediaServer.isStatus()) {
|
||||||
|
mediaNodeServerService.online(mediaServer);
|
||||||
|
}else {
|
||||||
|
// 发送事件
|
||||||
|
MediaServerChangeEvent event = new MediaServerChangeEvent(this);
|
||||||
|
event.setMediaServerItemList(mediaServer);
|
||||||
|
applicationEventPublisher.publishEvent(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void resetOnlineServerItem(MediaServer serverItem) {
|
||||||
|
// 更新缓存
|
||||||
|
String key = VideoManagerConstants.ONLINE_MEDIA_SERVERS_PREFIX + userSetting.getServerId();
|
||||||
|
// 使用zset的分数作为当前并发量, 默认值设置为0
|
||||||
|
if (redisTemplate.opsForZSet().score(key, serverItem.getId()) == null) { // 不存在则设置默认值 已存在则重置
|
||||||
|
redisTemplate.opsForZSet().add(key, serverItem.getId(), 0L);
|
||||||
|
// 查询服务流数量
|
||||||
|
int count = getMediaList(serverItem);
|
||||||
|
redisTemplate.opsForZSet().add(key, serverItem.getId(), count);
|
||||||
|
}else {
|
||||||
|
clearRTPServer(serverItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getMediaList(MediaServer serverItem) {
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addCount(String mediaServerId) {
|
||||||
|
if (mediaServerId == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String key = VideoManagerConstants.ONLINE_MEDIA_SERVERS_PREFIX + userSetting.getServerId();
|
||||||
|
redisTemplate.opsForZSet().incrementScore(key, mediaServerId, 1);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeCount(String mediaServerId) {
|
||||||
|
String key = VideoManagerConstants.ONLINE_MEDIA_SERVERS_PREFIX + userSetting.getServerId();
|
||||||
|
redisTemplate.opsForZSet().incrementScore(key, mediaServerId, - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取负载最低的节点
|
||||||
|
* @return mediaServer
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public MediaServer getMediaServerForMinimumLoad(Boolean hasAssist) {
|
||||||
|
String key = VideoManagerConstants.ONLINE_MEDIA_SERVERS_PREFIX + userSetting.getServerId();
|
||||||
|
Long size = redisTemplate.opsForZSet().zCard(key);
|
||||||
|
if (size == null || size == 0) {
|
||||||
|
logger.info("获取负载最低的节点时无在线节点");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取分数最低的,及并发最低的
|
||||||
|
Set<Object> objects = redisTemplate.opsForZSet().range(key, 0, -1);
|
||||||
|
ArrayList<Object> mediaServerObjectS = new ArrayList<>(objects);
|
||||||
|
MediaServer mediaServer = null;
|
||||||
|
if (hasAssist == null) {
|
||||||
|
String mediaServerId = (String)mediaServerObjectS.get(0);
|
||||||
|
mediaServer = getOne(mediaServerId);
|
||||||
|
}else if (hasAssist) {
|
||||||
|
for (Object mediaServerObject : mediaServerObjectS) {
|
||||||
|
String mediaServerId = (String)mediaServerObject;
|
||||||
|
MediaServer serverItem = getOne(mediaServerId);
|
||||||
|
if (serverItem.getRecordAssistPort() > 0) {
|
||||||
|
mediaServer = serverItem;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}else if (!hasAssist) {
|
||||||
|
for (Object mediaServerObject : mediaServerObjectS) {
|
||||||
|
String mediaServerId = (String)mediaServerObject;
|
||||||
|
MediaServer serverItem = getOne(mediaServerId);
|
||||||
|
if (serverItem.getRecordAssistPort() == 0) {
|
||||||
|
mediaServer = serverItem;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return mediaServer;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MediaServer checkMediaServer(String ip, int port, String secret, String type) {
|
||||||
|
if (mediaServerMapper.queryOneByHostAndPort(ip, port) != null) {
|
||||||
|
throw new ControllerException(ErrorCode.ERROR100.getCode(), "此连接已存在");
|
||||||
|
}
|
||||||
|
|
||||||
|
IMediaNodeServerService mediaNodeServerService = nodeServerServiceMap.get(type);
|
||||||
|
if (mediaNodeServerService == null) {
|
||||||
|
logger.info("[closeRTPServer] 失败, mediaServer的类型: {},未找到对应的实现类", type);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
MediaServer mediaServer = mediaNodeServerService.checkMediaServer(ip, port, secret);
|
||||||
|
if (mediaServer != null) {
|
||||||
|
if (mediaServerMapper.queryOne(mediaServer.getId()) != null) {
|
||||||
|
throw new ControllerException(ErrorCode.ERROR100.getCode(), "媒体服务ID [" + mediaServer.getId() + " ] 已存在,请修改媒体服务器配置");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return mediaServer;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean checkMediaRecordServer(String ip, int port) {
|
||||||
|
boolean result = false;
|
||||||
|
OkHttpClient client = new OkHttpClient();
|
||||||
|
String url = String.format("http://%s:%s/index/api/record", ip, port);
|
||||||
|
Request request = new Request.Builder()
|
||||||
|
.get()
|
||||||
|
.url(url)
|
||||||
|
.build();
|
||||||
|
try {
|
||||||
|
Response response = client.newCall(request).execute();
|
||||||
|
if (response != null) {
|
||||||
|
result = true;
|
||||||
|
}
|
||||||
|
} catch (Exception e) {}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void delete(String id) {
|
||||||
|
mediaServerMapper.delOne(id);
|
||||||
|
redisTemplate.opsForZSet().remove(VideoManagerConstants.ONLINE_MEDIA_SERVERS_PREFIX + userSetting.getServerId(), id);
|
||||||
|
String key = VideoManagerConstants.MEDIA_SERVER_PREFIX + userSetting.getServerId() + ":" + id;
|
||||||
|
redisTemplate.delete(key);
|
||||||
|
// 发送节点移除通知
|
||||||
|
MediaServerDeleteEvent event = new MediaServerDeleteEvent(this);
|
||||||
|
event.setMediaServerId(id);
|
||||||
|
applicationEventPublisher.publishEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MediaServer getOneFromDatabase(String mediaServerId) {
|
||||||
|
return mediaServerMapper.queryOne(mediaServerId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void syncCatchFromDatabase() {
|
||||||
|
List<MediaServer> allInCatch = getAllOnlineList();
|
||||||
|
List<MediaServer> allInDatabase = mediaServerMapper.queryAll();
|
||||||
|
Map<String, MediaServer> mediaServerMap = new HashMap<>();
|
||||||
|
|
||||||
|
for (MediaServer mediaServer : allInDatabase) {
|
||||||
|
mediaServerMap.put(mediaServer.getId(), mediaServer);
|
||||||
|
}
|
||||||
|
for (MediaServer mediaServer : allInCatch) {
|
||||||
|
// 清除数据中不存在但redis缓存数据
|
||||||
|
if (!mediaServerMap.containsKey(mediaServer.getId())) {
|
||||||
|
delete(mediaServer.getId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MediaServerLoad getLoad(MediaServer mediaServer) {
|
||||||
|
MediaServerLoad result = new MediaServerLoad();
|
||||||
|
result.setId(mediaServer.getId());
|
||||||
|
result.setPush(redisCatchStorage.getPushStreamCount(mediaServer.getId()));
|
||||||
|
result.setProxy(redisCatchStorage.getProxyStreamCount(mediaServer.getId()));
|
||||||
|
|
||||||
|
result.setGbReceive(inviteStreamService.getStreamInfoCount(mediaServer.getId()));
|
||||||
|
result.setGbSend(redisCatchStorage.getGbSendCount(mediaServer.getId()));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<MediaServer> getAllWithAssistPort() {
|
||||||
|
return mediaServerMapper.queryAllWithAssistPort();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean stopSendRtp(MediaServer mediaInfo, String app, String stream, String ssrc) {
|
||||||
|
IMediaNodeServerService mediaNodeServerService = nodeServerServiceMap.get(mediaInfo.getType());
|
||||||
|
if (mediaNodeServerService == null) {
|
||||||
|
logger.info("[stopSendRtp] 失败, mediaServer的类型: {},未找到对应的实现类", mediaInfo.getType());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return mediaNodeServerService.stopSendRtp(mediaInfo, app, stream, ssrc);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean deleteRecordDirectory(MediaServer mediaServer, String app, String stream, String date, String fileName) {
|
||||||
|
IMediaNodeServerService mediaNodeServerService = nodeServerServiceMap.get(mediaServer.getType());
|
||||||
|
if (mediaNodeServerService == null) {
|
||||||
|
logger.info("[stopSendRtp] 失败, mediaServer的类型: {},未找到对应的实现类", mediaServer.getType());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return mediaNodeServerService.deleteRecordDirectory(mediaServer, app, stream, date, fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<StreamInfo> getMediaList(MediaServer mediaServer, String app, String stream, String callId) {
|
||||||
|
IMediaNodeServerService mediaNodeServerService = nodeServerServiceMap.get(mediaServer.getType());
|
||||||
|
if (mediaNodeServerService == null) {
|
||||||
|
logger.info("[getMediaList] 失败, mediaServer的类型: {},未找到对应的实现类", mediaServer.getType());
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
return mediaNodeServerService.getMediaList(mediaServer, app, stream, callId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Boolean connectRtpServer(MediaServer mediaServer, String address, int port, String stream) {
|
||||||
|
IMediaNodeServerService mediaNodeServerService = nodeServerServiceMap.get(mediaServer.getType());
|
||||||
|
if (mediaNodeServerService == null) {
|
||||||
|
logger.info("[connectRtpServer] 失败, mediaServer的类型: {},未找到对应的实现类", mediaServer.getType());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return mediaNodeServerService.connectRtpServer(mediaServer, address, port, stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void getSnap(MediaServer mediaServer, String streamUrl, int timeoutSec, int expireSec, String path, String fileName) {
|
||||||
|
IMediaNodeServerService mediaNodeServerService = nodeServerServiceMap.get(mediaServer.getType());
|
||||||
|
if (mediaNodeServerService == null) {
|
||||||
|
logger.info("[getSnap] 失败, mediaServer的类型: {},未找到对应的实现类", mediaServer.getType());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mediaNodeServerService.getSnap(mediaServer, streamUrl, timeoutSec, expireSec, path, fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MediaInfo getMediaInfo(MediaServer mediaServer, String app, String stream) {
|
||||||
|
IMediaNodeServerService mediaNodeServerService = nodeServerServiceMap.get(mediaServer.getType());
|
||||||
|
if (mediaNodeServerService == null) {
|
||||||
|
logger.info("[getMediaInfo] 失败, mediaServer的类型: {},未找到对应的实现类", mediaServer.getType());
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return mediaNodeServerService.getMediaInfo(mediaServer, app, stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Boolean pauseRtpCheck(MediaServer mediaServer, String streamKey) {
|
||||||
|
IMediaNodeServerService mediaNodeServerService = nodeServerServiceMap.get(mediaServer.getType());
|
||||||
|
if (mediaNodeServerService == null) {
|
||||||
|
logger.info("[pauseRtpCheck] 失败, mediaServer的类型: {},未找到对应的实现类", mediaServer.getType());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return mediaNodeServerService.pauseRtpCheck(mediaServer, streamKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean resumeRtpCheck(MediaServer mediaServer, String streamKey) {
|
||||||
|
IMediaNodeServerService mediaNodeServerService = nodeServerServiceMap.get(mediaServer.getType());
|
||||||
|
if (mediaNodeServerService == null) {
|
||||||
|
logger.info("[pauseRtpCheck] 失败, mediaServer的类型: {},未找到对应的实现类", mediaServer.getType());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return mediaNodeServerService.resumeRtpCheck(mediaServer, streamKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getFfmpegCmd(MediaServer mediaServer, String cmdKey) {
|
||||||
|
IMediaNodeServerService mediaNodeServerService = nodeServerServiceMap.get(mediaServer.getType());
|
||||||
|
if (mediaNodeServerService == null) {
|
||||||
|
logger.info("[getFfmpegCmd] 失败, mediaServer的类型: {},未找到对应的实现类", mediaServer.getType());
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return mediaNodeServerService.getFfmpegCmd(mediaServer, cmdKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void closeStreams(MediaServer mediaServer, String app, String stream) {
|
||||||
|
IMediaNodeServerService mediaNodeServerService = nodeServerServiceMap.get(mediaServer.getType());
|
||||||
|
if (mediaNodeServerService == null) {
|
||||||
|
logger.info("[closeStreams] 失败, mediaServer的类型: {},未找到对应的实现类", mediaServer.getType());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mediaNodeServerService.closeStreams(mediaServer, app, stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WVPResult<String> addFFmpegSource(MediaServer mediaServer, String srcUrl, String dstUrl, int timeoutMs, boolean enableAudio, boolean enableMp4, String ffmpegCmdKey) {
|
||||||
|
IMediaNodeServerService mediaNodeServerService = nodeServerServiceMap.get(mediaServer.getType());
|
||||||
|
if (mediaNodeServerService == null) {
|
||||||
|
logger.info("[addFFmpegSource] 失败, mediaServer的类型: {},未找到对应的实现类", mediaServer.getType());
|
||||||
|
return WVPResult.fail(ErrorCode.ERROR400);
|
||||||
|
}
|
||||||
|
return mediaNodeServerService.addFFmpegSource(mediaServer, srcUrl, dstUrl, timeoutMs, enableAudio, enableMp4, ffmpegCmdKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WVPResult<String> addStreamProxy(MediaServer mediaServer, String app, String stream, String url, boolean enableAudio, boolean enableMp4, String rtpType) {
|
||||||
|
IMediaNodeServerService mediaNodeServerService = nodeServerServiceMap.get(mediaServer.getType());
|
||||||
|
if (mediaNodeServerService == null) {
|
||||||
|
logger.info("[addStreamProxy] 失败, mediaServer的类型: {},未找到对应的实现类", mediaServer.getType());
|
||||||
|
return WVPResult.fail(ErrorCode.ERROR400);
|
||||||
|
}
|
||||||
|
return mediaNodeServerService.addStreamProxy(mediaServer, app, stream, url, enableAudio, enableMp4, rtpType);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Boolean delFFmpegSource(MediaServer mediaServer, String streamKey) {
|
||||||
|
IMediaNodeServerService mediaNodeServerService = nodeServerServiceMap.get(mediaServer.getType());
|
||||||
|
if (mediaNodeServerService == null) {
|
||||||
|
logger.info("[delFFmpegSource] 失败, mediaServer的类型: {},未找到对应的实现类", mediaServer.getType());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return mediaNodeServerService.delFFmpegSource(mediaServer, streamKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Boolean delStreamProxy(MediaServer mediaServerItem, String streamKey) {
|
||||||
|
IMediaNodeServerService mediaNodeServerService = nodeServerServiceMap.get(mediaServerItem.getType());
|
||||||
|
if (mediaNodeServerService == null) {
|
||||||
|
logger.info("[delStreamProxy] 失败, mediaServer的类型: {},未找到对应的实现类", mediaServerItem.getType());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return mediaNodeServerService.delStreamProxy(mediaServerItem, streamKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, String> getFFmpegCMDs(MediaServer mediaServer) {
|
||||||
|
IMediaNodeServerService mediaNodeServerService = nodeServerServiceMap.get(mediaServer.getType());
|
||||||
|
if (mediaNodeServerService == null) {
|
||||||
|
logger.info("[getFFmpegCMDs] 失败, mediaServer的类型: {},未找到对应的实现类", mediaServer.getType());
|
||||||
|
return new HashMap<>();
|
||||||
|
}
|
||||||
|
return mediaNodeServerService.getFFmpegCMDs(mediaServer);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public StreamInfo getStreamInfoByAppAndStream(MediaServer mediaServerItem, String app, String stream, MediaInfo mediaInfo, String callId) {
|
||||||
|
return getStreamInfoByAppAndStream(mediaServerItem, app, stream, mediaInfo, null, callId, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public StreamInfo getStreamInfoByAppAndStreamWithCheck(String app, String stream, String mediaServerId, String addr, boolean authority) {
|
||||||
|
StreamInfo streamInfo = null;
|
||||||
|
if (mediaServerId == null) {
|
||||||
|
mediaServerId = mediaConfig.getId();
|
||||||
|
}
|
||||||
|
MediaServer mediaInfo = getOne(mediaServerId);
|
||||||
|
if (mediaInfo == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
String calld = null;
|
||||||
|
StreamAuthorityInfo streamAuthorityInfo = redisCatchStorage.getStreamAuthorityInfo(app, stream);
|
||||||
|
if (streamAuthorityInfo != null) {
|
||||||
|
calld = streamAuthorityInfo.getCallId();
|
||||||
|
}
|
||||||
|
List<StreamInfo> streamInfoList = getMediaList(mediaInfo, app, stream, calld);
|
||||||
|
if (streamInfoList.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}else {
|
||||||
|
return streamInfoList.get(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public StreamInfo getStreamInfoByAppAndStreamWithCheck(String app, String stream, String mediaServerId, boolean authority) {
|
||||||
|
return getStreamInfoByAppAndStreamWithCheck(app, stream, mediaServerId, null, authority);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public StreamInfo getStreamInfoByAppAndStream(MediaServer mediaServer, String app, String stream, MediaInfo mediaInfo, String addr, String callId, boolean isPlay) {
|
||||||
|
StreamInfo streamInfoResult = new StreamInfo();
|
||||||
|
streamInfoResult.setStream(stream);
|
||||||
|
streamInfoResult.setApp(app);
|
||||||
|
if (addr == null) {
|
||||||
|
addr = mediaServer.getStreamIp();
|
||||||
|
}
|
||||||
|
|
||||||
|
streamInfoResult.setIp(addr);
|
||||||
|
streamInfoResult.setMediaServerId(mediaServer.getId());
|
||||||
|
String callIdParam = ObjectUtils.isEmpty(callId)?"":"?callId=" + callId;
|
||||||
|
streamInfoResult.setRtmp(addr, mediaServer.getRtmpPort(),mediaServer.getRtmpSSlPort(), app, stream, callIdParam);
|
||||||
|
streamInfoResult.setRtsp(addr, mediaServer.getRtspPort(),mediaServer.getRtspSSLPort(), app, stream, callIdParam);
|
||||||
|
|
||||||
|
|
||||||
|
if ("abl".equals(mediaServer.getType())) {
|
||||||
|
String flvFile = String.format("%s/%s.flv%s", app, stream, callIdParam);
|
||||||
|
streamInfoResult.setFlv(addr, mediaServer.getFlvPort(),mediaServer.getFlvSSLPort(), flvFile);
|
||||||
|
streamInfoResult.setWsFlv(addr, mediaServer.getWsFlvPort(),mediaServer.getWsFlvSSLPort(), flvFile);
|
||||||
|
}else {
|
||||||
|
String flvFile = String.format("%s/%s.live.flv%s", app, stream, callIdParam);
|
||||||
|
streamInfoResult.setFlv(addr, mediaServer.getFlvPort(),mediaServer.getFlvSSLPort(), flvFile);
|
||||||
|
streamInfoResult.setWsFlv(addr, mediaServer.getWsFlvPort(),mediaServer.getWsFlvSSLPort(), flvFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
streamInfoResult.setFmp4(addr, mediaServer.getHttpPort(),mediaServer.getHttpSSlPort(), app, stream, callIdParam);
|
||||||
|
streamInfoResult.setHls(addr, mediaServer.getHttpPort(),mediaServer.getHttpSSlPort(), app, stream, callIdParam);
|
||||||
|
streamInfoResult.setTs(addr, mediaServer.getHttpPort(),mediaServer.getHttpSSlPort(), app, stream, callIdParam);
|
||||||
|
streamInfoResult.setRtc(addr, mediaServer.getHttpPort(),mediaServer.getHttpSSlPort(), app, stream, callIdParam, isPlay);
|
||||||
|
|
||||||
|
streamInfoResult.setMediaInfo(mediaInfo);
|
||||||
|
return streamInfoResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Boolean isStreamReady(MediaServer mediaServer, String rtp, String streamId) {
|
||||||
|
IMediaNodeServerService mediaNodeServerService = nodeServerServiceMap.get(mediaServer.getType());
|
||||||
|
if (mediaNodeServerService == null) {
|
||||||
|
logger.info("[isStreamReady] 失败, mediaServer的类型: {},未找到对应的实现类", mediaServer.getType());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
MediaInfo mediaInfo = mediaNodeServerService.getMediaInfo(mediaServer, rtp, streamId);
|
||||||
|
return mediaInfo != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void startSendRtpPassive(MediaServer mediaServer, ParentPlatform platform, SendRtpItem sendRtpItem, Integer timeout) {
|
||||||
|
IMediaNodeServerService mediaNodeServerService = nodeServerServiceMap.get(mediaServer.getType());
|
||||||
|
if (mediaNodeServerService == null) {
|
||||||
|
logger.info("[startSendRtpPassive] 失败, mediaServer的类型: {},未找到对应的实现类", mediaServer.getType());
|
||||||
|
throw new ControllerException(ErrorCode.ERROR100.getCode(), "未找到mediaServer对应的实现类");
|
||||||
|
}
|
||||||
|
mediaNodeServerService.startSendRtpPassive(mediaServer, sendRtpItem, timeout);
|
||||||
|
sendPlatformStartPlayMsg(platform, sendRtpItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void startSendRtp(MediaServer mediaServer, ParentPlatform platform, SendRtpItem sendRtpItem) {
|
||||||
|
IMediaNodeServerService mediaNodeServerService = nodeServerServiceMap.get(mediaServer.getType());
|
||||||
|
if (mediaNodeServerService == null) {
|
||||||
|
logger.info("[startSendRtpStream] 失败, mediaServer的类型: {},未找到对应的实现类", mediaServer.getType());
|
||||||
|
throw new ControllerException(ErrorCode.ERROR100.getCode(), "未找到mediaServer对应的实现类");
|
||||||
|
}
|
||||||
|
logger.info("[开始推流] rtp/{}, 目标={}:{},SSRC={}, RTCP={}", sendRtpItem.getStream(),
|
||||||
|
sendRtpItem.getIp(), sendRtpItem.getPort(), sendRtpItem.getSsrc(), sendRtpItem.isRtcp());
|
||||||
|
mediaNodeServerService.startSendRtpStream(mediaServer, sendRtpItem);
|
||||||
|
if (platform != null) {
|
||||||
|
sendPlatformStartPlayMsg(platform, sendRtpItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendPlatformStartPlayMsg(ParentPlatform platform, SendRtpItem sendRtpItem) {
|
||||||
|
if (sendRtpItem.getPlayType() == InviteStreamType.PUSH && platform != null) {
|
||||||
|
MessageForPushChannel messageForPushChannel = MessageForPushChannel.getInstance(0, sendRtpItem.getApp(), sendRtpItem.getStream(),
|
||||||
|
sendRtpItem.getChannelId(), platform.getServerGBId(), platform.getName(), userSetting.getServerId(),
|
||||||
|
sendRtpItem.getMediaServerId());
|
||||||
|
messageForPushChannel.setPlatFormIndex(platform.getId());
|
||||||
|
redisCatchStorage.sendPlatformStartPlayMsg(messageForPushChannel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SendRtpItem createSendRtpItem(MediaServer mediaServer, String ip, int port, String ssrc, String requesterId, String deviceId, String channelId, boolean isTcp, boolean rtcp) {
|
||||||
|
int localPort = sendRtpPortManager.getNextPort(mediaServer);
|
||||||
|
if (localPort == 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
SendRtpItem sendRtpItem = new SendRtpItem();
|
||||||
|
sendRtpItem.setIp(ip);
|
||||||
|
sendRtpItem.setPort(port);
|
||||||
|
sendRtpItem.setSsrc(ssrc);
|
||||||
|
sendRtpItem.setPlatformId(deviceId);
|
||||||
|
sendRtpItem.setDeviceId(deviceId);
|
||||||
|
sendRtpItem.setChannelId(channelId);
|
||||||
|
sendRtpItem.setTcp(isTcp);
|
||||||
|
sendRtpItem.setRtcp(rtcp);
|
||||||
|
sendRtpItem.setApp("rtp");
|
||||||
|
sendRtpItem.setLocalPort(localPort);
|
||||||
|
sendRtpItem.setServerId(userSetting.getServerId());
|
||||||
|
sendRtpItem.setMediaServerId(mediaServer.getId());
|
||||||
|
return sendRtpItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SendRtpItem createSendRtpItem(MediaServer serverItem, String ip, int port, String ssrc, String platformId,
|
||||||
|
String app, String stream, String channelId, boolean tcp, boolean rtcp){
|
||||||
|
|
||||||
|
int localPort = sendRtpPortManager.getNextPort(serverItem);
|
||||||
|
if (localPort == 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
SendRtpItem sendRtpItem = new SendRtpItem();
|
||||||
|
sendRtpItem.setIp(ip);
|
||||||
|
sendRtpItem.setPort(port);
|
||||||
|
sendRtpItem.setSsrc(ssrc);
|
||||||
|
sendRtpItem.setApp(app);
|
||||||
|
sendRtpItem.setStream(stream);
|
||||||
|
sendRtpItem.setPlatformId(platformId);
|
||||||
|
sendRtpItem.setChannelId(channelId);
|
||||||
|
sendRtpItem.setTcp(tcp);
|
||||||
|
sendRtpItem.setLocalPort(localPort);
|
||||||
|
sendRtpItem.setServerId(userSetting.getServerId());
|
||||||
|
sendRtpItem.setMediaServerId(serverItem.getId());
|
||||||
|
sendRtpItem.setRtcp(rtcp);
|
||||||
|
return sendRtpItem;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -2,7 +2,7 @@ package com.genersoft.iot.vmp.media.zlm;
|
|||||||
|
|
||||||
import com.alibaba.fastjson2.JSON;
|
import com.alibaba.fastjson2.JSON;
|
||||||
import com.alibaba.fastjson2.JSONObject;
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
import com.genersoft.iot.vmp.media.bean.MediaServer;
|
||||||
import com.genersoft.iot.vmp.utils.SSLSocketClientUtil;
|
import com.genersoft.iot.vmp.utils.SSLSocketClientUtil;
|
||||||
import okhttp3.*;
|
import okhttp3.*;
|
||||||
import okhttp3.logging.HttpLoggingInterceptor;
|
import okhttp3.logging.HttpLoggingInterceptor;
|
||||||
@ -70,7 +70,7 @@ public class AssistRESTfulUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public JSONObject sendGet(MediaServerItem mediaServerItem, String api, Map<String, Object> param, RequestCallback callback) {
|
public JSONObject sendGet(MediaServer mediaServerItem, String api, Map<String, Object> param, RequestCallback callback) {
|
||||||
OkHttpClient client = getClient();
|
OkHttpClient client = getClient();
|
||||||
|
|
||||||
if (mediaServerItem == null) {
|
if (mediaServerItem == null) {
|
||||||
@ -155,7 +155,7 @@ public class AssistRESTfulUtils {
|
|||||||
return responseJSON;
|
return responseJSON;
|
||||||
}
|
}
|
||||||
|
|
||||||
public JSONObject sendPost(MediaServerItem mediaServerItem, String url,
|
public JSONObject sendPost(MediaServer mediaServerItem, String url,
|
||||||
JSONObject param, ZLMRESTfulUtils.RequestCallback callback,
|
JSONObject param, ZLMRESTfulUtils.RequestCallback callback,
|
||||||
Integer readTimeOut) {
|
Integer readTimeOut) {
|
||||||
OkHttpClient client = getClient(readTimeOut);
|
OkHttpClient client = getClient(readTimeOut);
|
||||||
@ -244,12 +244,12 @@ public class AssistRESTfulUtils {
|
|||||||
return responseJSON;
|
return responseJSON;
|
||||||
}
|
}
|
||||||
|
|
||||||
public JSONObject getInfo(MediaServerItem mediaServerItem, RequestCallback callback){
|
public JSONObject getInfo(MediaServer mediaServerItem, RequestCallback callback){
|
||||||
Map<String, Object> param = new HashMap<>();
|
Map<String, Object> param = new HashMap<>();
|
||||||
return sendGet(mediaServerItem, "api/record/info",param, callback);
|
return sendGet(mediaServerItem, "api/record/info",param, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
public JSONObject addTask(MediaServerItem mediaServerItem, String app, String stream, String startTime,
|
public JSONObject addTask(MediaServer mediaServerItem, String app, String stream, String startTime,
|
||||||
String endTime, String callId, List<String> filePathList, String remoteHost) {
|
String endTime, String callId, List<String> filePathList, String remoteHost) {
|
||||||
|
|
||||||
JSONObject videoTaskInfoJSON = new JSONObject();
|
JSONObject videoTaskInfoJSON = new JSONObject();
|
||||||
@ -266,7 +266,7 @@ public class AssistRESTfulUtils {
|
|||||||
return sendPost(mediaServerItem, urlStr, videoTaskInfoJSON, null, 30);
|
return sendPost(mediaServerItem, urlStr, videoTaskInfoJSON, null, 30);
|
||||||
}
|
}
|
||||||
|
|
||||||
public JSONObject queryTaskList(MediaServerItem mediaServerItem, String app, String stream, String callId,
|
public JSONObject queryTaskList(MediaServer mediaServerItem, String app, String stream, String callId,
|
||||||
String taskId, Boolean isEnd, String scheme) {
|
String taskId, Boolean isEnd, String scheme) {
|
||||||
Map<String, Object> param = new HashMap<>();
|
Map<String, Object> param = new HashMap<>();
|
||||||
if (!ObjectUtils.isEmpty(app)) {
|
if (!ObjectUtils.isEmpty(app)) {
|
||||||
|
|||||||
@ -3,7 +3,7 @@ package com.genersoft.iot.vmp.media.zlm;
|
|||||||
import com.genersoft.iot.vmp.common.VideoManagerConstants;
|
import com.genersoft.iot.vmp.common.VideoManagerConstants;
|
||||||
import com.genersoft.iot.vmp.conf.UserSetting;
|
import com.genersoft.iot.vmp.conf.UserSetting;
|
||||||
import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
|
import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
|
||||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
import com.genersoft.iot.vmp.media.bean.MediaServer;
|
||||||
import com.genersoft.iot.vmp.utils.redis.RedisUtil;
|
import com.genersoft.iot.vmp.utils.redis.RedisUtil;
|
||||||
import org.apache.commons.lang3.math.NumberUtils;
|
import org.apache.commons.lang3.math.NumberUtils;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
@ -30,7 +30,7 @@ public class SendRtpPortManager {
|
|||||||
|
|
||||||
private final String KEY = "VM_MEDIA_SEND_RTP_PORT_";
|
private final String KEY = "VM_MEDIA_SEND_RTP_PORT_";
|
||||||
|
|
||||||
public synchronized int getNextPort(MediaServerItem mediaServer) {
|
public synchronized int getNextPort(MediaServer mediaServer) {
|
||||||
if (mediaServer == null) {
|
if (mediaServer == null) {
|
||||||
logger.warn("[发送端口管理] 参数错误,mediaServer为NULL");
|
logger.warn("[发送端口管理] 参数错误,mediaServer为NULL");
|
||||||
return -1;
|
return -1;
|
||||||
@ -83,6 +83,7 @@ public class SendRtpPortManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private synchronized int getSendPort(int startPort, int endPort, String sendIndexKey, Map<Integer, SendRtpItem> sendRtpItemMap){
|
private synchronized int getSendPort(int startPort, int endPort, String sendIndexKey, Map<Integer, SendRtpItem> sendRtpItemMap){
|
||||||
|
// TODO 这里改为只取偶数端口
|
||||||
RedisAtomicInteger redisAtomicInteger = new RedisAtomicInteger(sendIndexKey , redisTemplate.getConnectionFactory());
|
RedisAtomicInteger redisAtomicInteger = new RedisAtomicInteger(sendIndexKey , redisTemplate.getConnectionFactory());
|
||||||
if (redisAtomicInteger.get() < startPort) {
|
if (redisAtomicInteger.get() < startPort) {
|
||||||
redisAtomicInteger.set(startPort);
|
redisAtomicInteger.set(startPort);
|
||||||
|
|||||||
@ -2,55 +2,40 @@ package com.genersoft.iot.vmp.media.zlm;
|
|||||||
|
|
||||||
import com.alibaba.fastjson2.JSON;
|
import com.alibaba.fastjson2.JSON;
|
||||||
import com.alibaba.fastjson2.JSONObject;
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
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.common.VideoManagerConstants;
|
|
||||||
import com.genersoft.iot.vmp.conf.UserSetting;
|
import com.genersoft.iot.vmp.conf.UserSetting;
|
||||||
import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException;
|
|
||||||
import com.genersoft.iot.vmp.gb28181.bean.*;
|
|
||||||
import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
|
import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
|
||||||
import com.genersoft.iot.vmp.gb28181.session.AudioBroadcastManager;
|
import com.genersoft.iot.vmp.gb28181.session.AudioBroadcastManager;
|
||||||
import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent;
|
|
||||||
import com.genersoft.iot.vmp.gb28181.session.SSRCFactory;
|
import com.genersoft.iot.vmp.gb28181.session.SSRCFactory;
|
||||||
import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
|
import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
|
||||||
import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
|
import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
|
||||||
import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
|
|
||||||
import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform;
|
import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform;
|
||||||
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
|
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
|
||||||
import com.genersoft.iot.vmp.media.zlm.dto.HookType;
|
import com.genersoft.iot.vmp.media.bean.ResultForOnPublish;
|
||||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
import com.genersoft.iot.vmp.media.event.hook.HookSubscribe;
|
||||||
import com.genersoft.iot.vmp.media.zlm.dto.StreamAuthorityInfo;
|
import com.genersoft.iot.vmp.media.event.media.*;
|
||||||
import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem;
|
import com.genersoft.iot.vmp.media.event.mediaServer.MediaSendRtpStoppedEvent;
|
||||||
|
import com.genersoft.iot.vmp.media.service.IMediaServerService;
|
||||||
|
import com.genersoft.iot.vmp.media.bean.MediaServer;
|
||||||
|
import com.genersoft.iot.vmp.media.zlm.dto.ZLMServerConfig;
|
||||||
import com.genersoft.iot.vmp.media.zlm.dto.hook.*;
|
import com.genersoft.iot.vmp.media.zlm.dto.hook.*;
|
||||||
|
import com.genersoft.iot.vmp.media.zlm.event.HookZlmServerKeepaliveEvent;
|
||||||
|
import com.genersoft.iot.vmp.media.zlm.event.HookZlmServerStartEvent;
|
||||||
import com.genersoft.iot.vmp.service.*;
|
import com.genersoft.iot.vmp.service.*;
|
||||||
import com.genersoft.iot.vmp.service.bean.MessageForPushChannel;
|
|
||||||
import com.genersoft.iot.vmp.service.bean.SSRCInfo;
|
|
||||||
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
|
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
|
||||||
import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
|
import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
|
||||||
import com.genersoft.iot.vmp.utils.DateUtil;
|
|
||||||
import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
|
|
||||||
import com.genersoft.iot.vmp.vmanager.bean.OtherPsSendInfo;
|
|
||||||
import com.genersoft.iot.vmp.vmanager.bean.OtherRtpSendInfo;
|
|
||||||
import com.genersoft.iot.vmp.vmanager.bean.StreamContent;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.beans.factory.annotation.Qualifier;
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
|
import org.springframework.context.ApplicationEventPublisher;
|
||||||
import org.springframework.data.redis.core.RedisTemplate;
|
import org.springframework.data.redis.core.RedisTemplate;
|
||||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
||||||
import org.springframework.util.ObjectUtils;
|
import org.springframework.util.ObjectUtils;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
import org.springframework.web.context.request.async.DeferredResult;
|
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.sip.InvalidArgumentException;
|
|
||||||
import javax.sip.SipException;
|
|
||||||
import java.text.ParseException;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description:针对 ZLMediaServer的hook事件监听
|
* @description:针对 ZLMediaServer的hook事件监听
|
||||||
@ -106,7 +91,7 @@ public class ZLMHttpHookListener {
|
|||||||
private ZLMMediaListManager zlmMediaListManager;
|
private ZLMMediaListManager zlmMediaListManager;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private ZlmHttpHookSubscribe subscribe;
|
private HookSubscribe subscribe;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private UserSetting userSetting;
|
private UserSetting userSetting;
|
||||||
@ -130,25 +115,25 @@ public class ZLMHttpHookListener {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private RedisTemplate<Object, Object> redisTemplate;
|
private RedisTemplate<Object, Object> redisTemplate;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ApplicationEventPublisher applicationEventPublisher;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 服务器定时上报时间,上报间隔可配置,默认10s上报一次
|
* 服务器定时上报时间,上报间隔可配置,默认10s上报一次
|
||||||
*/
|
*/
|
||||||
@ResponseBody
|
@ResponseBody
|
||||||
|
|
||||||
@PostMapping(value = "/on_server_keepalive", produces = "application/json;charset=UTF-8")
|
@PostMapping(value = "/on_server_keepalive", produces = "application/json;charset=UTF-8")
|
||||||
public HookResult onServerKeepalive(@RequestBody OnServerKeepaliveHookParam param) {
|
public HookResult onServerKeepalive(@RequestBody OnServerKeepaliveHookParam param) {
|
||||||
|
try {
|
||||||
|
HookZlmServerKeepaliveEvent event = new HookZlmServerKeepaliveEvent(this);
|
||||||
taskExecutor.execute(() -> {
|
MediaServer mediaServerItem = mediaServerService.getOne(param.getMediaServerId());
|
||||||
List<ZlmHttpHookSubscribe.Event> subscribes = this.subscribe.getSubscribes(HookType.on_server_keepalive);
|
if (mediaServerItem != null) {
|
||||||
if (subscribes != null && !subscribes.isEmpty()) {
|
event.setMediaServerItem(mediaServerItem);
|
||||||
for (ZlmHttpHookSubscribe.Event subscribe : subscribes) {
|
applicationEventPublisher.publishEvent(event);
|
||||||
subscribe.response(null, param);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
}catch (Exception e) {
|
||||||
mediaServerService.updateMediaServerKeepalive(param.getMediaServerId(), param.getData());
|
logger.info("[ZLM-HOOK-心跳] 发送通知失败 ", e);
|
||||||
|
}
|
||||||
return HookResult.SUCCESS();
|
return HookResult.SUCCESS();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -156,32 +141,17 @@ public class ZLMHttpHookListener {
|
|||||||
* 播放器鉴权事件,rtsp/rtmp/http-flv/ws-flv/hls的播放都将触发此鉴权事件。
|
* 播放器鉴权事件,rtsp/rtmp/http-flv/ws-flv/hls的播放都将触发此鉴权事件。
|
||||||
*/
|
*/
|
||||||
@ResponseBody
|
@ResponseBody
|
||||||
|
|
||||||
@PostMapping(value = "/on_play", produces = "application/json;charset=UTF-8")
|
@PostMapping(value = "/on_play", produces = "application/json;charset=UTF-8")
|
||||||
public HookResult onPlay(@RequestBody OnPlayHookParam param) {
|
public HookResult onPlay(@RequestBody OnPlayHookParam param) {
|
||||||
if (logger.isDebugEnabled()) {
|
|
||||||
logger.debug("[ZLM HOOK] 播放鉴权:{}->{}", param.getMediaServerId(), param);
|
|
||||||
}
|
|
||||||
String mediaServerId = param.getMediaServerId();
|
|
||||||
|
|
||||||
taskExecutor.execute(() -> {
|
Map<String, String> paramMap = urlParamToMap(param.getParams());
|
||||||
JSONObject json = (JSONObject) JSON.toJSON(param);
|
// 对于播放流进行鉴权
|
||||||
ZlmHttpHookSubscribe.Event subscribe = this.subscribe.sendNotify(HookType.on_play, json);
|
boolean authenticateResult = mediaService.authenticatePlay(param.getApp(), param.getStream(), paramMap.get("callId"));
|
||||||
if (subscribe != null) {
|
if (!authenticateResult) {
|
||||||
MediaServerItem mediaInfo = mediaServerService.getOne(mediaServerId);
|
logger.info("[ZLM HOOK] 播放鉴权 失败:{}->{}", param.getMediaServerId(), param);
|
||||||
if (mediaInfo != null) {
|
return new HookResult(401, "Unauthorized");
|
||||||
subscribe.response(mediaInfo, param);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if (!"rtp".equals(param.getApp())) {
|
|
||||||
Map<String, String> paramMap = urlParamToMap(param.getParams());
|
|
||||||
StreamAuthorityInfo streamAuthorityInfo = redisCatchStorage.getStreamAuthorityInfo(param.getApp(), param.getStream());
|
|
||||||
if (streamAuthorityInfo != null && streamAuthorityInfo.getCallId() != null && !streamAuthorityInfo.getCallId().equals(paramMap.get("callId"))) {
|
|
||||||
return new HookResult(401, "Unauthorized");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
logger.info("[ZLM HOOK] 播放鉴权成功:{}->{}", param.getMediaServerId(), param);
|
||||||
return HookResult.SUCCESS();
|
return HookResult.SUCCESS();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -195,136 +165,24 @@ public class ZLMHttpHookListener {
|
|||||||
JSONObject json = (JSONObject) JSON.toJSON(param);
|
JSONObject json = (JSONObject) JSON.toJSON(param);
|
||||||
|
|
||||||
logger.info("[ZLM HOOK]推流鉴权:{}->{}", param.getMediaServerId(), param);
|
logger.info("[ZLM HOOK]推流鉴权:{}->{}", param.getMediaServerId(), param);
|
||||||
|
// TODO 加快处理速度
|
||||||
|
|
||||||
String mediaServerId = json.getString("mediaServerId");
|
String mediaServerId = json.getString("mediaServerId");
|
||||||
MediaServerItem mediaInfo = mediaServerService.getOne(mediaServerId);
|
MediaServer mediaServer = mediaServerService.getOne(mediaServerId);
|
||||||
if (mediaInfo == null) {
|
if (mediaServer == null) {
|
||||||
return new HookResultForOnPublish(200, "success");
|
return new HookResultForOnPublish(0, "success");
|
||||||
}
|
|
||||||
// 推流鉴权的处理
|
|
||||||
if (!"rtp".equals(param.getApp())) {
|
|
||||||
StreamProxyItem stream = streamProxyService.getStreamProxyByAppAndStream(param.getApp(), param.getStream());
|
|
||||||
if (stream != null) {
|
|
||||||
HookResultForOnPublish result = HookResultForOnPublish.SUCCESS();
|
|
||||||
result.setEnable_audio(stream.isEnableAudio());
|
|
||||||
result.setEnable_mp4(stream.isEnableMp4());
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
if (userSetting.getPushAuthority()) {
|
|
||||||
// 推流鉴权
|
|
||||||
if (param.getParams() == null) {
|
|
||||||
logger.info("推流鉴权失败: 缺少必要参数:sign=md5(user表的pushKey)");
|
|
||||||
return new HookResultForOnPublish(401, "Unauthorized");
|
|
||||||
}
|
|
||||||
Map<String, String> paramMap = urlParamToMap(param.getParams());
|
|
||||||
String sign = paramMap.get("sign");
|
|
||||||
if (sign == null) {
|
|
||||||
logger.info("推流鉴权失败: 缺少必要参数:sign=md5(user表的pushKey)");
|
|
||||||
return new HookResultForOnPublish(401, "Unauthorized");
|
|
||||||
}
|
|
||||||
// 推流自定义播放鉴权码
|
|
||||||
String callId = paramMap.get("callId");
|
|
||||||
// 鉴权配置
|
|
||||||
boolean hasAuthority = userService.checkPushAuthority(callId, sign);
|
|
||||||
if (!hasAuthority) {
|
|
||||||
logger.info("推流鉴权失败: sign 无权限: callId={}. sign={}", callId, sign);
|
|
||||||
return new HookResultForOnPublish(401, "Unauthorized");
|
|
||||||
}
|
|
||||||
StreamAuthorityInfo streamAuthorityInfo = StreamAuthorityInfo.getInstanceByHook(param);
|
|
||||||
streamAuthorityInfo.setCallId(callId);
|
|
||||||
streamAuthorityInfo.setSign(sign);
|
|
||||||
// 鉴权通过
|
|
||||||
redisCatchStorage.updateStreamAuthorityInfo(param.getApp(), param.getStream(), streamAuthorityInfo);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
zlmMediaListManager.sendStreamEvent(param.getApp(), param.getStream(), param.getMediaServerId());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ResultForOnPublish resultForOnPublish = mediaService.authenticatePublish(mediaServer, param.getApp(), param.getStream(), param.getParams());
|
||||||
HookResultForOnPublish result = HookResultForOnPublish.SUCCESS();
|
if (resultForOnPublish != null) {
|
||||||
result.setEnable_audio(true);
|
HookResultForOnPublish successResult = HookResultForOnPublish.getInstance(resultForOnPublish);
|
||||||
taskExecutor.execute(() -> {
|
logger.info("[ZLM HOOK]推流鉴权 响应:{}->{}->>>>{}", param.getMediaServerId(), param, successResult);
|
||||||
ZlmHttpHookSubscribe.Event subscribe = this.subscribe.sendNotify(HookType.on_publish, json);
|
return successResult;
|
||||||
if (subscribe != null) {
|
}else {
|
||||||
subscribe.response(mediaInfo, param);
|
HookResultForOnPublish fail = HookResultForOnPublish.Fail();
|
||||||
}
|
logger.info("[ZLM HOOK]推流鉴权 响应:{}->{}->>>>{}", param.getMediaServerId(), param, fail);
|
||||||
});
|
return fail;
|
||||||
|
|
||||||
// 是否录像
|
|
||||||
if ("rtp".equals(param.getApp())) {
|
|
||||||
result.setEnable_mp4(userSetting.getRecordSip());
|
|
||||||
} else {
|
|
||||||
result.setEnable_mp4(userSetting.isRecordPushLive());
|
|
||||||
}
|
}
|
||||||
// 国标流
|
|
||||||
if ("rtp".equals(param.getApp())) {
|
|
||||||
|
|
||||||
InviteInfo inviteInfo = inviteStreamService.getInviteInfoByStream(null, param.getStream());
|
|
||||||
|
|
||||||
// 单端口模式下修改流 ID
|
|
||||||
if (!mediaInfo.isRtpEnable() && inviteInfo == null) {
|
|
||||||
String ssrc = String.format("%010d", Long.parseLong(param.getStream(), 16));
|
|
||||||
inviteInfo = inviteStreamService.getInviteInfoBySSRC(ssrc);
|
|
||||||
if (inviteInfo != null) {
|
|
||||||
result.setStream_replace(inviteInfo.getStream());
|
|
||||||
logger.info("[ZLM HOOK]推流鉴权 stream: {} 替换为 {}", param.getStream(), inviteInfo.getStream());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 设置音频信息及录制信息
|
|
||||||
List<SsrcTransaction> ssrcTransactionForAll = sessionManager.getSsrcTransactionForAll(null, null, null, param.getStream());
|
|
||||||
if (ssrcTransactionForAll != null && ssrcTransactionForAll.size() == 1) {
|
|
||||||
|
|
||||||
// 为录制国标模拟一个鉴权信息, 方便后续写入录像文件时使用
|
|
||||||
StreamAuthorityInfo streamAuthorityInfo = StreamAuthorityInfo.getInstanceByHook(param);
|
|
||||||
streamAuthorityInfo.setApp(param.getApp());
|
|
||||||
streamAuthorityInfo.setStream(ssrcTransactionForAll.get(0).getStream());
|
|
||||||
streamAuthorityInfo.setCallId(ssrcTransactionForAll.get(0).getSipTransactionInfo().getCallId());
|
|
||||||
|
|
||||||
redisCatchStorage.updateStreamAuthorityInfo(param.getApp(), ssrcTransactionForAll.get(0).getStream(), streamAuthorityInfo);
|
|
||||||
|
|
||||||
String deviceId = ssrcTransactionForAll.get(0).getDeviceId();
|
|
||||||
String channelId = ssrcTransactionForAll.get(0).getChannelId();
|
|
||||||
DeviceChannel deviceChannel = storager.queryChannel(deviceId, channelId);
|
|
||||||
if (deviceChannel != null) {
|
|
||||||
result.setEnable_audio(deviceChannel.isHasAudio());
|
|
||||||
}
|
|
||||||
// 如果是录像下载就设置视频间隔十秒
|
|
||||||
if (ssrcTransactionForAll.get(0).getType() == InviteSessionType.DOWNLOAD) {
|
|
||||||
// 获取录像的总时长,然后设置为这个视频的时长
|
|
||||||
InviteInfo inviteInfoForDownload = inviteStreamService.getInviteInfo(InviteSessionType.DOWNLOAD, deviceId, channelId, param.getStream());
|
|
||||||
if (inviteInfoForDownload != null && inviteInfoForDownload.getStreamInfo() != null) {
|
|
||||||
String startTime = inviteInfoForDownload.getStreamInfo().getStartTime();
|
|
||||||
String endTime = inviteInfoForDownload.getStreamInfo().getEndTime();
|
|
||||||
long difference = DateUtil.getDifference(startTime, endTime) / 1000;
|
|
||||||
result.setMp4_max_second((int) difference);
|
|
||||||
result.setEnable_mp4(true);
|
|
||||||
// 设置为2保证得到的mp4的时长是正常的
|
|
||||||
result.setModify_stamp(2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 如果是talk对讲,则默认获取声音
|
|
||||||
if (ssrcTransactionForAll.get(0).getType() == InviteSessionType.TALK) {
|
|
||||||
result.setEnable_audio(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (param.getApp().equals("broadcast")) {
|
|
||||||
result.setEnable_audio(true);
|
|
||||||
} else if (param.getApp().equals("talk")) {
|
|
||||||
result.setEnable_audio(true);
|
|
||||||
}
|
|
||||||
if (param.getApp().equalsIgnoreCase("rtp")) {
|
|
||||||
String receiveKey = VideoManagerConstants.WVP_OTHER_RECEIVE_RTP_INFO + userSetting.getServerId() + "_" + param.getStream();
|
|
||||||
OtherRtpSendInfo otherRtpSendInfo = (OtherRtpSendInfo) redisTemplate.opsForValue().get(receiveKey);
|
|
||||||
|
|
||||||
String receiveKeyForPS = VideoManagerConstants.WVP_OTHER_RECEIVE_PS_INFO + userSetting.getServerId() + "_" + param.getStream();
|
|
||||||
OtherPsSendInfo otherPsSendInfo = (OtherPsSendInfo) redisTemplate.opsForValue().get(receiveKeyForPS);
|
|
||||||
if (otherRtpSendInfo != null || otherPsSendInfo != null) {
|
|
||||||
result.setEnable_mp4(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
logger.info("[ZLM HOOK]推流鉴权 响应:{}->{}->>>>{}", param.getMediaServerId(), param, result);
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -335,226 +193,20 @@ public class ZLMHttpHookListener {
|
|||||||
@PostMapping(value = "/on_stream_changed", produces = "application/json;charset=UTF-8")
|
@PostMapping(value = "/on_stream_changed", produces = "application/json;charset=UTF-8")
|
||||||
public HookResult onStreamChanged(@RequestBody OnStreamChangedHookParam param) {
|
public HookResult onStreamChanged(@RequestBody OnStreamChangedHookParam param) {
|
||||||
|
|
||||||
if (param.isRegist()) {
|
MediaServer mediaServer = mediaServerService.getOne(param.getMediaServerId());
|
||||||
logger.info("[ZLM HOOK] 流注册, {}->{}->{}/{}", param.getMediaServerId(), param.getSchema(), param.getApp(), param.getStream());
|
if (mediaServer == null) {
|
||||||
} else {
|
return HookResult.SUCCESS();
|
||||||
logger.info("[ZLM HOOK] 流注销, {}->{}->{}/{}", param.getMediaServerId(), param.getSchema(), param.getApp(), param.getStream());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
JSONObject json = (JSONObject) JSON.toJSON(param);
|
if (param.isRegist()) {
|
||||||
taskExecutor.execute(() -> {
|
logger.info("[ZLM HOOK] 流注册, {}->{}->{}/{}", param.getMediaServerId(), param.getSchema(), param.getApp(), param.getStream());
|
||||||
ZlmHttpHookSubscribe.Event subscribe = this.subscribe.sendNotify(HookType.on_stream_changed, json);
|
MediaArrivalEvent mediaArrivalEvent = MediaArrivalEvent.getInstance(this, param, mediaServer);
|
||||||
MediaServerItem mediaInfo = mediaServerService.getOne(param.getMediaServerId());
|
applicationEventPublisher.publishEvent(mediaArrivalEvent);
|
||||||
if (mediaInfo == null) {
|
} else {
|
||||||
logger.info("[ZLM HOOK] 流变化未找到ZLM, {}", param.getMediaServerId());
|
logger.info("[ZLM HOOK] 流注销, {}->{}->{}/{}", param.getMediaServerId(), param.getSchema(), param.getApp(), param.getStream());
|
||||||
return;
|
MediaDepartureEvent mediaDepartureEvent = MediaDepartureEvent.getInstance(this, param, mediaServer);
|
||||||
}
|
applicationEventPublisher.publishEvent(mediaDepartureEvent);
|
||||||
if (subscribe != null) {
|
}
|
||||||
subscribe.response(mediaInfo, param);
|
|
||||||
}
|
|
||||||
|
|
||||||
List<OnStreamChangedHookParam.MediaTrack> tracks = param.getTracks();
|
|
||||||
// TODO 重构此处逻辑
|
|
||||||
if (param.isRegist()) {
|
|
||||||
// 处理流注册的鉴权信息, 流注销这里不再删除鉴权信息,下次来了新的鉴权信息会对就的进行覆盖
|
|
||||||
if (param.getOriginType() == OriginType.RTMP_PUSH.ordinal()
|
|
||||||
|| param.getOriginType() == OriginType.RTSP_PUSH.ordinal()
|
|
||||||
|| param.getOriginType() == OriginType.RTC_PUSH.ordinal()) {
|
|
||||||
StreamAuthorityInfo streamAuthorityInfo = redisCatchStorage.getStreamAuthorityInfo(param.getApp(), param.getStream());
|
|
||||||
if (streamAuthorityInfo == null) {
|
|
||||||
streamAuthorityInfo = StreamAuthorityInfo.getInstanceByHook(param);
|
|
||||||
} else {
|
|
||||||
streamAuthorityInfo.setOriginType(param.getOriginType());
|
|
||||||
streamAuthorityInfo.setOriginTypeStr(param.getOriginTypeStr());
|
|
||||||
}
|
|
||||||
redisCatchStorage.updateStreamAuthorityInfo(param.getApp(), param.getStream(), streamAuthorityInfo);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ("rtsp".equals(param.getSchema())) {
|
|
||||||
logger.info("流变化:注册->{}, app->{}, stream->{}", param.isRegist(), param.getApp(), param.getStream());
|
|
||||||
if (param.isRegist()) {
|
|
||||||
mediaServerService.addCount(param.getMediaServerId());
|
|
||||||
} else {
|
|
||||||
mediaServerService.removeCount(param.getMediaServerId());
|
|
||||||
}
|
|
||||||
|
|
||||||
int updateStatusResult = streamProxyService.updateStatus(param.isRegist(), param.getApp(), param.getStream());
|
|
||||||
if (updateStatusResult > 0) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if ("rtp".equals(param.getApp()) && !param.isRegist()) {
|
|
||||||
InviteInfo inviteInfo = inviteStreamService.getInviteInfoByStream(null, param.getStream());
|
|
||||||
if (inviteInfo != null && (inviteInfo.getType() == InviteSessionType.PLAY || inviteInfo.getType() == InviteSessionType.PLAYBACK)) {
|
|
||||||
inviteStreamService.removeInviteInfo(inviteInfo);
|
|
||||||
storager.stopPlay(inviteInfo.getDeviceId(), inviteInfo.getChannelId());
|
|
||||||
}
|
|
||||||
} else if ("broadcast".equals(param.getApp())) {
|
|
||||||
// 语音对讲推流 stream需要满足格式deviceId_channelId
|
|
||||||
if (param.getStream().indexOf("_") > 0) {
|
|
||||||
String[] streamArray = param.getStream().split("_");
|
|
||||||
if (streamArray.length == 2) {
|
|
||||||
String deviceId = streamArray[0];
|
|
||||||
String channelId = streamArray[1];
|
|
||||||
Device device = deviceService.getDevice(deviceId);
|
|
||||||
if (device != null) {
|
|
||||||
if (param.isRegist()) {
|
|
||||||
if (audioBroadcastManager.exit(deviceId, channelId)) {
|
|
||||||
playService.stopAudioBroadcast(deviceId, channelId);
|
|
||||||
}
|
|
||||||
// 开启语音对讲通道
|
|
||||||
try {
|
|
||||||
playService.audioBroadcastCmd(device, channelId, mediaInfo, param.getApp(), param.getStream(), 60, false, (msg) -> {
|
|
||||||
logger.info("[语音对讲] 通道建立成功, device: {}, channel: {}", deviceId, channelId);
|
|
||||||
});
|
|
||||||
} catch (InvalidArgumentException | ParseException | SipException e) {
|
|
||||||
logger.error("[命令发送失败] 语音对讲: {}", e.getMessage());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// 流注销
|
|
||||||
playService.stopAudioBroadcast(deviceId, channelId);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
logger.info("[语音对讲] 未找到设备:{}", deviceId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if ("talk".equals(param.getApp())) {
|
|
||||||
// 语音对讲推流 stream需要满足格式deviceId_channelId
|
|
||||||
if (param.getStream().indexOf("_") > 0) {
|
|
||||||
String[] streamArray = param.getStream().split("_");
|
|
||||||
if (streamArray.length == 2) {
|
|
||||||
String deviceId = streamArray[0];
|
|
||||||
String channelId = streamArray[1];
|
|
||||||
Device device = deviceService.getDevice(deviceId);
|
|
||||||
if (device != null) {
|
|
||||||
if (param.isRegist()) {
|
|
||||||
if (audioBroadcastManager.exit(deviceId, channelId)) {
|
|
||||||
playService.stopAudioBroadcast(deviceId, channelId);
|
|
||||||
}
|
|
||||||
// 开启语音对讲通道
|
|
||||||
playService.talkCmd(device, channelId, mediaInfo, param.getStream(), (msg) -> {
|
|
||||||
logger.info("[语音对讲] 通道建立成功, device: {}, channel: {}", deviceId, channelId);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
// 流注销
|
|
||||||
playService.stopTalk(device, channelId, param.isRegist());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
logger.info("[语音对讲] 未找到设备:{}", deviceId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
if (!"rtp".equals(param.getApp())) {
|
|
||||||
String type = OriginType.values()[param.getOriginType()].getType();
|
|
||||||
if (param.isRegist()) {
|
|
||||||
StreamAuthorityInfo streamAuthorityInfo = redisCatchStorage.getStreamAuthorityInfo(
|
|
||||||
param.getApp(), param.getStream());
|
|
||||||
String callId = null;
|
|
||||||
if (streamAuthorityInfo != null) {
|
|
||||||
callId = streamAuthorityInfo.getCallId();
|
|
||||||
}
|
|
||||||
StreamInfo streamInfoByAppAndStream = mediaService.getStreamInfoByAppAndStream(mediaInfo,
|
|
||||||
param.getApp(), param.getStream(), tracks, callId);
|
|
||||||
param.setStreamInfo(new StreamContent(streamInfoByAppAndStream));
|
|
||||||
redisCatchStorage.addStream(mediaInfo, type, param.getApp(), param.getStream(), param);
|
|
||||||
if (param.getOriginType() == OriginType.RTSP_PUSH.ordinal()
|
|
||||||
|| param.getOriginType() == OriginType.RTMP_PUSH.ordinal()
|
|
||||||
|| param.getOriginType() == OriginType.RTC_PUSH.ordinal()) {
|
|
||||||
param.setSeverId(userSetting.getServerId());
|
|
||||||
zlmMediaListManager.addPush(param);
|
|
||||||
|
|
||||||
// 冗余数据,自己系统中自用
|
|
||||||
redisCatchStorage.addPushListItem(param.getApp(), param.getStream(), param);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// 兼容流注销时类型从redis记录获取
|
|
||||||
OnStreamChangedHookParam onStreamChangedHookParam = redisCatchStorage.getStreamInfo(
|
|
||||||
param.getApp(), param.getStream(), param.getMediaServerId());
|
|
||||||
if (onStreamChangedHookParam != null) {
|
|
||||||
type = OriginType.values()[onStreamChangedHookParam.getOriginType()].getType();
|
|
||||||
redisCatchStorage.removeStream(mediaInfo.getId(), type, param.getApp(), param.getStream());
|
|
||||||
if ("PUSH".equalsIgnoreCase(type)) {
|
|
||||||
// 冗余数据,自己系统中自用
|
|
||||||
redisCatchStorage.removePushListItem(param.getApp(), param.getStream(), param.getMediaServerId());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
GbStream gbStream = storager.getGbStream(param.getApp(), param.getStream());
|
|
||||||
if (gbStream != null) {
|
|
||||||
// eventPublisher.catalogEventPublishForStream(null, gbStream, CatalogEvent.OFF);
|
|
||||||
}
|
|
||||||
zlmMediaListManager.removeMedia(param.getApp(), param.getStream());
|
|
||||||
}
|
|
||||||
GbStream gbStream = storager.getGbStream(param.getApp(), param.getStream());
|
|
||||||
if (gbStream != null) {
|
|
||||||
if (userSetting.isUsePushingAsStatus()) {
|
|
||||||
eventPublisher.catalogEventPublishForStream(null, gbStream, param.isRegist() ? CatalogEvent.ON : CatalogEvent.OFF);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (type != null) {
|
|
||||||
// 发送流变化redis消息
|
|
||||||
JSONObject jsonObject = new JSONObject();
|
|
||||||
jsonObject.put("serverId", userSetting.getServerId());
|
|
||||||
jsonObject.put("app", param.getApp());
|
|
||||||
jsonObject.put("stream", param.getStream());
|
|
||||||
jsonObject.put("register", param.isRegist());
|
|
||||||
jsonObject.put("mediaServerId", param.getMediaServerId());
|
|
||||||
redisCatchStorage.sendStreamChangeMsg(type, jsonObject);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!param.isRegist()) {
|
|
||||||
List<SendRtpItem> sendRtpItems = redisCatchStorage.querySendRTPServerByStream(param.getStream());
|
|
||||||
if (!sendRtpItems.isEmpty()) {
|
|
||||||
for (SendRtpItem sendRtpItem : sendRtpItems) {
|
|
||||||
if (sendRtpItem == null) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sendRtpItem.getApp().equals(param.getApp())) {
|
|
||||||
logger.info(sendRtpItem.toString());
|
|
||||||
if (userSetting.getServerId().equals(sendRtpItem.getServerId())) {
|
|
||||||
MessageForPushChannel messageForPushChannel = MessageForPushChannel.getInstance(0,
|
|
||||||
sendRtpItem.getApp(), sendRtpItem.getStream(), sendRtpItem.getChannelId(),
|
|
||||||
sendRtpItem.getPlatformId(), null, userSetting.getServerId(), param.getMediaServerId());
|
|
||||||
// 通知其他wvp停止发流
|
|
||||||
redisCatchStorage.sendPushStreamClose(messageForPushChannel);
|
|
||||||
}else {
|
|
||||||
String platformId = sendRtpItem.getPlatformId();
|
|
||||||
ParentPlatform platform = storager.queryParentPlatByServerGBId(platformId);
|
|
||||||
Device device = deviceService.getDevice(platformId);
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (platform != null) {
|
|
||||||
commanderFroPlatform.streamByeCmd(platform, sendRtpItem);
|
|
||||||
redisCatchStorage.deleteSendRTPServer(platformId, sendRtpItem.getChannelId(),
|
|
||||||
sendRtpItem.getCallId(), sendRtpItem.getStream());
|
|
||||||
} else {
|
|
||||||
cmder.streamByeCmd(device, sendRtpItem.getChannelId(), param.getStream(), sendRtpItem.getCallId());
|
|
||||||
if (sendRtpItem.getPlayType().equals(InviteStreamType.BROADCAST)
|
|
||||||
|| sendRtpItem.getPlayType().equals(InviteStreamType.TALK)) {
|
|
||||||
AudioBroadcastCatch audioBroadcastCatch = audioBroadcastManager.get(sendRtpItem.getDeviceId(), sendRtpItem.getChannelId());
|
|
||||||
if (audioBroadcastCatch != null) {
|
|
||||||
// 来自上级平台的停止对讲
|
|
||||||
logger.info("[停止对讲] 来自上级,平台:{}, 通道:{}", sendRtpItem.getDeviceId(), sendRtpItem.getChannelId());
|
|
||||||
audioBroadcastManager.del(sendRtpItem.getDeviceId(), sendRtpItem.getChannelId());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (SipException | InvalidArgumentException | ParseException |
|
|
||||||
SsrcTransactionNotFoundException e) {
|
|
||||||
logger.error("[命令发送失败] 发送BYE: {}", e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return HookResult.SUCCESS();
|
return HookResult.SUCCESS();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -568,104 +220,9 @@ public class ZLMHttpHookListener {
|
|||||||
logger.info("[ZLM HOOK]流无人观看:{}->{}->{}/{}", param.getMediaServerId(), param.getSchema(),
|
logger.info("[ZLM HOOK]流无人观看:{}->{}->{}/{}", param.getMediaServerId(), param.getSchema(),
|
||||||
param.getApp(), param.getStream());
|
param.getApp(), param.getStream());
|
||||||
JSONObject ret = new JSONObject();
|
JSONObject ret = new JSONObject();
|
||||||
ret.put("code", 0);
|
|
||||||
// 国标类型的流
|
|
||||||
if ("rtp".equals(param.getApp())) {
|
|
||||||
ret.put("close", userSetting.getStreamOnDemand());
|
|
||||||
// 国标流, 点播/录像回放/录像下载
|
|
||||||
InviteInfo inviteInfo = inviteStreamService.getInviteInfoByStream(null, param.getStream());
|
|
||||||
// 点播
|
|
||||||
if (inviteInfo != null) {
|
|
||||||
// 录像下载
|
|
||||||
if (inviteInfo.getType() == InviteSessionType.DOWNLOAD) {
|
|
||||||
ret.put("close", false);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
// 收到无人观看说明流也没有在往上级推送
|
|
||||||
if (redisCatchStorage.isChannelSendingRTP(inviteInfo.getChannelId())) {
|
|
||||||
List<SendRtpItem> sendRtpItems = redisCatchStorage.querySendRTPServerByChannelId(
|
|
||||||
inviteInfo.getChannelId());
|
|
||||||
if (!sendRtpItems.isEmpty()) {
|
|
||||||
for (SendRtpItem sendRtpItem : sendRtpItems) {
|
|
||||||
ParentPlatform parentPlatform = storager.queryParentPlatByServerGBId(sendRtpItem.getPlatformId());
|
|
||||||
try {
|
|
||||||
commanderFroPlatform.streamByeCmd(parentPlatform, sendRtpItem.getCallId());
|
|
||||||
} catch (SipException | InvalidArgumentException | ParseException e) {
|
|
||||||
logger.error("[命令发送失败] 国标级联 发送BYE: {}", e.getMessage());
|
|
||||||
}
|
|
||||||
redisCatchStorage.deleteSendRTPServer(parentPlatform.getServerGBId(), sendRtpItem.getChannelId(),
|
|
||||||
sendRtpItem.getCallId(), sendRtpItem.getStream());
|
|
||||||
if (InviteStreamType.PUSH == sendRtpItem.getPlayType()) {
|
|
||||||
MessageForPushChannel messageForPushChannel = MessageForPushChannel.getInstance(0,
|
|
||||||
sendRtpItem.getApp(), sendRtpItem.getStream(), sendRtpItem.getChannelId(),
|
|
||||||
sendRtpItem.getPlatformId(), parentPlatform.getName(), userSetting.getServerId(), sendRtpItem.getMediaServerId());
|
|
||||||
messageForPushChannel.setPlatFormIndex(parentPlatform.getId());
|
|
||||||
redisCatchStorage.sendPlatformStopPlayMsg(messageForPushChannel);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Device device = deviceService.getDevice(inviteInfo.getDeviceId());
|
|
||||||
if (device != null) {
|
|
||||||
try {
|
|
||||||
// 多查询一次防止已经被处理了
|
|
||||||
InviteInfo info = inviteStreamService.getInviteInfo(inviteInfo.getType(),
|
|
||||||
inviteInfo.getDeviceId(), inviteInfo.getChannelId(), inviteInfo.getStream());
|
|
||||||
if (info != null) {
|
|
||||||
cmder.streamByeCmd(device, inviteInfo.getChannelId(),
|
|
||||||
inviteInfo.getStream(), null);
|
|
||||||
} else {
|
|
||||||
logger.info("[无人观看] 未找到设备的点播信息: {}, 流:{}", inviteInfo.getDeviceId(), param.getStream());
|
|
||||||
}
|
|
||||||
} catch (InvalidArgumentException | ParseException | SipException |
|
|
||||||
SsrcTransactionNotFoundException e) {
|
|
||||||
logger.error("[无人观看]点播, 发送BYE失败 {}", e.getMessage());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
logger.info("[无人观看] 未找到设备: {},流:{}", inviteInfo.getDeviceId(), param.getStream());
|
|
||||||
}
|
|
||||||
|
|
||||||
inviteStreamService.removeInviteInfo(inviteInfo.getType(), inviteInfo.getDeviceId(),
|
boolean close = mediaService.closeStreamOnNoneReader(param.getMediaServerId(), param.getApp(), param.getStream(), param.getSchema());
|
||||||
inviteInfo.getChannelId(), inviteInfo.getStream());
|
ret.put("code", close);
|
||||||
storager.stopPlay(inviteInfo.getDeviceId(), inviteInfo.getChannelId());
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(null, null, param.getStream(), null);
|
|
||||||
if (sendRtpItem != null && "talk".equals(sendRtpItem.getApp())) {
|
|
||||||
ret.put("close", false);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
} else if ("talk".equals(param.getApp()) || "broadcast".equals(param.getApp())) {
|
|
||||||
ret.put("close", false);
|
|
||||||
} else {
|
|
||||||
// 非国标流 推流/拉流代理
|
|
||||||
// 拉流代理
|
|
||||||
StreamProxyItem streamProxyItem = streamProxyService.getStreamProxyByAppAndStream(param.getApp(), param.getStream());
|
|
||||||
if (streamProxyItem != null) {
|
|
||||||
if (streamProxyItem.isEnableRemoveNoneReader()) {
|
|
||||||
// 无人观看自动移除
|
|
||||||
ret.put("close", true);
|
|
||||||
streamProxyService.del(param.getApp(), param.getStream());
|
|
||||||
String url = streamProxyItem.getUrl() != null ? streamProxyItem.getUrl() : streamProxyItem.getSrcUrl();
|
|
||||||
logger.info("[{}/{}]<-[{}] 拉流代理无人观看已经移除", param.getApp(), param.getStream(), url);
|
|
||||||
} else if (streamProxyItem.isEnableDisableNoneReader()) {
|
|
||||||
// 无人观看停用
|
|
||||||
ret.put("close", true);
|
|
||||||
// 修改数据
|
|
||||||
streamProxyService.stop(param.getApp(), param.getStream());
|
|
||||||
} else {
|
|
||||||
// 无人观看不做处理
|
|
||||||
ret.put("close", false);
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
// TODO 推流具有主动性,暂时不做处理
|
|
||||||
// StreamPushItem streamPushItem = streamPushService.getPush(app, streamId);
|
|
||||||
// if (streamPushItem != null) {
|
|
||||||
// // TODO 发送停止
|
|
||||||
//
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -674,119 +231,17 @@ public class ZLMHttpHookListener {
|
|||||||
*/
|
*/
|
||||||
@ResponseBody
|
@ResponseBody
|
||||||
@PostMapping(value = "/on_stream_not_found", produces = "application/json;charset=UTF-8")
|
@PostMapping(value = "/on_stream_not_found", produces = "application/json;charset=UTF-8")
|
||||||
public DeferredResult<HookResult> onStreamNotFound(@RequestBody OnStreamNotFoundHookParam param) {
|
public HookResult onStreamNotFound(@RequestBody OnStreamNotFoundHookParam param) {
|
||||||
logger.info("[ZLM HOOK] 流未找到:{}->{}->{}/{}", param.getMediaServerId(), param.getSchema(), param.getApp(), param.getStream());
|
logger.info("[ZLM HOOK] 流未找到:{}->{}->{}/{}", param.getMediaServerId(), param.getSchema(), param.getApp(), param.getStream());
|
||||||
|
|
||||||
DeferredResult<HookResult> defaultResult = new DeferredResult<>();
|
|
||||||
|
|
||||||
MediaServerItem mediaInfo = mediaServerService.getOne(param.getMediaServerId());
|
MediaServer mediaServer = mediaServerService.getOne(param.getMediaServerId());
|
||||||
if (!userSetting.isAutoApplyPlay() || mediaInfo == null) {
|
if (!userSetting.isAutoApplyPlay() || mediaServer == null) {
|
||||||
defaultResult.setResult(new HookResult(ErrorCode.ERROR404.getCode(), ErrorCode.ERROR404.getMsg()));
|
return HookResult.SUCCESS();
|
||||||
return defaultResult;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ("rtp".equals(param.getApp())) {
|
|
||||||
String[] s = param.getStream().split("_");
|
|
||||||
if ((s.length != 2 && s.length != 4)) {
|
|
||||||
defaultResult.setResult(HookResult.SUCCESS());
|
|
||||||
return defaultResult;
|
|
||||||
}
|
|
||||||
String deviceId = s[0];
|
|
||||||
String channelId = s[1];
|
|
||||||
Device device = redisCatchStorage.getDevice(deviceId);
|
|
||||||
if (device == null || !device.isOnLine()) {
|
|
||||||
defaultResult.setResult(new HookResult(ErrorCode.ERROR404.getCode(), ErrorCode.ERROR404.getMsg()));
|
|
||||||
return defaultResult;
|
|
||||||
}
|
|
||||||
DeviceChannel deviceChannel = storager.queryChannel(deviceId, channelId);
|
|
||||||
if (deviceChannel == null) {
|
|
||||||
defaultResult.setResult(new HookResult(ErrorCode.ERROR404.getCode(), ErrorCode.ERROR404.getMsg()));
|
|
||||||
return defaultResult;
|
|
||||||
}
|
|
||||||
if (s.length == 2) {
|
|
||||||
logger.info("[ZLM HOOK] 预览流未找到, 发起自动点播:{}->{}->{}/{}", param.getMediaServerId(), param.getSchema(), param.getApp(), param.getStream());
|
|
||||||
|
|
||||||
RequestMessage msg = new RequestMessage();
|
|
||||||
String key = DeferredResultHolder.CALLBACK_CMD_PLAY + deviceId + channelId;
|
|
||||||
boolean exist = resultHolder.exist(key, null);
|
|
||||||
msg.setKey(key);
|
|
||||||
String uuid = UUID.randomUUID().toString();
|
|
||||||
msg.setId(uuid);
|
|
||||||
DeferredResult<HookResult> result = new DeferredResult<>(userSetting.getPlayTimeout().longValue());
|
|
||||||
|
|
||||||
result.onTimeout(() -> {
|
|
||||||
logger.info("[ZLM HOOK] 预览流自动点播, 等待超时");
|
|
||||||
msg.setData(new HookResult(ErrorCode.ERROR100.getCode(), "点播超时"));
|
|
||||||
resultHolder.invokeAllResult(msg);
|
|
||||||
inviteStreamService.removeInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, deviceId, channelId);
|
|
||||||
storager.stopPlay(deviceId, channelId);
|
|
||||||
});
|
|
||||||
|
|
||||||
resultHolder.put(key, uuid, result);
|
|
||||||
|
|
||||||
if (!exist) {
|
|
||||||
playService.play(mediaInfo, deviceId, channelId, null, (code, message, data) -> {
|
|
||||||
msg.setData(new HookResult(code, message));
|
|
||||||
resultHolder.invokeResult(msg);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
} else if (s.length == 4) {
|
|
||||||
// 此时为录像回放, 录像回放格式为> 设备ID_通道ID_开始时间_结束时间
|
|
||||||
String startTimeStr = s[2];
|
|
||||||
String endTimeStr = s[3];
|
|
||||||
if (startTimeStr == null || endTimeStr == null || startTimeStr.length() != 14 || endTimeStr.length() != 14) {
|
|
||||||
defaultResult.setResult(HookResult.SUCCESS());
|
|
||||||
return defaultResult;
|
|
||||||
}
|
|
||||||
String startTime = DateUtil.urlToyyyy_MM_dd_HH_mm_ss(startTimeStr);
|
|
||||||
String endTime = DateUtil.urlToyyyy_MM_dd_HH_mm_ss(endTimeStr);
|
|
||||||
logger.info("[ZLM HOOK] 回放流未找到, 发起自动点播:{}->{}->{}/{}-{}-{}",
|
|
||||||
param.getMediaServerId(), param.getSchema(),
|
|
||||||
param.getApp(), param.getStream(),
|
|
||||||
startTime, endTime
|
|
||||||
);
|
|
||||||
RequestMessage msg = new RequestMessage();
|
|
||||||
String key = DeferredResultHolder.CALLBACK_CMD_PLAYBACK + deviceId + channelId;
|
|
||||||
boolean exist = resultHolder.exist(key, null);
|
|
||||||
msg.setKey(key);
|
|
||||||
String uuid = UUID.randomUUID().toString();
|
|
||||||
msg.setId(uuid);
|
|
||||||
DeferredResult<HookResult> result = new DeferredResult<>(userSetting.getPlayTimeout().longValue());
|
|
||||||
|
|
||||||
result.onTimeout(() -> {
|
|
||||||
logger.info("[ZLM HOOK] 回放流自动点播, 等待超时");
|
|
||||||
// 释放rtpserver
|
|
||||||
msg.setData(new HookResult(ErrorCode.ERROR100.getCode(), "点播超时"));
|
|
||||||
resultHolder.invokeResult(msg);
|
|
||||||
});
|
|
||||||
|
|
||||||
resultHolder.put(key, uuid, result);
|
|
||||||
|
|
||||||
if (!exist) {
|
|
||||||
SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaInfo, param.getStream(), null,
|
|
||||||
device.isSsrcCheck(), true, 0, false, false, device.getStreamModeForParam());
|
|
||||||
playService.playBack(mediaInfo, ssrcInfo, deviceId, channelId, startTime, endTime, (code, message, data) -> {
|
|
||||||
msg.setData(new HookResult(code, message));
|
|
||||||
resultHolder.invokeResult(msg);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
} else {
|
|
||||||
defaultResult.setResult(HookResult.SUCCESS());
|
|
||||||
return defaultResult;
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
// 拉流代理
|
|
||||||
StreamProxyItem streamProxyByAppAndStream = streamProxyService.getStreamProxyByAppAndStream(param.getApp(), param.getStream());
|
|
||||||
if (streamProxyByAppAndStream != null && streamProxyByAppAndStream.isEnableDisableNoneReader()) {
|
|
||||||
streamProxyService.start(param.getApp(), param.getStream());
|
|
||||||
}
|
|
||||||
DeferredResult<HookResult> result = new DeferredResult<>();
|
|
||||||
result.setResult(HookResult.SUCCESS());
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
MediaNotFoundEvent mediaNotFoundEvent = MediaNotFoundEvent.getInstance(this, param, mediaServer);
|
||||||
|
applicationEventPublisher.publishEvent(mediaNotFoundEvent);
|
||||||
|
return HookResult.SUCCESS();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -800,15 +255,16 @@ public class ZLMHttpHookListener {
|
|||||||
ZLMServerConfig zlmServerConfig = JSON.to(ZLMServerConfig.class, jsonObject);
|
ZLMServerConfig zlmServerConfig = JSON.to(ZLMServerConfig.class, jsonObject);
|
||||||
zlmServerConfig.setIp(request.getRemoteAddr());
|
zlmServerConfig.setIp(request.getRemoteAddr());
|
||||||
logger.info("[ZLM HOOK] zlm 启动 " + zlmServerConfig.getGeneralMediaServerId());
|
logger.info("[ZLM HOOK] zlm 启动 " + zlmServerConfig.getGeneralMediaServerId());
|
||||||
taskExecutor.execute(() -> {
|
try {
|
||||||
List<ZlmHttpHookSubscribe.Event> subscribes = this.subscribe.getSubscribes(HookType.on_server_started);
|
HookZlmServerStartEvent event = new HookZlmServerStartEvent(this);
|
||||||
if (subscribes != null && !subscribes.isEmpty()) {
|
MediaServer mediaServerItem = mediaServerService.getOne(zlmServerConfig.getMediaServerId());
|
||||||
for (ZlmHttpHookSubscribe.Event subscribe : subscribes) {
|
if (mediaServerItem != null) {
|
||||||
subscribe.response(null, zlmServerConfig);
|
event.setMediaServerItem(mediaServerItem);
|
||||||
}
|
applicationEventPublisher.publishEvent(event);
|
||||||
}
|
}
|
||||||
mediaServerService.zlmServerOnline(zlmServerConfig);
|
}catch (Exception e) {
|
||||||
});
|
logger.info("[ZLM-HOOK-ZLM启动] 发送通知失败 ", e);
|
||||||
|
}
|
||||||
|
|
||||||
return HookResult.SUCCESS();
|
return HookResult.SUCCESS();
|
||||||
}
|
}
|
||||||
@ -826,22 +282,16 @@ public class ZLMHttpHookListener {
|
|||||||
if (!"rtp".equals(param.getApp())) {
|
if (!"rtp".equals(param.getApp())) {
|
||||||
return HookResult.SUCCESS();
|
return HookResult.SUCCESS();
|
||||||
}
|
}
|
||||||
taskExecutor.execute(() -> {
|
try {
|
||||||
List<SendRtpItem> sendRtpItems = redisCatchStorage.querySendRTPServerByStream(param.getStream());
|
MediaSendRtpStoppedEvent event = new MediaSendRtpStoppedEvent(this);
|
||||||
if (sendRtpItems.size() > 0) {
|
MediaServer mediaServerItem = mediaServerService.getOne(param.getMediaServerId());
|
||||||
for (SendRtpItem sendRtpItem : sendRtpItems) {
|
if (mediaServerItem != null) {
|
||||||
ParentPlatform parentPlatform = storager.queryParentPlatByServerGBId(sendRtpItem.getPlatformId());
|
event.setMediaServer(mediaServerItem);
|
||||||
ssrcFactory.releaseSsrc(sendRtpItem.getMediaServerId(), sendRtpItem.getSsrc());
|
applicationEventPublisher.publishEvent(event);
|
||||||
try {
|
|
||||||
commanderFroPlatform.streamByeCmd(parentPlatform, sendRtpItem.getCallId());
|
|
||||||
} catch (SipException | InvalidArgumentException | ParseException e) {
|
|
||||||
logger.error("[命令发送失败] 国标级联 发送BYE: {}", e.getMessage());
|
|
||||||
}
|
|
||||||
redisCatchStorage.deleteSendRTPServer(parentPlatform.getServerGBId(), sendRtpItem.getChannelId(),
|
|
||||||
sendRtpItem.getCallId(), sendRtpItem.getStream());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
}catch (Exception e) {
|
||||||
|
logger.info("[ZLM-HOOK-rtp发送关闭] 发送通知失败 ", e);
|
||||||
|
}
|
||||||
|
|
||||||
return HookResult.SUCCESS();
|
return HookResult.SUCCESS();
|
||||||
}
|
}
|
||||||
@ -855,14 +305,17 @@ public class ZLMHttpHookListener {
|
|||||||
param) {
|
param) {
|
||||||
logger.info("[ZLM HOOK] rtpServer收流超时:{}->{}({})", param.getMediaServerId(), param.getStream_id(), param.getSsrc());
|
logger.info("[ZLM HOOK] rtpServer收流超时:{}->{}({})", param.getMediaServerId(), param.getStream_id(), param.getSsrc());
|
||||||
|
|
||||||
taskExecutor.execute(() -> {
|
try {
|
||||||
List<ZlmHttpHookSubscribe.Event> subscribes = this.subscribe.getSubscribes(HookType.on_rtp_server_timeout);
|
MediaRtpServerTimeoutEvent event = new MediaRtpServerTimeoutEvent(this);
|
||||||
if (subscribes != null && !subscribes.isEmpty()) {
|
MediaServer mediaServerItem = mediaServerService.getOne(param.getMediaServerId());
|
||||||
for (ZlmHttpHookSubscribe.Event subscribe : subscribes) {
|
if (mediaServerItem != null) {
|
||||||
subscribe.response(null, param);
|
event.setMediaServer(mediaServerItem);
|
||||||
}
|
event.setApp("rtp");
|
||||||
|
applicationEventPublisher.publishEvent(event);
|
||||||
}
|
}
|
||||||
});
|
}catch (Exception e) {
|
||||||
|
logger.info("[ZLM-HOOK-rtpServer收流超时] 发送通知失败 ", e);
|
||||||
|
}
|
||||||
|
|
||||||
return HookResult.SUCCESS();
|
return HookResult.SUCCESS();
|
||||||
}
|
}
|
||||||
@ -875,16 +328,16 @@ public class ZLMHttpHookListener {
|
|||||||
public HookResult onRecordMp4(HttpServletRequest request, @RequestBody OnRecordMp4HookParam param) {
|
public HookResult onRecordMp4(HttpServletRequest request, @RequestBody OnRecordMp4HookParam param) {
|
||||||
logger.info("[ZLM HOOK] 录像完成事件:{}->{}", param.getMediaServerId(), param.getFile_path());
|
logger.info("[ZLM HOOK] 录像完成事件:{}->{}", param.getMediaServerId(), param.getFile_path());
|
||||||
|
|
||||||
taskExecutor.execute(() -> {
|
try {
|
||||||
List<ZlmHttpHookSubscribe.Event> subscribes = this.subscribe.getSubscribes(HookType.on_record_mp4);
|
MediaServer mediaServerItem = mediaServerService.getOne(param.getMediaServerId());
|
||||||
if (subscribes != null && !subscribes.isEmpty()) {
|
if (mediaServerItem != null) {
|
||||||
for (ZlmHttpHookSubscribe.Event subscribe : subscribes) {
|
MediaRecordMp4Event event = MediaRecordMp4Event.getInstance(this, param, mediaServerItem);
|
||||||
subscribe.response(null, param);
|
event.setMediaServer(mediaServerItem);
|
||||||
}
|
applicationEventPublisher.publishEvent(event);
|
||||||
}
|
}
|
||||||
cloudRecordService.addRecord(param);
|
}catch (Exception e) {
|
||||||
|
logger.info("[ZLM-HOOK-rtpServer收流超时] 发送通知失败 ", e);
|
||||||
});
|
}
|
||||||
|
|
||||||
return HookResult.SUCCESS();
|
return HookResult.SUCCESS();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,15 +2,14 @@ package com.genersoft.iot.vmp.media.zlm;
|
|||||||
|
|
||||||
import com.genersoft.iot.vmp.conf.UserSetting;
|
import com.genersoft.iot.vmp.conf.UserSetting;
|
||||||
import com.genersoft.iot.vmp.gb28181.bean.GbStream;
|
import com.genersoft.iot.vmp.gb28181.bean.GbStream;
|
||||||
import com.genersoft.iot.vmp.media.zlm.dto.*;
|
import com.genersoft.iot.vmp.media.bean.MediaServer;
|
||||||
|
import com.genersoft.iot.vmp.media.service.IMediaServerService;
|
||||||
|
import com.genersoft.iot.vmp.media.zlm.dto.ChannelOnlineEvent;
|
||||||
|
import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem;
|
||||||
import com.genersoft.iot.vmp.media.zlm.dto.hook.OnStreamChangedHookParam;
|
import com.genersoft.iot.vmp.media.zlm.dto.hook.OnStreamChangedHookParam;
|
||||||
import com.genersoft.iot.vmp.service.IMediaServerService;
|
|
||||||
import com.genersoft.iot.vmp.service.IStreamProxyService;
|
|
||||||
import com.genersoft.iot.vmp.service.IStreamPushService;
|
import com.genersoft.iot.vmp.service.IStreamPushService;
|
||||||
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
|
|
||||||
import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
|
import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
|
||||||
import com.genersoft.iot.vmp.storager.dao.GbStreamMapper;
|
import com.genersoft.iot.vmp.storager.dao.GbStreamMapper;
|
||||||
import com.genersoft.iot.vmp.storager.dao.PlatformGbStreamMapper;
|
|
||||||
import com.genersoft.iot.vmp.storager.dao.StreamPushMapper;
|
import com.genersoft.iot.vmp.storager.dao.StreamPushMapper;
|
||||||
import com.genersoft.iot.vmp.utils.DateUtil;
|
import com.genersoft.iot.vmp.utils.DateUtil;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
@ -19,7 +18,7 @@ import org.springframework.beans.factory.annotation.Autowired;
|
|||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import java.text.ParseException;
|
import java.text.ParseException;
|
||||||
import java.util.*;
|
import java.util.Map;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -30,38 +29,22 @@ public class ZLMMediaListManager {
|
|||||||
|
|
||||||
private Logger logger = LoggerFactory.getLogger("ZLMMediaListManager");
|
private Logger logger = LoggerFactory.getLogger("ZLMMediaListManager");
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private ZLMRESTfulUtils zlmresTfulUtils;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private IRedisCatchStorage redisCatchStorage;
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private IVideoManagerStorage storager;
|
private IVideoManagerStorage storager;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private GbStreamMapper gbStreamMapper;
|
private GbStreamMapper gbStreamMapper;
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private PlatformGbStreamMapper platformGbStreamMapper;
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private IStreamPushService streamPushService;
|
private IStreamPushService streamPushService;
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private IStreamProxyService streamProxyService;
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private StreamPushMapper streamPushMapper;
|
private StreamPushMapper streamPushMapper;
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private ZlmHttpHookSubscribe subscribe;
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private UserSetting userSetting;
|
private UserSetting userSetting;
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private ZLMServerFactory zlmServerFactory;
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private IMediaServerService mediaServerService;
|
private IMediaServerService mediaServerService;
|
||||||
@ -95,9 +78,9 @@ public class ZLMMediaListManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void sendStreamEvent(String app, String stream, String mediaServerId) {
|
public void sendStreamEvent(String app, String stream, String mediaServerId) {
|
||||||
MediaServerItem mediaServerItem = mediaServerService.getOne(mediaServerId);
|
MediaServer mediaServerItem = mediaServerService.getOne(mediaServerId);
|
||||||
// 查看推流状态
|
// 查看推流状态
|
||||||
Boolean streamReady = zlmServerFactory.isStreamReady(mediaServerItem, app, stream);
|
Boolean streamReady = mediaServerService.isStreamReady(mediaServerItem, app, stream);
|
||||||
if (streamReady != null && streamReady) {
|
if (streamReady != null && streamReady) {
|
||||||
ChannelOnlineEvent channelOnlineEventLister = getChannelOnlineEventLister(app, stream);
|
ChannelOnlineEvent channelOnlineEventLister = getChannelOnlineEventLister(app, stream);
|
||||||
if (channelOnlineEventLister != null) {
|
if (channelOnlineEventLister != null) {
|
||||||
|
|||||||
@ -0,0 +1,361 @@
|
|||||||
|
package com.genersoft.iot.vmp.media.zlm;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSON;
|
||||||
|
import com.alibaba.fastjson2.JSONArray;
|
||||||
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
|
import com.genersoft.iot.vmp.common.CommonCallback;
|
||||||
|
import com.genersoft.iot.vmp.common.StreamInfo;
|
||||||
|
import com.genersoft.iot.vmp.conf.exception.ControllerException;
|
||||||
|
import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
|
||||||
|
import com.genersoft.iot.vmp.media.bean.MediaInfo;
|
||||||
|
import com.genersoft.iot.vmp.media.service.IMediaNodeServerService;
|
||||||
|
import com.genersoft.iot.vmp.media.bean.MediaServer;
|
||||||
|
import com.genersoft.iot.vmp.media.zlm.dto.ZLMServerConfig;
|
||||||
|
import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
|
||||||
|
import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
|
||||||
|
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.stereotype.Service;
|
||||||
|
import org.springframework.util.ObjectUtils;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@Service("zlm")
|
||||||
|
public class ZLMMediaNodeServerService implements IMediaNodeServerService {
|
||||||
|
|
||||||
|
private final static Logger logger = LoggerFactory.getLogger(ZLMMediaNodeServerService.class);
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ZLMRESTfulUtils zlmresTfulUtils;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ZLMServerFactory zlmServerFactory;
|
||||||
|
|
||||||
|
@Value("${sip.ip}")
|
||||||
|
private String sipIp;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int createRTPServer(MediaServer mediaServer, String streamId, long ssrc, Integer port, Boolean onlyAuto, Boolean disableAudio, Boolean reUsePort, Integer tcpMode) {
|
||||||
|
return zlmServerFactory.createRTPServer(mediaServer, streamId, ssrc, port, onlyAuto, reUsePort, tcpMode);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void closeRtpServer(MediaServer mediaServer, String streamId) {
|
||||||
|
zlmServerFactory.closeRtpServer(mediaServer, streamId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void closeRtpServer(MediaServer mediaServer, String streamId, CommonCallback<Boolean> callback) {
|
||||||
|
zlmServerFactory.closeRtpServer(mediaServer, streamId, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void closeStreams(MediaServer mediaServer, String app, String stream) {
|
||||||
|
zlmresTfulUtils.closeStreams(mediaServer, app, stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Boolean updateRtpServerSSRC(MediaServer mediaServer, String streamId, String ssrc) {
|
||||||
|
return zlmServerFactory.updateRtpServerSSRC(mediaServer, streamId, ssrc);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean checkNodeId(MediaServer mediaServer) {
|
||||||
|
if (mediaServer == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
JSONObject responseJSON = zlmresTfulUtils.getMediaServerConfig(mediaServer);
|
||||||
|
if (responseJSON != null) {
|
||||||
|
JSONArray data = responseJSON.getJSONArray("data");
|
||||||
|
if (data != null && !data.isEmpty()) {
|
||||||
|
ZLMServerConfig zlmServerConfig= JSON.parseObject(JSON.toJSONString(data.get(0)), ZLMServerConfig.class);
|
||||||
|
return zlmServerConfig.getGeneralMediaServerId().equals(mediaServer.getId());
|
||||||
|
}else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void online(MediaServer mediaServer) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MediaServer checkMediaServer(String ip, int port, String secret) {
|
||||||
|
MediaServer mediaServer = new MediaServer();
|
||||||
|
mediaServer.setIp(ip);
|
||||||
|
mediaServer.setHttpPort(port);
|
||||||
|
mediaServer.setSecret(secret);
|
||||||
|
JSONObject responseJSON = zlmresTfulUtils.getMediaServerConfig(mediaServer);
|
||||||
|
if (responseJSON == null) {
|
||||||
|
throw new ControllerException(ErrorCode.ERROR100.getCode(), "连接失败");
|
||||||
|
}
|
||||||
|
JSONArray data = responseJSON.getJSONArray("data");
|
||||||
|
if (data == null) {
|
||||||
|
throw new ControllerException(ErrorCode.ERROR100.getCode(), "读取配置失败");
|
||||||
|
}
|
||||||
|
ZLMServerConfig zlmServerConfig = JSON.parseObject(JSON.toJSONString(data.get(0)), ZLMServerConfig.class);
|
||||||
|
if (zlmServerConfig == null) {
|
||||||
|
throw new ControllerException(ErrorCode.ERROR100.getCode(), "读取配置失败");
|
||||||
|
}
|
||||||
|
mediaServer.setId(zlmServerConfig.getGeneralMediaServerId());
|
||||||
|
mediaServer.setHttpSSlPort(zlmServerConfig.getHttpPort());
|
||||||
|
mediaServer.setRtmpPort(zlmServerConfig.getRtmpPort());
|
||||||
|
mediaServer.setRtmpSSlPort(zlmServerConfig.getRtmpSslPort());
|
||||||
|
mediaServer.setRtspPort(zlmServerConfig.getRtspPort());
|
||||||
|
mediaServer.setRtspSSLPort(zlmServerConfig.getRtspSSlport());
|
||||||
|
mediaServer.setRtpProxyPort(zlmServerConfig.getRtpProxyPort());
|
||||||
|
mediaServer.setStreamIp(ip);
|
||||||
|
mediaServer.setHookIp(sipIp.split(",")[0]);
|
||||||
|
mediaServer.setSdpIp(ip);
|
||||||
|
mediaServer.setType("zlm");
|
||||||
|
return mediaServer;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean stopSendRtp(MediaServer mediaInfo, String app, String stream, String ssrc) {
|
||||||
|
Map<String, Object> param = new HashMap<>();
|
||||||
|
param.put("vhost", "__defaultVhost__");
|
||||||
|
param.put("app", app);
|
||||||
|
param.put("stream", stream);
|
||||||
|
if (!ObjectUtils.isEmpty(ssrc)) {
|
||||||
|
param.put("ssrc", ssrc);
|
||||||
|
}
|
||||||
|
JSONObject jsonObject = zlmresTfulUtils.stopSendRtp(mediaInfo, param);
|
||||||
|
return (jsonObject != null && jsonObject.getInteger("code") == 0);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean deleteRecordDirectory(MediaServer mediaServer, String app, String stream, String date, String fileName) {
|
||||||
|
logger.info("[zlm-deleteRecordDirectory] 删除磁盘文件, server: {} {}:{}->{}/{}", mediaServer.getId(), app, stream, date, fileName);
|
||||||
|
JSONObject jsonObject = zlmresTfulUtils.deleteRecordDirectory(mediaServer, app,
|
||||||
|
stream, date, fileName);
|
||||||
|
if (jsonObject.getInteger("code") == 0) {
|
||||||
|
return true;
|
||||||
|
}else {
|
||||||
|
logger.info("[zlm-deleteRecordDirectory] 删除磁盘文件错误, server: {} {}:{}->{}/{}, 结果: {}", mediaServer.getId(), app, stream, date, fileName, jsonObject);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<StreamInfo> getMediaList(MediaServer mediaServer, String app, String stream, String callId) {
|
||||||
|
List<StreamInfo> streamInfoList = new ArrayList<>();
|
||||||
|
JSONObject mediaList = zlmresTfulUtils.getMediaList(mediaServer, app, stream);
|
||||||
|
if (mediaList != null) {
|
||||||
|
if (mediaList.getInteger("code") == 0) {
|
||||||
|
JSONArray data = mediaList.getJSONArray("data");
|
||||||
|
if (data == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
JSONObject mediaJSON = data.getJSONObject(0);
|
||||||
|
MediaInfo mediaInfo = MediaInfo.getInstance(mediaJSON, mediaServer);
|
||||||
|
StreamInfo streamInfo = getStreamInfoByAppAndStream(mediaServer, app, stream, mediaInfo, callId, true);
|
||||||
|
if (streamInfo != null) {
|
||||||
|
streamInfoList.add(streamInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return streamInfoList;
|
||||||
|
}
|
||||||
|
|
||||||
|
public StreamInfo getStreamInfoByAppAndStream(MediaServer mediaServer, String app, String stream, MediaInfo mediaInfo, String callId, boolean isPlay) {
|
||||||
|
StreamInfo streamInfoResult = new StreamInfo();
|
||||||
|
streamInfoResult.setStream(stream);
|
||||||
|
streamInfoResult.setApp(app);
|
||||||
|
String addr = mediaServer.getStreamIp();
|
||||||
|
streamInfoResult.setIp(addr);
|
||||||
|
streamInfoResult.setMediaServerId(mediaServer.getId());
|
||||||
|
String callIdParam = ObjectUtils.isEmpty(callId)?"":"?callId=" + callId;
|
||||||
|
streamInfoResult.setRtmp(addr, mediaServer.getRtmpPort(),mediaServer.getRtmpSSlPort(), app, stream, callIdParam);
|
||||||
|
streamInfoResult.setRtsp(addr, mediaServer.getRtspPort(),mediaServer.getRtspSSLPort(), app, stream, callIdParam);
|
||||||
|
String flvFile = String.format("%s/%s.live.flv%s", app, stream, callIdParam);
|
||||||
|
streamInfoResult.setFlv(addr, mediaServer.getHttpPort(),mediaServer.getHttpSSlPort(), flvFile);
|
||||||
|
streamInfoResult.setWsFlv(addr, mediaServer.getHttpPort(),mediaServer.getHttpSSlPort(), flvFile);
|
||||||
|
streamInfoResult.setFmp4(addr, mediaServer.getHttpPort(),mediaServer.getHttpSSlPort(), app, stream, callIdParam);
|
||||||
|
streamInfoResult.setHls(addr, mediaServer.getHttpPort(),mediaServer.getHttpSSlPort(), app, stream, callIdParam);
|
||||||
|
streamInfoResult.setTs(addr, mediaServer.getHttpPort(),mediaServer.getHttpSSlPort(), app, stream, callIdParam);
|
||||||
|
streamInfoResult.setRtc(addr, mediaServer.getHttpPort(),mediaServer.getHttpSSlPort(), app, stream, callIdParam, isPlay);
|
||||||
|
|
||||||
|
streamInfoResult.setMediaInfo(mediaInfo);
|
||||||
|
streamInfoResult.setOriginType(mediaInfo.getOriginType());
|
||||||
|
return streamInfoResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Boolean connectRtpServer(MediaServer mediaServer, String address, int port, String stream) {
|
||||||
|
JSONObject jsonObject = zlmresTfulUtils.connectRtpServer(mediaServer, address, port, stream);
|
||||||
|
logger.info("[TCP主动连接对方] 结果: {}", jsonObject);
|
||||||
|
return jsonObject.getInteger("code") == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void getSnap(MediaServer mediaServer, String streamUrl, int timeoutSec, int expireSec, String path, String fileName) {
|
||||||
|
zlmresTfulUtils.getSnap(mediaServer, streamUrl, timeoutSec, expireSec, path, fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MediaInfo getMediaInfo(MediaServer mediaServer, String app, String stream) {
|
||||||
|
JSONObject jsonObject = zlmresTfulUtils.getMediaInfo(mediaServer, app, "rtsp", stream);
|
||||||
|
if (jsonObject.getInteger("code") != 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return MediaInfo.getInstance(jsonObject, mediaServer);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Boolean pauseRtpCheck(MediaServer mediaServer, String streamKey) {
|
||||||
|
JSONObject jsonObject = zlmresTfulUtils.pauseRtpCheck(mediaServer, streamKey);
|
||||||
|
return jsonObject.getInteger("code") == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Boolean resumeRtpCheck(MediaServer mediaServer, String streamKey) {
|
||||||
|
JSONObject jsonObject = zlmresTfulUtils.resumeRtpCheck(mediaServer, streamKey);
|
||||||
|
return jsonObject.getInteger("code") == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getFfmpegCmd(MediaServer mediaServer, String cmdKey) {
|
||||||
|
JSONObject jsonObject = zlmresTfulUtils.getMediaServerConfig(mediaServer);
|
||||||
|
if (jsonObject.getInteger("code") != 0) {
|
||||||
|
logger.warn("[getFfmpegCmd] 获取流媒体配置失败");
|
||||||
|
throw new ControllerException(ErrorCode.ERROR100.getCode(), "获取流媒体配置失败");
|
||||||
|
}
|
||||||
|
JSONArray dataArray = jsonObject.getJSONArray("data");
|
||||||
|
JSONObject mediaServerConfig = dataArray.getJSONObject(0);
|
||||||
|
if (ObjectUtils.isEmpty(cmdKey)) {
|
||||||
|
cmdKey = "ffmpeg.cmd";
|
||||||
|
}
|
||||||
|
return mediaServerConfig.getString(cmdKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WVPResult<String> addFFmpegSource(MediaServer mediaServer, String srcUrl, String dstUrl, int timeoutMs, boolean enableAudio, boolean enableMp4, String ffmpegCmdKey) {
|
||||||
|
JSONObject jsonObject = zlmresTfulUtils.addFFmpegSource(mediaServer, srcUrl, dstUrl, timeoutMs, enableAudio, enableMp4, ffmpegCmdKey);
|
||||||
|
if (jsonObject.getInteger("code") != 0) {
|
||||||
|
logger.warn("[getFfmpegCmd] 添加FFMPEG代理失败");
|
||||||
|
return WVPResult.fail(ErrorCode.ERROR100.getCode(), "添加FFMPEG代理失败");
|
||||||
|
}else {
|
||||||
|
JSONObject data = jsonObject.getJSONObject("data");
|
||||||
|
if (data == null) {
|
||||||
|
return WVPResult.fail(ErrorCode.ERROR100.getCode(), "代理结果异常: " + jsonObject);
|
||||||
|
}else {
|
||||||
|
return WVPResult.success(data.getString("key"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WVPResult<String> addStreamProxy(MediaServer mediaServer, String app, String stream, String url, boolean enableAudio, boolean enableMp4, String rtpType) {
|
||||||
|
JSONObject jsonObject = zlmresTfulUtils.addStreamProxy(mediaServer, app, stream, url, enableAudio, enableMp4, rtpType);
|
||||||
|
if (jsonObject.getInteger("code") != 0) {
|
||||||
|
return WVPResult.fail(ErrorCode.ERROR100.getCode(), "添加代理失败");
|
||||||
|
}else {
|
||||||
|
JSONObject data = jsonObject.getJSONObject("data");
|
||||||
|
if (data == null) {
|
||||||
|
return WVPResult.fail(ErrorCode.ERROR100.getCode(), "代理结果异常: " + jsonObject);
|
||||||
|
}else {
|
||||||
|
return WVPResult.success(data.getString("key"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Boolean delFFmpegSource(MediaServer mediaServer, String streamKey) {
|
||||||
|
JSONObject jsonObject = zlmresTfulUtils.delFFmpegSource(mediaServer, streamKey);
|
||||||
|
return jsonObject.getInteger("code") == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Boolean delStreamProxy(MediaServer mediaServer, String streamKey) {
|
||||||
|
JSONObject jsonObject = zlmresTfulUtils.delStreamProxy(mediaServer, streamKey);
|
||||||
|
return jsonObject.getInteger("code") == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, String> getFFmpegCMDs(MediaServer mediaServer) {
|
||||||
|
Map<String, String> result = new HashMap<>();
|
||||||
|
JSONObject mediaServerConfigResuly = zlmresTfulUtils.getMediaServerConfig(mediaServer);
|
||||||
|
if (mediaServerConfigResuly != null && mediaServerConfigResuly.getInteger("code") == 0
|
||||||
|
&& mediaServerConfigResuly.getJSONArray("data").size() > 0){
|
||||||
|
JSONObject mediaServerConfig = mediaServerConfigResuly.getJSONArray("data").getJSONObject(0);
|
||||||
|
|
||||||
|
for (String key : mediaServerConfig.keySet()) {
|
||||||
|
if (key.startsWith("ffmpeg.cmd")){
|
||||||
|
result.put(key, mediaServerConfig.getString(key));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void startSendRtpPassive(MediaServer mediaServer, SendRtpItem sendRtpItem, 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("src_port", sendRtpItem.getLocalPort());
|
||||||
|
param.put("pt", sendRtpItem.getPt());
|
||||||
|
param.put("use_ps", sendRtpItem.isUsePs() ? "1" : "0");
|
||||||
|
param.put("only_audio", sendRtpItem.isOnlyAudio() ? "1" : "0");
|
||||||
|
param.put("is_udp", sendRtpItem.isTcp() ? "0" : "1");
|
||||||
|
param.put("recv_stream_id", sendRtpItem.getReceiveStream());
|
||||||
|
if (timeout != null) {
|
||||||
|
param.put("close_delay_ms", timeout);
|
||||||
|
}
|
||||||
|
if (!sendRtpItem.isTcp()) {
|
||||||
|
// 开启rtcp保活
|
||||||
|
param.put("udp_rtcp_timeout", sendRtpItem.isRtcp()? "1":"0");
|
||||||
|
}
|
||||||
|
if (!sendRtpItem.isTcpActive()) {
|
||||||
|
param.put("dst_url",sendRtpItem.getIp());
|
||||||
|
param.put("dst_port", sendRtpItem.getPort());
|
||||||
|
}
|
||||||
|
|
||||||
|
JSONObject jsonObject = zlmServerFactory.startSendRtpPassive(mediaServer, param, null);
|
||||||
|
if (jsonObject == null || jsonObject.getInteger("code") != 0 ) {
|
||||||
|
logger.error("启动监听TCP被动推流失败: {}, 参数:{}", jsonObject.getString("msg"), JSON.toJSONString(param));
|
||||||
|
throw new ControllerException(jsonObject.getInteger("code"), jsonObject.getString("msg"));
|
||||||
|
}
|
||||||
|
logger.info("调用ZLM-TCP被动推流接口, 结果: {}", jsonObject);
|
||||||
|
logger.info("启动监听TCP被动推流成功[ {}/{} ],{}->{}:{}, " , sendRtpItem.getApp(), sendRtpItem.getStream(),
|
||||||
|
jsonObject.getString("local_port"), param.get("dst_url"), param.get("dst_port"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void startSendRtpStream(MediaServer mediaServer, SendRtpItem sendRtpItem) {
|
||||||
|
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("src_port", sendRtpItem.getLocalPort());
|
||||||
|
param.put("pt", sendRtpItem.getPt());
|
||||||
|
param.put("use_ps", sendRtpItem.isUsePs() ? "1" : "0");
|
||||||
|
param.put("only_audio", sendRtpItem.isOnlyAudio() ? "1" : "0");
|
||||||
|
param.put("is_udp", sendRtpItem.isTcp() ? "0" : "1");
|
||||||
|
if (!sendRtpItem.isTcp()) {
|
||||||
|
// udp模式下开启rtcp保活
|
||||||
|
param.put("udp_rtcp_timeout", sendRtpItem.isRtcp() ? "1" : "0");
|
||||||
|
}
|
||||||
|
param.put("dst_url", sendRtpItem.getIp());
|
||||||
|
param.put("dst_port", sendRtpItem.getPort());
|
||||||
|
JSONObject jsonObject = zlmresTfulUtils.startSendRtp(mediaServer, param);
|
||||||
|
if (jsonObject == null || jsonObject.getInteger("code") != 0 ) {
|
||||||
|
throw new ControllerException(jsonObject.getInteger("code"), jsonObject.getString("msg"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,306 @@
|
|||||||
|
package com.genersoft.iot.vmp.media.zlm;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSON;
|
||||||
|
import com.alibaba.fastjson2.JSONArray;
|
||||||
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
|
import com.genersoft.iot.vmp.conf.DynamicTask;
|
||||||
|
import com.genersoft.iot.vmp.conf.UserSetting;
|
||||||
|
import com.genersoft.iot.vmp.media.event.mediaServer.MediaServerChangeEvent;
|
||||||
|
import com.genersoft.iot.vmp.media.event.mediaServer.MediaServerDeleteEvent;
|
||||||
|
import com.genersoft.iot.vmp.media.service.IMediaServerService;
|
||||||
|
import com.genersoft.iot.vmp.media.bean.MediaServer;
|
||||||
|
import com.genersoft.iot.vmp.media.zlm.dto.ZLMServerConfig;
|
||||||
|
import com.genersoft.iot.vmp.media.zlm.event.HookZlmServerKeepaliveEvent;
|
||||||
|
import com.genersoft.iot.vmp.media.zlm.event.HookZlmServerStartEvent;
|
||||||
|
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.event.EventListener;
|
||||||
|
import org.springframework.scheduling.annotation.Async;
|
||||||
|
import org.springframework.scheduling.annotation.Scheduled;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.util.ObjectUtils;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 管理zlm流媒体节点的状态
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class ZLMMediaServerStatusManger {
|
||||||
|
|
||||||
|
private final static Logger logger = LoggerFactory.getLogger(ZLMMediaServerStatusManger.class);
|
||||||
|
|
||||||
|
private final Map<Object, MediaServer> offlineZlmPrimaryMap = new ConcurrentHashMap<>();
|
||||||
|
private final Map<Object, MediaServer> offlineZlmsecondaryMap = new ConcurrentHashMap<>();
|
||||||
|
private final Map<Object, Long> offlineZlmTimeMap = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ZLMRESTfulUtils zlmresTfulUtils;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IMediaServerService mediaServerService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private DynamicTask dynamicTask;
|
||||||
|
|
||||||
|
@Value("${server.ssl.enabled:false}")
|
||||||
|
private boolean sslEnabled;
|
||||||
|
|
||||||
|
@Value("${server.port}")
|
||||||
|
private Integer serverPort;
|
||||||
|
|
||||||
|
@Value("${server.servlet.context-path:}")
|
||||||
|
private String serverServletContextPath;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private UserSetting userSetting;
|
||||||
|
|
||||||
|
private final String type = "zlm";
|
||||||
|
|
||||||
|
@Async("taskExecutor")
|
||||||
|
@EventListener
|
||||||
|
public void onApplicationEvent(MediaServerChangeEvent event) {
|
||||||
|
if (event.getMediaServerItemList() == null
|
||||||
|
|| event.getMediaServerItemList().isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (MediaServer mediaServerItem : event.getMediaServerItemList()) {
|
||||||
|
if (!type.equals(mediaServerItem.getType())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
logger.info("[ZLM-添加待上线节点] ID:" + mediaServerItem.getId());
|
||||||
|
offlineZlmPrimaryMap.put(mediaServerItem.getId(), mediaServerItem);
|
||||||
|
offlineZlmTimeMap.put(mediaServerItem.getId(), System.currentTimeMillis());
|
||||||
|
execute();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Async("taskExecutor")
|
||||||
|
@EventListener
|
||||||
|
public void onApplicationEvent(HookZlmServerStartEvent event) {
|
||||||
|
if (event.getMediaServerItem() == null
|
||||||
|
|| !type.equals(event.getMediaServerItem().getType())
|
||||||
|
|| event.getMediaServerItem().isStatus()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
MediaServer serverItem = mediaServerService.getOne(event.getMediaServerItem().getId());
|
||||||
|
if (serverItem == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
logger.info("[ZLM-HOOK事件-服务启动] ID:" + event.getMediaServerItem().getId());
|
||||||
|
online(serverItem, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Async("taskExecutor")
|
||||||
|
@EventListener
|
||||||
|
public void onApplicationEvent(HookZlmServerKeepaliveEvent event) {
|
||||||
|
if (event.getMediaServerItem() == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
MediaServer serverItem = mediaServerService.getOne(event.getMediaServerItem().getId());
|
||||||
|
if (serverItem == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
logger.info("[ZLM-HOOK事件-心跳] ID:" + event.getMediaServerItem().getId());
|
||||||
|
online(serverItem, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Async("taskExecutor")
|
||||||
|
@EventListener
|
||||||
|
public void onApplicationEvent(MediaServerDeleteEvent event) {
|
||||||
|
if (event.getMediaServerId() == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
logger.info("[ZLM-节点被移除] ID:" + event.getMediaServerId());
|
||||||
|
offlineZlmPrimaryMap.remove(event.getMediaServerId());
|
||||||
|
offlineZlmsecondaryMap.remove(event.getMediaServerId());
|
||||||
|
offlineZlmTimeMap.remove(event.getMediaServerId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Scheduled(fixedDelay = 10*1000) //每隔10秒检查一次
|
||||||
|
public void execute(){
|
||||||
|
// 初次加入的离线节点会在30分钟内,每间隔十秒尝试一次,30分钟后如果仍然没有上线,则每隔30分钟尝试一次连接
|
||||||
|
if (offlineZlmPrimaryMap.isEmpty() && offlineZlmsecondaryMap.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!offlineZlmPrimaryMap.isEmpty()) {
|
||||||
|
for (MediaServer mediaServerItem : offlineZlmPrimaryMap.values()) {
|
||||||
|
if (offlineZlmTimeMap.get(mediaServerItem.getId()) < System.currentTimeMillis() - 30*60*1000) {
|
||||||
|
offlineZlmsecondaryMap.put(mediaServerItem.getId(), mediaServerItem);
|
||||||
|
offlineZlmPrimaryMap.remove(mediaServerItem.getId());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
logger.info("[ZLM-尝试连接] ID:{}, 地址: {}:{}", mediaServerItem.getId(), mediaServerItem.getIp(), mediaServerItem.getHttpPort());
|
||||||
|
JSONObject responseJson = zlmresTfulUtils.getMediaServerConfig(mediaServerItem);
|
||||||
|
ZLMServerConfig zlmServerConfig = null;
|
||||||
|
if (responseJson == null) {
|
||||||
|
logger.info("[ZLM-尝试连接]失败, ID:{}, 地址: {}:{}", mediaServerItem.getId(), mediaServerItem.getIp(), mediaServerItem.getHttpPort());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
JSONArray data = responseJson.getJSONArray("data");
|
||||||
|
if (data == null || data.isEmpty()) {
|
||||||
|
logger.info("[ZLM-尝试连接]失败, ID:{}, 地址: {}:{}", mediaServerItem.getId(), mediaServerItem.getIp(), mediaServerItem.getHttpPort());
|
||||||
|
}else {
|
||||||
|
zlmServerConfig = JSON.parseObject(JSON.toJSONString(data.get(0)), ZLMServerConfig.class);
|
||||||
|
initPort(mediaServerItem, zlmServerConfig);
|
||||||
|
online(mediaServerItem, zlmServerConfig);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!offlineZlmsecondaryMap.isEmpty()) {
|
||||||
|
for (MediaServer mediaServerItem : offlineZlmsecondaryMap.values()) {
|
||||||
|
if (offlineZlmTimeMap.get(mediaServerItem.getId()) < System.currentTimeMillis() - 30*60*1000) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
logger.info("[ZLM-尝试连接] ID:{}, 地址: {}:{}", mediaServerItem.getId(), mediaServerItem.getIp(), mediaServerItem.getHttpPort());
|
||||||
|
JSONObject responseJson = zlmresTfulUtils.getMediaServerConfig(mediaServerItem);
|
||||||
|
ZLMServerConfig zlmServerConfig = null;
|
||||||
|
if (responseJson == null) {
|
||||||
|
logger.info("[ZLM-尝试连接]失败, ID:{}, 地址: {}:{}", mediaServerItem.getId(), mediaServerItem.getIp(), mediaServerItem.getHttpPort());
|
||||||
|
offlineZlmTimeMap.put(mediaServerItem.getId(), System.currentTimeMillis());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
JSONArray data = responseJson.getJSONArray("data");
|
||||||
|
if (data == null || data.isEmpty()) {
|
||||||
|
logger.info("[ZLM-尝试连接]失败, ID:{}, 地址: {}:{}", mediaServerItem.getId(), mediaServerItem.getIp(), mediaServerItem.getHttpPort());
|
||||||
|
offlineZlmTimeMap.put(mediaServerItem.getId(), System.currentTimeMillis());
|
||||||
|
}else {
|
||||||
|
zlmServerConfig = JSON.parseObject(JSON.toJSONString(data.get(0)), ZLMServerConfig.class);
|
||||||
|
initPort(mediaServerItem, zlmServerConfig);
|
||||||
|
online(mediaServerItem, zlmServerConfig);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void online(MediaServer mediaServerItem, ZLMServerConfig config) {
|
||||||
|
offlineZlmPrimaryMap.remove(mediaServerItem.getId());
|
||||||
|
offlineZlmsecondaryMap.remove(mediaServerItem.getId());
|
||||||
|
offlineZlmTimeMap.remove(mediaServerItem.getId());
|
||||||
|
if (!mediaServerItem.isStatus()) {
|
||||||
|
logger.info("[ZLM-连接成功] ID:{}, 地址: {}:{}", mediaServerItem.getId(), mediaServerItem.getIp(), mediaServerItem.getHttpPort());
|
||||||
|
mediaServerItem.setStatus(true);
|
||||||
|
mediaServerItem.setHookAliveInterval(10F);
|
||||||
|
mediaServerService.update(mediaServerItem);
|
||||||
|
if(mediaServerItem.isAutoConfig()) {
|
||||||
|
if (config == null) {
|
||||||
|
JSONObject responseJSON = zlmresTfulUtils.getMediaServerConfig(mediaServerItem);
|
||||||
|
JSONArray data = responseJSON.getJSONArray("data");
|
||||||
|
if (data != null && !data.isEmpty()) {
|
||||||
|
config = JSON.parseObject(JSON.toJSONString(data.get(0)), ZLMServerConfig.class);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (config != null) {
|
||||||
|
initPort(mediaServerItem, config);
|
||||||
|
setZLMConfig(mediaServerItem, "0".equals(config.getHookEnable())
|
||||||
|
|| !Objects.equals(mediaServerItem.getHookAliveInterval(), config.getHookAliveInterval()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mediaServerService.update(mediaServerItem);
|
||||||
|
}
|
||||||
|
// 设置两次心跳未收到则认为zlm离线
|
||||||
|
String key = "zlm-keepalive-" + mediaServerItem.getId();
|
||||||
|
dynamicTask.startDelay(key, ()->{
|
||||||
|
logger.warn("[ZLM-心跳超时] ID:{}", mediaServerItem.getId());
|
||||||
|
mediaServerItem.setStatus(false);
|
||||||
|
offlineZlmPrimaryMap.put(mediaServerItem.getId(), mediaServerItem);
|
||||||
|
offlineZlmTimeMap.put(mediaServerItem.getId(), System.currentTimeMillis());
|
||||||
|
// TODO 发送离线通知
|
||||||
|
mediaServerService.update(mediaServerItem);
|
||||||
|
}, (int)(mediaServerItem.getHookAliveInterval() * 2 * 1000));
|
||||||
|
}
|
||||||
|
private void initPort(MediaServer mediaServerItem, ZLMServerConfig zlmServerConfig) {
|
||||||
|
// 端口只会从配置中读取一次,一旦自己配置或者读取过了将不在配置
|
||||||
|
if (mediaServerItem.getHttpSSlPort() == 0) {
|
||||||
|
mediaServerItem.setHttpSSlPort(zlmServerConfig.getHttpSSLport());
|
||||||
|
}
|
||||||
|
if (mediaServerItem.getRtmpPort() == 0) {
|
||||||
|
mediaServerItem.setRtmpPort(zlmServerConfig.getRtmpPort());
|
||||||
|
}
|
||||||
|
if (mediaServerItem.getRtmpSSlPort() == 0) {
|
||||||
|
mediaServerItem.setRtmpSSlPort(zlmServerConfig.getRtmpSslPort());
|
||||||
|
}
|
||||||
|
if (mediaServerItem.getRtspPort() == 0) {
|
||||||
|
mediaServerItem.setRtspPort(zlmServerConfig.getRtspPort());
|
||||||
|
}
|
||||||
|
if (mediaServerItem.getRtspSSLPort() == 0) {
|
||||||
|
mediaServerItem.setRtspSSLPort(zlmServerConfig.getRtspSSlport());
|
||||||
|
}
|
||||||
|
if (mediaServerItem.getRtpProxyPort() == 0) {
|
||||||
|
mediaServerItem.setRtpProxyPort(zlmServerConfig.getRtpProxyPort());
|
||||||
|
}
|
||||||
|
mediaServerItem.setHookAliveInterval(10F);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setZLMConfig(MediaServer mediaServerItem, boolean restart) {
|
||||||
|
logger.info("[媒体服务节点] 正在设置 :{} -> {}:{}",
|
||||||
|
mediaServerItem.getId(), mediaServerItem.getIp(), mediaServerItem.getHttpPort());
|
||||||
|
String protocol = sslEnabled ? "https" : "http";
|
||||||
|
String hookPrefix = String.format("%s://%s:%s%s/index/hook", protocol, mediaServerItem.getHookIp(), serverPort, (serverServletContextPath == null || "/".equals(serverServletContextPath)) ? "" : serverServletContextPath);
|
||||||
|
|
||||||
|
Map<String, Object> param = new HashMap<>();
|
||||||
|
param.put("api.secret",mediaServerItem.getSecret()); // -profile:v Baseline
|
||||||
|
if (mediaServerItem.getRtspPort() != 0) {
|
||||||
|
param.put("ffmpeg.snap", "%s -rtsp_transport tcp -i %s -y -f mjpeg -frames:v 1 %s");
|
||||||
|
}
|
||||||
|
param.put("hook.enable","1");
|
||||||
|
param.put("hook.on_flow_report","");
|
||||||
|
param.put("hook.on_play",String.format("%s/on_play", hookPrefix));
|
||||||
|
param.put("hook.on_http_access","");
|
||||||
|
param.put("hook.on_publish", String.format("%s/on_publish", hookPrefix));
|
||||||
|
param.put("hook.on_record_ts","");
|
||||||
|
param.put("hook.on_rtsp_auth","");
|
||||||
|
param.put("hook.on_rtsp_realm","");
|
||||||
|
param.put("hook.on_server_started",String.format("%s/on_server_started", hookPrefix));
|
||||||
|
param.put("hook.on_shell_login","");
|
||||||
|
param.put("hook.on_stream_changed",String.format("%s/on_stream_changed", hookPrefix));
|
||||||
|
param.put("hook.on_stream_none_reader",String.format("%s/on_stream_none_reader", hookPrefix));
|
||||||
|
param.put("hook.on_stream_not_found",String.format("%s/on_stream_not_found", hookPrefix));
|
||||||
|
param.put("hook.on_server_keepalive",String.format("%s/on_server_keepalive", hookPrefix));
|
||||||
|
param.put("hook.on_send_rtp_stopped",String.format("%s/on_send_rtp_stopped", hookPrefix));
|
||||||
|
param.put("hook.on_rtp_server_timeout",String.format("%s/on_rtp_server_timeout", hookPrefix));
|
||||||
|
param.put("hook.on_record_mp4",String.format("%s/on_record_mp4", hookPrefix));
|
||||||
|
param.put("hook.timeoutSec","30");
|
||||||
|
param.put("hook.alive_interval", mediaServerItem.getHookAliveInterval());
|
||||||
|
// 推流断开后可以在超时时间内重新连接上继续推流,这样播放器会接着播放。
|
||||||
|
// 置0关闭此特性(推流断开会导致立即断开播放器)
|
||||||
|
// 此参数不应大于播放器超时时间
|
||||||
|
// 优化此消息以更快的收到流注销事件
|
||||||
|
param.put("protocol.continue_push_ms", "3000" );
|
||||||
|
// 最多等待未初始化的Track时间,单位毫秒,超时之后会忽略未初始化的Track, 设置此选项优化那些音频错误的不规范流,
|
||||||
|
// 等zlm支持给每个rtpServer设置关闭音频的时候可以不设置此选项
|
||||||
|
if (mediaServerItem.isRtpEnable() && !ObjectUtils.isEmpty(mediaServerItem.getRtpPortRange())) {
|
||||||
|
param.put("rtp_proxy.port_range", mediaServerItem.getRtpPortRange().replace(",", "-"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ObjectUtils.isEmpty(mediaServerItem.getRecordPath())) {
|
||||||
|
File recordPathFile = new File(mediaServerItem.getRecordPath());
|
||||||
|
param.put("protocol.mp4_save_path", recordPathFile.getParentFile().getPath());
|
||||||
|
param.put("protocol.downloadRoot", recordPathFile.getParentFile().getPath());
|
||||||
|
param.put("record.appName", recordPathFile.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
JSONObject responseJSON = zlmresTfulUtils.setServerConfig(mediaServerItem, param);
|
||||||
|
|
||||||
|
if (responseJSON != null && responseJSON.getInteger("code") == 0) {
|
||||||
|
if (restart) {
|
||||||
|
logger.info("[媒体服务节点] 设置成功,开始重启以保证配置生效 {} -> {}:{}",
|
||||||
|
mediaServerItem.getId(), mediaServerItem.getIp(), mediaServerItem.getHttpPort());
|
||||||
|
zlmresTfulUtils.restartServer(mediaServerItem);
|
||||||
|
}else {
|
||||||
|
logger.info("[媒体服务节点] 设置成功 {} -> {}:{}",
|
||||||
|
mediaServerItem.getId(), mediaServerItem.getIp(), mediaServerItem.getHttpPort());
|
||||||
|
}
|
||||||
|
}else {
|
||||||
|
logger.info("[媒体服务节点] 设置媒体服务节点失败 {} -> {}:{}",
|
||||||
|
mediaServerItem.getId(), mediaServerItem.getIp(), mediaServerItem.getHttpPort());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -2,7 +2,7 @@ package com.genersoft.iot.vmp.media.zlm;
|
|||||||
|
|
||||||
import com.alibaba.fastjson2.JSON;
|
import com.alibaba.fastjson2.JSON;
|
||||||
import com.alibaba.fastjson2.JSONObject;
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
import com.genersoft.iot.vmp.media.bean.MediaServer;
|
||||||
import okhttp3.*;
|
import okhttp3.*;
|
||||||
import okhttp3.logging.HttpLoggingInterceptor;
|
import okhttp3.logging.HttpLoggingInterceptor;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
@ -60,12 +60,12 @@ public class ZLMRESTfulUtils {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public JSONObject sendPost(MediaServerItem mediaServerItem, String api, Map<String, Object> param, RequestCallback callback) {
|
public JSONObject sendPost(MediaServer mediaServerItem, String api, Map<String, Object> param, RequestCallback callback) {
|
||||||
return sendPost(mediaServerItem, api, param, callback, null);
|
return sendPost(mediaServerItem, api, param, callback, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public JSONObject sendPost(MediaServerItem mediaServerItem, String api, Map<String, Object> param, RequestCallback callback, Integer readTimeOut) {
|
public JSONObject sendPost(MediaServer mediaServerItem, String api, Map<String, Object> param, RequestCallback callback, Integer readTimeOut) {
|
||||||
OkHttpClient client = getClient(readTimeOut);
|
OkHttpClient client = getClient(readTimeOut);
|
||||||
|
|
||||||
if (mediaServerItem == null) {
|
if (mediaServerItem == null) {
|
||||||
@ -104,8 +104,6 @@ public class ZLMRESTfulUtils {
|
|||||||
responseJSON = JSON.parseObject(responseStr);
|
responseJSON = JSON.parseObject(responseStr);
|
||||||
}
|
}
|
||||||
}else {
|
}else {
|
||||||
System.out.println( 2222);
|
|
||||||
System.out.println( response.code());
|
|
||||||
response.close();
|
response.close();
|
||||||
Objects.requireNonNull(response.body()).close();
|
Objects.requireNonNull(response.body()).close();
|
||||||
}
|
}
|
||||||
@ -164,7 +162,7 @@ public class ZLMRESTfulUtils {
|
|||||||
return responseJSON;
|
return responseJSON;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void sendGetForImg(MediaServerItem mediaServerItem, String api, Map<String, Object> params, String targetPath, String fileName) {
|
public void sendGetForImg(MediaServer mediaServerItem, String api, Map<String, Object> params, String targetPath, String fileName) {
|
||||||
String url = String.format("http://%s:%s/index/api/%s", mediaServerItem.getIp(), mediaServerItem.getHttpPort(), api);
|
String url = String.format("http://%s:%s/index/api/%s", mediaServerItem.getIp(), mediaServerItem.getHttpPort(), api);
|
||||||
HttpUrl parseUrl = HttpUrl.parse(url);
|
HttpUrl parseUrl = HttpUrl.parse(url);
|
||||||
if (parseUrl == null) {
|
if (parseUrl == null) {
|
||||||
@ -216,7 +214,7 @@ public class ZLMRESTfulUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public JSONObject isMediaOnline(MediaServerItem mediaServerItem, String app, String stream, String schema){
|
public JSONObject isMediaOnline(MediaServer mediaServerItem, String app, String stream, String schema){
|
||||||
Map<String, Object> param = new HashMap<>();
|
Map<String, Object> param = new HashMap<>();
|
||||||
if (app != null) {
|
if (app != null) {
|
||||||
param.put("app",app);
|
param.put("app",app);
|
||||||
@ -231,7 +229,7 @@ public class ZLMRESTfulUtils {
|
|||||||
return sendPost(mediaServerItem, "isMediaOnline", param, null);
|
return sendPost(mediaServerItem, "isMediaOnline", param, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public JSONObject getMediaList(MediaServerItem mediaServerItem, String app, String stream, String schema, RequestCallback callback){
|
public JSONObject getMediaList(MediaServer mediaServerItem, String app, String stream, String schema, RequestCallback callback){
|
||||||
Map<String, Object> param = new HashMap<>();
|
Map<String, Object> param = new HashMap<>();
|
||||||
if (app != null) {
|
if (app != null) {
|
||||||
param.put("app",app);
|
param.put("app",app);
|
||||||
@ -246,15 +244,15 @@ public class ZLMRESTfulUtils {
|
|||||||
return sendPost(mediaServerItem, "getMediaList",param, callback);
|
return sendPost(mediaServerItem, "getMediaList",param, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
public JSONObject getMediaList(MediaServerItem mediaServerItem, String app, String stream){
|
public JSONObject getMediaList(MediaServer mediaServerItem, String app, String stream){
|
||||||
return getMediaList(mediaServerItem, app, stream,null, null);
|
return getMediaList(mediaServerItem, app, stream,null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public JSONObject getMediaList(MediaServerItem mediaServerItem, RequestCallback callback){
|
public JSONObject getMediaList(MediaServer mediaServerItem, RequestCallback callback){
|
||||||
return sendPost(mediaServerItem, "getMediaList",null, callback);
|
return sendPost(mediaServerItem, "getMediaList",null, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
public JSONObject getMediaInfo(MediaServerItem mediaServerItem, String app, String schema, String stream){
|
public JSONObject getMediaInfo(MediaServer mediaServerItem, String app, String schema, String stream){
|
||||||
Map<String, Object> param = new HashMap<>();
|
Map<String, Object> param = new HashMap<>();
|
||||||
param.put("app",app);
|
param.put("app",app);
|
||||||
param.put("schema",schema);
|
param.put("schema",schema);
|
||||||
@ -263,13 +261,13 @@ public class ZLMRESTfulUtils {
|
|||||||
return sendPost(mediaServerItem, "getMediaInfo",param, null);
|
return sendPost(mediaServerItem, "getMediaInfo",param, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public JSONObject getRtpInfo(MediaServerItem mediaServerItem, String stream_id){
|
public JSONObject getRtpInfo(MediaServer mediaServerItem, String stream_id){
|
||||||
Map<String, Object> param = new HashMap<>();
|
Map<String, Object> param = new HashMap<>();
|
||||||
param.put("stream_id",stream_id);
|
param.put("stream_id",stream_id);
|
||||||
return sendPost(mediaServerItem, "getRtpInfo",param, null);
|
return sendPost(mediaServerItem, "getRtpInfo",param, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public JSONObject addFFmpegSource(MediaServerItem mediaServerItem, String src_url, String dst_url, String timeout_ms,
|
public JSONObject addFFmpegSource(MediaServer mediaServerItem, String src_url, String dst_url, Integer timeout_ms,
|
||||||
boolean enable_audio, boolean enable_mp4, String ffmpeg_cmd_key){
|
boolean enable_audio, boolean enable_mp4, String ffmpeg_cmd_key){
|
||||||
logger.info(src_url);
|
logger.info(src_url);
|
||||||
logger.info(dst_url);
|
logger.info(dst_url);
|
||||||
@ -282,63 +280,63 @@ public class ZLMRESTfulUtils {
|
|||||||
return sendPost(mediaServerItem, "addFFmpegSource",param, null);
|
return sendPost(mediaServerItem, "addFFmpegSource",param, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public JSONObject delFFmpegSource(MediaServerItem mediaServerItem, String key){
|
public JSONObject delFFmpegSource(MediaServer mediaServerItem, String key){
|
||||||
Map<String, Object> param = new HashMap<>();
|
Map<String, Object> param = new HashMap<>();
|
||||||
param.put("key", key);
|
param.put("key", key);
|
||||||
return sendPost(mediaServerItem, "delFFmpegSource",param, null);
|
return sendPost(mediaServerItem, "delFFmpegSource",param, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public JSONObject delStreamProxy(MediaServerItem mediaServerItem, String key){
|
public JSONObject delStreamProxy(MediaServer mediaServerItem, String key){
|
||||||
Map<String, Object> param = new HashMap<>();
|
Map<String, Object> param = new HashMap<>();
|
||||||
param.put("key", key);
|
param.put("key", key);
|
||||||
return sendPost(mediaServerItem, "delStreamProxy",param, null);
|
return sendPost(mediaServerItem, "delStreamProxy",param, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public JSONObject getMediaServerConfig(MediaServerItem mediaServerItem){
|
public JSONObject getMediaServerConfig(MediaServer mediaServerItem){
|
||||||
return sendPost(mediaServerItem, "getServerConfig",null, null);
|
return sendPost(mediaServerItem, "getServerConfig",null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public JSONObject setServerConfig(MediaServerItem mediaServerItem, Map<String, Object> param){
|
public JSONObject setServerConfig(MediaServer mediaServerItem, Map<String, Object> param){
|
||||||
return sendPost(mediaServerItem,"setServerConfig",param, null);
|
return sendPost(mediaServerItem,"setServerConfig",param, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public JSONObject openRtpServer(MediaServerItem mediaServerItem, Map<String, Object> param){
|
public JSONObject openRtpServer(MediaServer mediaServerItem, Map<String, Object> param){
|
||||||
return sendPost(mediaServerItem, "openRtpServer",param, null);
|
return sendPost(mediaServerItem, "openRtpServer",param, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public JSONObject closeRtpServer(MediaServerItem mediaServerItem, Map<String, Object> param) {
|
public JSONObject closeRtpServer(MediaServer mediaServerItem, Map<String, Object> param) {
|
||||||
return sendPost(mediaServerItem, "closeRtpServer",param, null);
|
return sendPost(mediaServerItem, "closeRtpServer",param, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void closeRtpServer(MediaServerItem mediaServerItem, Map<String, Object> param, RequestCallback callback) {
|
public void closeRtpServer(MediaServer mediaServerItem, Map<String, Object> param, RequestCallback callback) {
|
||||||
sendPost(mediaServerItem, "closeRtpServer",param, callback);
|
sendPost(mediaServerItem, "closeRtpServer",param, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
public JSONObject listRtpServer(MediaServerItem mediaServerItem) {
|
public JSONObject listRtpServer(MediaServer mediaServerItem) {
|
||||||
return sendPost(mediaServerItem, "listRtpServer",null, null);
|
return sendPost(mediaServerItem, "listRtpServer",null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public JSONObject startSendRtp(MediaServerItem mediaServerItem, Map<String, Object> param) {
|
public JSONObject startSendRtp(MediaServer mediaServerItem, Map<String, Object> param) {
|
||||||
return sendPost(mediaServerItem, "startSendRtp",param, null);
|
return sendPost(mediaServerItem, "startSendRtp",param, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public JSONObject startSendRtpPassive(MediaServerItem mediaServerItem, Map<String, Object> param) {
|
public JSONObject startSendRtpPassive(MediaServer mediaServerItem, Map<String, Object> param) {
|
||||||
return sendPost(mediaServerItem, "startSendRtpPassive",param, null);
|
return sendPost(mediaServerItem, "startSendRtpPassive",param, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public JSONObject startSendRtpPassive(MediaServerItem mediaServerItem, Map<String, Object> param, RequestCallback callback) {
|
public JSONObject startSendRtpPassive(MediaServer mediaServerItem, Map<String, Object> param, RequestCallback callback) {
|
||||||
return sendPost(mediaServerItem, "startSendRtpPassive",param, callback);
|
return sendPost(mediaServerItem, "startSendRtpPassive",param, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
public JSONObject stopSendRtp(MediaServerItem mediaServerItem, Map<String, Object> param) {
|
public JSONObject stopSendRtp(MediaServer mediaServerItem, Map<String, Object> param) {
|
||||||
return sendPost(mediaServerItem, "stopSendRtp",param, null);
|
return sendPost(mediaServerItem, "stopSendRtp",param, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public JSONObject restartServer(MediaServerItem mediaServerItem) {
|
public JSONObject restartServer(MediaServer mediaServerItem) {
|
||||||
return sendPost(mediaServerItem, "restartServer",null, null);
|
return sendPost(mediaServerItem, "restartServer",null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public JSONObject addStreamProxy(MediaServerItem mediaServerItem, String app, String stream, String url, boolean enable_audio, boolean enable_mp4, String rtp_type) {
|
public JSONObject addStreamProxy(MediaServer mediaServerItem, String app, String stream, String url, boolean enable_audio, boolean enable_mp4, String rtp_type) {
|
||||||
Map<String, Object> param = new HashMap<>();
|
Map<String, Object> param = new HashMap<>();
|
||||||
param.put("vhost", "__defaultVhost__");
|
param.put("vhost", "__defaultVhost__");
|
||||||
param.put("app", app);
|
param.put("app", app);
|
||||||
@ -350,7 +348,7 @@ public class ZLMRESTfulUtils {
|
|||||||
return sendPost(mediaServerItem, "addStreamProxy",param, null, 20);
|
return sendPost(mediaServerItem, "addStreamProxy",param, null, 20);
|
||||||
}
|
}
|
||||||
|
|
||||||
public JSONObject closeStreams(MediaServerItem mediaServerItem, String app, String stream) {
|
public JSONObject closeStreams(MediaServer mediaServerItem, String app, String stream) {
|
||||||
Map<String, Object> param = new HashMap<>();
|
Map<String, Object> param = new HashMap<>();
|
||||||
param.put("vhost", "__defaultVhost__");
|
param.put("vhost", "__defaultVhost__");
|
||||||
param.put("app", app);
|
param.put("app", app);
|
||||||
@ -359,17 +357,17 @@ public class ZLMRESTfulUtils {
|
|||||||
return sendPost(mediaServerItem, "close_streams",param, null);
|
return sendPost(mediaServerItem, "close_streams",param, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public JSONObject getAllSession(MediaServerItem mediaServerItem) {
|
public JSONObject getAllSession(MediaServer mediaServerItem) {
|
||||||
return sendPost(mediaServerItem, "getAllSession",null, null);
|
return sendPost(mediaServerItem, "getAllSession",null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void kickSessions(MediaServerItem mediaServerItem, String localPortSStr) {
|
public void kickSessions(MediaServer mediaServerItem, String localPortSStr) {
|
||||||
Map<String, Object> param = new HashMap<>();
|
Map<String, Object> param = new HashMap<>();
|
||||||
param.put("local_port", localPortSStr);
|
param.put("local_port", localPortSStr);
|
||||||
sendPost(mediaServerItem, "kick_sessions",param, null);
|
sendPost(mediaServerItem, "kick_sessions",param, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void getSnap(MediaServerItem mediaServerItem, String streamUrl, int timeout_sec, int expire_sec, String targetPath, String fileName) {
|
public void getSnap(MediaServer mediaServerItem, String streamUrl, int timeout_sec, int expire_sec, String targetPath, String fileName) {
|
||||||
Map<String, Object> param = new HashMap<>(3);
|
Map<String, Object> param = new HashMap<>(3);
|
||||||
param.put("url", streamUrl);
|
param.put("url", streamUrl);
|
||||||
param.put("timeout_sec", timeout_sec);
|
param.put("timeout_sec", timeout_sec);
|
||||||
@ -377,19 +375,19 @@ public class ZLMRESTfulUtils {
|
|||||||
sendGetForImg(mediaServerItem, "getSnap", param, targetPath, fileName);
|
sendGetForImg(mediaServerItem, "getSnap", param, targetPath, fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public JSONObject pauseRtpCheck(MediaServerItem mediaServerItem, String streamId) {
|
public JSONObject pauseRtpCheck(MediaServer mediaServerItem, String streamId) {
|
||||||
Map<String, Object> param = new HashMap<>(1);
|
Map<String, Object> param = new HashMap<>(1);
|
||||||
param.put("stream_id", streamId);
|
param.put("stream_id", streamId);
|
||||||
return sendPost(mediaServerItem, "pauseRtpCheck",param, null);
|
return sendPost(mediaServerItem, "pauseRtpCheck",param, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public JSONObject resumeRtpCheck(MediaServerItem mediaServerItem, String streamId) {
|
public JSONObject resumeRtpCheck(MediaServer mediaServerItem, String streamId) {
|
||||||
Map<String, Object> param = new HashMap<>(1);
|
Map<String, Object> param = new HashMap<>(1);
|
||||||
param.put("stream_id", streamId);
|
param.put("stream_id", streamId);
|
||||||
return sendPost(mediaServerItem, "resumeRtpCheck",param, null);
|
return sendPost(mediaServerItem, "resumeRtpCheck",param, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public JSONObject connectRtpServer(MediaServerItem mediaServerItem, String dst_url, int dst_port, String stream_id) {
|
public JSONObject connectRtpServer(MediaServer mediaServerItem, String dst_url, int dst_port, String stream_id) {
|
||||||
Map<String, Object> param = new HashMap<>(1);
|
Map<String, Object> param = new HashMap<>(1);
|
||||||
param.put("dst_url", dst_url);
|
param.put("dst_url", dst_url);
|
||||||
param.put("dst_port", dst_port);
|
param.put("dst_port", dst_port);
|
||||||
@ -397,14 +395,14 @@ public class ZLMRESTfulUtils {
|
|||||||
return sendPost(mediaServerItem, "connectRtpServer",param, null);
|
return sendPost(mediaServerItem, "connectRtpServer",param, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public JSONObject updateRtpServerSSRC(MediaServerItem mediaServerItem, String streamId, String ssrc) {
|
public JSONObject updateRtpServerSSRC(MediaServer mediaServerItem, String streamId, String ssrc) {
|
||||||
Map<String, Object> param = new HashMap<>(1);
|
Map<String, Object> param = new HashMap<>(1);
|
||||||
param.put("ssrc", ssrc);
|
param.put("ssrc", ssrc);
|
||||||
param.put("stream_id", streamId);
|
param.put("stream_id", streamId);
|
||||||
return sendPost(mediaServerItem, "updateRtpServerSSRC",param, null);
|
return sendPost(mediaServerItem, "updateRtpServerSSRC",param, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public JSONObject deleteRecordDirectory(MediaServerItem mediaServerItem, String app, String stream, String date, String fileName) {
|
public JSONObject deleteRecordDirectory(MediaServer mediaServerItem, String app, String stream, String date, String fileName) {
|
||||||
Map<String, Object> param = new HashMap<>(1);
|
Map<String, Object> param = new HashMap<>(1);
|
||||||
param.put("vhost", "__defaultVhost__");
|
param.put("vhost", "__defaultVhost__");
|
||||||
param.put("app", app);
|
param.put("app", app);
|
||||||
|
|||||||
@ -1,173 +0,0 @@
|
|||||||
package com.genersoft.iot.vmp.media.zlm;
|
|
||||||
|
|
||||||
import com.alibaba.fastjson2.JSON;
|
|
||||||
import com.alibaba.fastjson2.JSONArray;
|
|
||||||
import com.alibaba.fastjson2.JSONObject;
|
|
||||||
import com.genersoft.iot.vmp.conf.DynamicTask;
|
|
||||||
import com.genersoft.iot.vmp.conf.MediaConfig;
|
|
||||||
import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
|
|
||||||
import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeFactory;
|
|
||||||
import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForServerStarted;
|
|
||||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
|
||||||
import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem;
|
|
||||||
import com.genersoft.iot.vmp.service.IMediaServerService;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.boot.CommandLineRunner;
|
|
||||||
import org.springframework.core.annotation.Order;
|
|
||||||
import org.springframework.scheduling.annotation.Async;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
|
|
||||||
@Component
|
|
||||||
@Order(value=12)
|
|
||||||
public class ZLMRunner implements CommandLineRunner {
|
|
||||||
|
|
||||||
private final static Logger logger = LoggerFactory.getLogger(ZLMRunner.class);
|
|
||||||
|
|
||||||
private Map<String, Boolean> startGetMedia;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private ZLMRESTfulUtils zlmresTfulUtils;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private ZlmHttpHookSubscribe hookSubscribe;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private EventPublisher publisher;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private IMediaServerService mediaServerService;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private MediaConfig mediaConfig;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private DynamicTask dynamicTask;
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run(String... strings) throws Exception {
|
|
||||||
mediaServerService.clearMediaServerForOnline();
|
|
||||||
MediaServerItem defaultMediaServer = mediaServerService.getDefaultMediaServer();
|
|
||||||
if (defaultMediaServer == null) {
|
|
||||||
mediaServerService.addToDatabase(mediaConfig.getMediaSerItem());
|
|
||||||
}else {
|
|
||||||
MediaServerItem mediaSerItem = mediaConfig.getMediaSerItem();
|
|
||||||
mediaServerService.updateToDatabase(mediaSerItem);
|
|
||||||
}
|
|
||||||
mediaServerService.syncCatchFromDatabase();
|
|
||||||
HookSubscribeForServerStarted hookSubscribeForServerStarted = HookSubscribeFactory.on_server_started();
|
|
||||||
// 订阅 zlm启动事件, 新的zlm也会从这里进入系统
|
|
||||||
hookSubscribe.addSubscribe(hookSubscribeForServerStarted,
|
|
||||||
(mediaServerItem, hookParam)->{
|
|
||||||
ZLMServerConfig zlmServerConfig = (ZLMServerConfig)hookParam;
|
|
||||||
if (zlmServerConfig !=null ) {
|
|
||||||
if (startGetMedia != null) {
|
|
||||||
startGetMedia.remove(zlmServerConfig.getGeneralMediaServerId());
|
|
||||||
if (startGetMedia.size() == 0) {
|
|
||||||
hookSubscribe.removeSubscribe(HookSubscribeFactory.on_server_started());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// 获取zlm信息
|
|
||||||
logger.info("[zlm] 等待默认zlm中...");
|
|
||||||
|
|
||||||
// 获取所有的zlm, 并开启主动连接
|
|
||||||
List<MediaServerItem> all = mediaServerService.getAllFromDatabase();
|
|
||||||
Map<String, MediaServerItem> allMap = new HashMap<>();
|
|
||||||
mediaServerService.updateVmServer(all);
|
|
||||||
if (all.size() == 0) {
|
|
||||||
all.add(mediaConfig.getMediaSerItem());
|
|
||||||
}
|
|
||||||
for (MediaServerItem mediaServerItem : all) {
|
|
||||||
if (startGetMedia == null) {
|
|
||||||
startGetMedia = new ConcurrentHashMap<>();
|
|
||||||
}
|
|
||||||
startGetMedia.put(mediaServerItem.getId(), true);
|
|
||||||
connectZlmServer(mediaServerItem);
|
|
||||||
allMap.put(mediaServerItem.getId(), mediaServerItem);
|
|
||||||
}
|
|
||||||
String taskKey = "zlm-connect-timeout";
|
|
||||||
dynamicTask.startDelay(taskKey, ()->{
|
|
||||||
if (startGetMedia != null && startGetMedia.size() > 0) {
|
|
||||||
Set<String> allZlmId = startGetMedia.keySet();
|
|
||||||
for (String id : allZlmId) {
|
|
||||||
logger.error("[ {} ]]主动连接失败,不再尝试连接", id);
|
|
||||||
}
|
|
||||||
startGetMedia = null;
|
|
||||||
}
|
|
||||||
// 获取redis中所有的zlm
|
|
||||||
List<MediaServerItem> allInRedis = mediaServerService.getAll();
|
|
||||||
for (MediaServerItem mediaServerItem : allInRedis) {
|
|
||||||
if (!allMap.containsKey(mediaServerItem.getId())) {
|
|
||||||
mediaServerService.delete(mediaServerItem.getId());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, 60 * 1000 );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Async("taskExecutor")
|
|
||||||
public void connectZlmServer(MediaServerItem mediaServerItem){
|
|
||||||
String connectZlmServerTaskKey = "connect-zlm-" + mediaServerItem.getId();
|
|
||||||
ZLMServerConfig zlmServerConfigFirst = getMediaServerConfig(mediaServerItem);
|
|
||||||
if (zlmServerConfigFirst != null) {
|
|
||||||
zlmServerConfigFirst.setIp(mediaServerItem.getIp());
|
|
||||||
zlmServerConfigFirst.setHttpPort(mediaServerItem.getHttpPort());
|
|
||||||
startGetMedia.remove(mediaServerItem.getId());
|
|
||||||
if (startGetMedia.size() == 0) {
|
|
||||||
hookSubscribe.removeSubscribe(HookSubscribeFactory.on_server_started());
|
|
||||||
}
|
|
||||||
mediaServerService.zlmServerOnline(zlmServerConfigFirst);
|
|
||||||
}else {
|
|
||||||
logger.info("[ {} ]-[ {}:{} ]主动连接失败, 清理相关资源, 开始尝试重试连接",
|
|
||||||
mediaServerItem.getId(), mediaServerItem.getIp(), mediaServerItem.getHttpPort());
|
|
||||||
publisher.zlmOfflineEventPublish(mediaServerItem.getId());
|
|
||||||
}
|
|
||||||
|
|
||||||
dynamicTask.startCron(connectZlmServerTaskKey, ()->{
|
|
||||||
ZLMServerConfig zlmServerConfig = getMediaServerConfig(mediaServerItem);
|
|
||||||
if (zlmServerConfig != null) {
|
|
||||||
dynamicTask.stop(connectZlmServerTaskKey);
|
|
||||||
zlmServerConfig.setIp(mediaServerItem.getIp());
|
|
||||||
zlmServerConfig.setHttpPort(mediaServerItem.getHttpPort());
|
|
||||||
startGetMedia.remove(mediaServerItem.getId());
|
|
||||||
if (startGetMedia.size() == 0) {
|
|
||||||
hookSubscribe.removeSubscribe(HookSubscribeFactory.on_server_started());
|
|
||||||
}
|
|
||||||
mediaServerService.zlmServerOnline(zlmServerConfig);
|
|
||||||
}
|
|
||||||
}, 2000);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ZLMServerConfig getMediaServerConfig(MediaServerItem mediaServerItem) {
|
|
||||||
if (startGetMedia == null) { return null;}
|
|
||||||
if (!mediaServerItem.isDefaultServer() && mediaServerService.getOne(mediaServerItem.getId()) == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
if ( startGetMedia.get(mediaServerItem.getId()) == null || !startGetMedia.get(mediaServerItem.getId())) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
JSONObject responseJson = zlmresTfulUtils.getMediaServerConfig(mediaServerItem);
|
|
||||||
ZLMServerConfig zlmServerConfig = null;
|
|
||||||
if (responseJson != null) {
|
|
||||||
JSONArray data = responseJson.getJSONArray("data");
|
|
||||||
if (data != null && data.size() > 0) {
|
|
||||||
zlmServerConfig = JSON.parseObject(JSON.toJSONString(data.get(0)), ZLMServerConfig.class);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
logger.error("[ {} ]-[ {}:{} ]主动连接失败, 2s后重试",
|
|
||||||
mediaServerItem.getId(), mediaServerItem.getIp(), mediaServerItem.getHttpPort());
|
|
||||||
}
|
|
||||||
return zlmServerConfig;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -5,7 +5,7 @@ import com.alibaba.fastjson2.JSONObject;
|
|||||||
import com.genersoft.iot.vmp.common.CommonCallback;
|
import com.genersoft.iot.vmp.common.CommonCallback;
|
||||||
import com.genersoft.iot.vmp.conf.UserSetting;
|
import com.genersoft.iot.vmp.conf.UserSetting;
|
||||||
import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
|
import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
|
||||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
import com.genersoft.iot.vmp.media.bean.MediaServer;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
@ -17,7 +17,7 @@ import java.util.Map;
|
|||||||
@Component
|
@Component
|
||||||
public class ZLMServerFactory {
|
public class ZLMServerFactory {
|
||||||
|
|
||||||
private Logger logger = LoggerFactory.getLogger("ZLMRTPServerFactory");
|
private Logger logger = LoggerFactory.getLogger("ZLMServerFactory");
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private ZLMRESTfulUtils zlmresTfulUtils;
|
private ZLMRESTfulUtils zlmresTfulUtils;
|
||||||
@ -25,9 +25,6 @@ public class ZLMServerFactory {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private UserSetting userSetting;
|
private UserSetting userSetting;
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private ZlmHttpHookSubscribe hookSubscribe;
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private SendRtpPortManager sendRtpPortManager;
|
private SendRtpPortManager sendRtpPortManager;
|
||||||
|
|
||||||
@ -42,7 +39,7 @@ public class ZLMServerFactory {
|
|||||||
* @param tcpMode 0/null udp 模式,1 tcp 被动模式, 2 tcp 主动模式。
|
* @param tcpMode 0/null udp 模式,1 tcp 被动模式, 2 tcp 主动模式。
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public int createRTPServer(MediaServerItem mediaServerItem, String streamId, long ssrc, Integer port, Boolean onlyAuto, Boolean reUsePort, Integer tcpMode) {
|
public int createRTPServer(MediaServer mediaServerItem, String streamId, long ssrc, Integer port, Boolean onlyAuto, Boolean reUsePort, Integer tcpMode) {
|
||||||
int result = -1;
|
int result = -1;
|
||||||
// 查询此rtp server 是否已经存在
|
// 查询此rtp server 是否已经存在
|
||||||
JSONObject rtpInfo = zlmresTfulUtils.getRtpInfo(mediaServerItem, streamId);
|
JSONObject rtpInfo = zlmresTfulUtils.getRtpInfo(mediaServerItem, streamId);
|
||||||
@ -108,7 +105,7 @@ public class ZLMServerFactory {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean closeRtpServer(MediaServerItem serverItem, String streamId) {
|
public boolean closeRtpServer(MediaServer serverItem, String streamId) {
|
||||||
boolean result = false;
|
boolean result = false;
|
||||||
if (serverItem !=null){
|
if (serverItem !=null){
|
||||||
Map<String, Object> param = new HashMap<>();
|
Map<String, Object> param = new HashMap<>();
|
||||||
@ -129,7 +126,7 @@ public class ZLMServerFactory {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void closeRtpServer(MediaServerItem serverItem, String streamId, CommonCallback<Boolean> callback) {
|
public void closeRtpServer(MediaServer serverItem, String streamId, CommonCallback<Boolean> callback) {
|
||||||
if (serverItem == null) {
|
if (serverItem == null) {
|
||||||
callback.run(false);
|
callback.run(false);
|
||||||
return;
|
return;
|
||||||
@ -155,105 +152,28 @@ public class ZLMServerFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 创建一个国标推流
|
|
||||||
* @param ip 推流ip
|
|
||||||
* @param port 推流端口
|
|
||||||
* @param ssrc 推流唯一标识
|
|
||||||
* @param platformId 平台id
|
|
||||||
* @param channelId 通道id
|
|
||||||
* @param tcp 是否为tcp
|
|
||||||
* @return SendRtpItem
|
|
||||||
*/
|
|
||||||
public SendRtpItem createSendRtpItem(MediaServerItem serverItem, String ip, int port, String ssrc, String platformId,
|
|
||||||
String deviceId, String channelId, boolean tcp, boolean rtcp){
|
|
||||||
|
|
||||||
int localPort = sendRtpPortManager.getNextPort(serverItem);
|
|
||||||
if (localPort == 0) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
SendRtpItem sendRtpItem = new SendRtpItem();
|
|
||||||
sendRtpItem.setIp(ip);
|
|
||||||
sendRtpItem.setPort(port);
|
|
||||||
sendRtpItem.setSsrc(ssrc);
|
|
||||||
sendRtpItem.setPlatformId(platformId);
|
|
||||||
sendRtpItem.setDeviceId(deviceId);
|
|
||||||
sendRtpItem.setChannelId(channelId);
|
|
||||||
sendRtpItem.setTcp(tcp);
|
|
||||||
sendRtpItem.setRtcp(rtcp);
|
|
||||||
sendRtpItem.setApp("rtp");
|
|
||||||
sendRtpItem.setLocalPort(localPort);
|
|
||||||
sendRtpItem.setServerId(userSetting.getServerId());
|
|
||||||
sendRtpItem.setMediaServerId(serverItem.getId());
|
|
||||||
return sendRtpItem;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 创建一个直播推流
|
|
||||||
* @param ip 推流ip
|
|
||||||
* @param port 推流端口
|
|
||||||
* @param ssrc 推流唯一标识
|
|
||||||
* @param platformId 平台id
|
|
||||||
* @param channelId 通道id
|
|
||||||
* @param tcp 是否为tcp
|
|
||||||
* @return SendRtpItem
|
|
||||||
*/
|
|
||||||
public SendRtpItem createSendRtpItem(MediaServerItem serverItem, String ip, int port, String ssrc, String platformId,
|
|
||||||
String app, String stream, String channelId, boolean tcp, boolean rtcp){
|
|
||||||
|
|
||||||
int localPort = sendRtpPortManager.getNextPort(serverItem);
|
|
||||||
if (localPort == 0) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
SendRtpItem sendRtpItem = new SendRtpItem();
|
|
||||||
sendRtpItem.setIp(ip);
|
|
||||||
sendRtpItem.setPort(port);
|
|
||||||
sendRtpItem.setSsrc(ssrc);
|
|
||||||
sendRtpItem.setApp(app);
|
|
||||||
sendRtpItem.setStream(stream);
|
|
||||||
sendRtpItem.setPlatformId(platformId);
|
|
||||||
sendRtpItem.setChannelId(channelId);
|
|
||||||
sendRtpItem.setTcp(tcp);
|
|
||||||
sendRtpItem.setLocalPort(localPort);
|
|
||||||
sendRtpItem.setServerId(userSetting.getServerId());
|
|
||||||
sendRtpItem.setMediaServerId(serverItem.getId());
|
|
||||||
sendRtpItem.setRtcp(rtcp);
|
|
||||||
return sendRtpItem;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 调用zlm RESTFUL API —— startSendRtp
|
* 调用zlm RESTFUL API —— startSendRtp
|
||||||
*/
|
*/
|
||||||
public JSONObject startSendRtpStream(MediaServerItem mediaServerItem, Map<String, Object>param) {
|
public JSONObject startSendRtpStream(MediaServer mediaServerItem, Map<String, Object>param) {
|
||||||
return zlmresTfulUtils.startSendRtp(mediaServerItem, param);
|
return zlmresTfulUtils.startSendRtp(mediaServerItem, param);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 调用zlm RESTFUL API —— startSendRtpPassive
|
* 调用zlm RESTFUL API —— startSendRtpPassive
|
||||||
*/
|
*/
|
||||||
public JSONObject startSendRtpPassive(MediaServerItem mediaServerItem, Map<String, Object>param) {
|
public JSONObject startSendRtpPassive(MediaServer mediaServerItem, Map<String, Object>param) {
|
||||||
return zlmresTfulUtils.startSendRtpPassive(mediaServerItem, param);
|
return zlmresTfulUtils.startSendRtpPassive(mediaServerItem, param);
|
||||||
}
|
}
|
||||||
|
|
||||||
public JSONObject startSendRtpPassive(MediaServerItem mediaServerItem, Map<String, Object>param, ZLMRESTfulUtils.RequestCallback callback) {
|
public JSONObject startSendRtpPassive(MediaServer mediaServerItem, Map<String, Object>param, ZLMRESTfulUtils.RequestCallback callback) {
|
||||||
return zlmresTfulUtils.startSendRtpPassive(mediaServerItem, param, callback);
|
return zlmresTfulUtils.startSendRtpPassive(mediaServerItem, param, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询待转推的流是否就绪
|
* 查询待转推的流是否就绪
|
||||||
*/
|
*/
|
||||||
public Boolean isRtpReady(MediaServerItem mediaServerItem, String streamId) {
|
public Boolean isStreamReady(MediaServer mediaServerItem, String app, String streamId) {
|
||||||
JSONObject mediaInfo = zlmresTfulUtils.getMediaInfo(mediaServerItem,"rtp", "rtsp", streamId);
|
|
||||||
if (mediaInfo.getInteger("code") == -2) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return (mediaInfo.getInteger("code") == 0 && mediaInfo.getBoolean("online"));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 查询待转推的流是否就绪
|
|
||||||
*/
|
|
||||||
public Boolean isStreamReady(MediaServerItem mediaServerItem, String app, String streamId) {
|
|
||||||
JSONObject mediaInfo = zlmresTfulUtils.getMediaList(mediaServerItem, app, streamId);
|
JSONObject mediaInfo = zlmresTfulUtils.getMediaList(mediaServerItem, app, streamId);
|
||||||
if (mediaInfo == null || (mediaInfo.getInteger("code") == -2)) {
|
if (mediaInfo == null || (mediaInfo.getInteger("code") == -2)) {
|
||||||
return null;
|
return null;
|
||||||
@ -268,7 +188,7 @@ public class ZLMServerFactory {
|
|||||||
* @param streamId
|
* @param streamId
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public int totalReaderCount(MediaServerItem mediaServerItem, String app, String streamId) {
|
public int totalReaderCount(MediaServer mediaServerItem, String app, String streamId) {
|
||||||
JSONObject mediaInfo = zlmresTfulUtils.getMediaInfo(mediaServerItem, app, "rtsp", streamId);
|
JSONObject mediaInfo = zlmresTfulUtils.getMediaInfo(mediaServerItem, app, "rtsp", streamId);
|
||||||
if (mediaInfo == null) {
|
if (mediaInfo == null) {
|
||||||
return 0;
|
return 0;
|
||||||
@ -285,28 +205,7 @@ public class ZLMServerFactory {
|
|||||||
return mediaInfo.getInteger("totalReaderCount");
|
return mediaInfo.getInteger("totalReaderCount");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public JSONObject startSendRtp(MediaServer mediaInfo, SendRtpItem sendRtpItem) {
|
||||||
* 调用zlm RESTful API —— stopSendRtp
|
|
||||||
*/
|
|
||||||
public Boolean stopSendRtpStream(MediaServerItem mediaServerItem, Map<String, Object>param) {
|
|
||||||
if (mediaServerItem == null) {
|
|
||||||
logger.error("[停止RTP推流] 失败: 媒体节点为NULL");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
Boolean result = false;
|
|
||||||
JSONObject jsonObject = zlmresTfulUtils.stopSendRtp(mediaServerItem, param);
|
|
||||||
if (jsonObject == null) {
|
|
||||||
logger.error("[停止RTP推流] 失败: 请检查ZLM服务");
|
|
||||||
} else if (jsonObject.getInteger("code") == 0) {
|
|
||||||
result= true;
|
|
||||||
logger.info("[停止RTP推流] 成功");
|
|
||||||
} else {
|
|
||||||
logger.warn("[停止RTP推流] 失败: {}, 参数:{}->\r\n{}",jsonObject.getString("msg"), JSON.toJSON(param), jsonObject);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public JSONObject startSendRtp(MediaServerItem mediaInfo, SendRtpItem sendRtpItem) {
|
|
||||||
String is_Udp = sendRtpItem.isTcp() ? "0" : "1";
|
String is_Udp = sendRtpItem.isTcp() ? "0" : "1";
|
||||||
logger.info("rtp/{}开始推流, 目标={}:{},SSRC={}", sendRtpItem.getStream(), sendRtpItem.getIp(), sendRtpItem.getPort(), sendRtpItem.getSsrc());
|
logger.info("rtp/{}开始推流, 目标={}:{},SSRC={}", sendRtpItem.getStream(), sendRtpItem.getIp(), sendRtpItem.getPort(), sendRtpItem.getSsrc());
|
||||||
Map<String, Object> param = new HashMap<>(12);
|
Map<String, Object> param = new HashMap<>(12);
|
||||||
@ -351,7 +250,7 @@ public class ZLMServerFactory {
|
|||||||
return startSendRtpStreamResult;
|
return startSendRtpStreamResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Boolean updateRtpServerSSRC(MediaServerItem mediaServerItem, String streamId, String ssrc) {
|
public Boolean updateRtpServerSSRC(MediaServer mediaServerItem, String streamId, String ssrc) {
|
||||||
boolean result = false;
|
boolean result = false;
|
||||||
JSONObject jsonObject = zlmresTfulUtils.updateRtpServerSSRC(mediaServerItem, streamId, ssrc);
|
JSONObject jsonObject = zlmresTfulUtils.updateRtpServerSSRC(mediaServerItem, streamId, ssrc);
|
||||||
if (jsonObject == null) {
|
if (jsonObject == null) {
|
||||||
|
|||||||
@ -1,161 +0,0 @@
|
|||||||
package com.genersoft.iot.vmp.media.zlm;
|
|
||||||
|
|
||||||
import com.alibaba.fastjson2.JSONObject;
|
|
||||||
import com.genersoft.iot.vmp.media.zlm.dto.HookType;
|
|
||||||
import com.genersoft.iot.vmp.media.zlm.dto.IHookSubscribe;
|
|
||||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
|
||||||
import com.genersoft.iot.vmp.media.zlm.dto.hook.HookParam;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import org.springframework.scheduling.annotation.Scheduled;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
import org.springframework.util.CollectionUtils;
|
|
||||||
|
|
||||||
import java.time.Instant;
|
|
||||||
import java.util.*;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ZLMediaServer的hook事件订阅
|
|
||||||
* @author lin
|
|
||||||
*/
|
|
||||||
@Component
|
|
||||||
public class ZlmHttpHookSubscribe {
|
|
||||||
|
|
||||||
private final static Logger logger = LoggerFactory.getLogger(ZlmHttpHookSubscribe.class);
|
|
||||||
|
|
||||||
@FunctionalInterface
|
|
||||||
public interface Event{
|
|
||||||
void response(MediaServerItem mediaServerItem, HookParam hookParam);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Map<HookType, Map<IHookSubscribe, ZlmHttpHookSubscribe.Event>> allSubscribes = new ConcurrentHashMap<>();
|
|
||||||
|
|
||||||
public void addSubscribe(IHookSubscribe hookSubscribe, ZlmHttpHookSubscribe.Event event) {
|
|
||||||
if (hookSubscribe.getExpires() == null) {
|
|
||||||
// 默认5分钟过期
|
|
||||||
Instant expiresInstant = Instant.now().plusSeconds(TimeUnit.MINUTES.toSeconds(5));
|
|
||||||
hookSubscribe.setExpires(expiresInstant);
|
|
||||||
}
|
|
||||||
allSubscribes.computeIfAbsent(hookSubscribe.getHookType(), k -> new ConcurrentHashMap<>()).put(hookSubscribe, event);
|
|
||||||
System.out.println(allSubscribes);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ZlmHttpHookSubscribe.Event sendNotify(HookType type, JSONObject hookResponse) {
|
|
||||||
ZlmHttpHookSubscribe.Event event= null;
|
|
||||||
Map<IHookSubscribe, Event> eventMap = allSubscribes.get(type);
|
|
||||||
if (eventMap == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
for (IHookSubscribe key : eventMap.keySet()) {
|
|
||||||
Boolean result = null;
|
|
||||||
|
|
||||||
for (String s : key.getContent().keySet()) {
|
|
||||||
if (result == null) {
|
|
||||||
result = key.getContent().getString(s).equals(hookResponse.getString(s));
|
|
||||||
}else {
|
|
||||||
if (key.getContent().getString(s) == null) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
result = result && key.getContent().getString(s).equals(hookResponse.getString(s));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (null != result && result) {
|
|
||||||
event = eventMap.get(key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return event;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void removeSubscribe(IHookSubscribe hookSubscribe) {
|
|
||||||
Map<IHookSubscribe, Event> eventMap = allSubscribes.get(hookSubscribe.getHookType());
|
|
||||||
if (eventMap == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Set<Map.Entry<IHookSubscribe, Event>> entries = eventMap.entrySet();
|
|
||||||
if (entries.size() > 0) {
|
|
||||||
List<Map.Entry<IHookSubscribe, ZlmHttpHookSubscribe.Event>> entriesToRemove = new ArrayList<>();
|
|
||||||
for (Map.Entry<IHookSubscribe, ZlmHttpHookSubscribe.Event> entry : entries) {
|
|
||||||
JSONObject content = entry.getKey().getContent();
|
|
||||||
if (content == null || content.size() == 0) {
|
|
||||||
entriesToRemove.add(entry);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
Boolean result = null;
|
|
||||||
for (String s : content.keySet()) {
|
|
||||||
if (result == null) {
|
|
||||||
result = content.getString(s).equals(hookSubscribe.getContent().getString(s));
|
|
||||||
}else {
|
|
||||||
if (content.getString(s) == null) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
result = result && content.getString(s).equals(hookSubscribe.getContent().getString(s));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (result){
|
|
||||||
entriesToRemove.add(entry);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!CollectionUtils.isEmpty(entriesToRemove)) {
|
|
||||||
for (Map.Entry<IHookSubscribe, ZlmHttpHookSubscribe.Event> entry : entriesToRemove) {
|
|
||||||
eventMap.remove(entry.getKey());
|
|
||||||
}
|
|
||||||
if (eventMap.size() == 0) {
|
|
||||||
allSubscribes.remove(hookSubscribe.getHookType());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取某个类型的所有的订阅
|
|
||||||
* @param type
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public List<ZlmHttpHookSubscribe.Event> getSubscribes(HookType type) {
|
|
||||||
Map<IHookSubscribe, Event> eventMap = allSubscribes.get(type);
|
|
||||||
if (eventMap == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
List<ZlmHttpHookSubscribe.Event> result = new ArrayList<>();
|
|
||||||
for (IHookSubscribe key : eventMap.keySet()) {
|
|
||||||
result.add(eventMap.get(key));
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<IHookSubscribe> getAll(){
|
|
||||||
ArrayList<IHookSubscribe> result = new ArrayList<>();
|
|
||||||
Collection<Map<IHookSubscribe, Event>> values = allSubscribes.values();
|
|
||||||
for (Map<IHookSubscribe, Event> value : values) {
|
|
||||||
result.addAll(value.keySet());
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 对订阅数据进行过期清理
|
|
||||||
*/
|
|
||||||
// @Scheduled(cron="0 0/5 * * * ?") //每5分钟执行一次
|
|
||||||
@Scheduled(fixedRate = 2 * 1000)
|
|
||||||
public void execute(){
|
|
||||||
Instant instant = Instant.now().minusMillis(TimeUnit.MINUTES.toMillis(5));
|
|
||||||
int total = 0;
|
|
||||||
for (HookType hookType : allSubscribes.keySet()) {
|
|
||||||
Map<IHookSubscribe, Event> hookSubscribeEventMap = allSubscribes.get(hookType);
|
|
||||||
if (hookSubscribeEventMap.size() > 0) {
|
|
||||||
for (IHookSubscribe hookSubscribe : hookSubscribeEventMap.keySet()) {
|
|
||||||
if (hookSubscribe.getExpires().isBefore(instant)) {
|
|
||||||
// 过期的
|
|
||||||
hookSubscribeEventMap.remove(hookSubscribe);
|
|
||||||
total ++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,71 +0,0 @@
|
|||||||
package com.genersoft.iot.vmp.media.zlm.dto;
|
|
||||||
|
|
||||||
|
|
||||||
import com.alibaba.fastjson2.JSONObject;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* hook 订阅工厂
|
|
||||||
* @author lin
|
|
||||||
*/
|
|
||||||
public class HookSubscribeFactory {
|
|
||||||
|
|
||||||
public static HookSubscribeForStreamChange on_stream_changed(String app, String stream, boolean regist, String scheam, String mediaServerId) {
|
|
||||||
HookSubscribeForStreamChange hookSubscribe = new HookSubscribeForStreamChange();
|
|
||||||
JSONObject subscribeKey = new com.alibaba.fastjson2.JSONObject();
|
|
||||||
subscribeKey.put("app", app);
|
|
||||||
subscribeKey.put("stream", stream);
|
|
||||||
subscribeKey.put("regist", regist);
|
|
||||||
if (scheam != null) {
|
|
||||||
subscribeKey.put("schema", scheam);
|
|
||||||
}
|
|
||||||
subscribeKey.put("mediaServerId", mediaServerId);
|
|
||||||
hookSubscribe.setContent(subscribeKey);
|
|
||||||
|
|
||||||
return hookSubscribe;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static HookSubscribeForRtpServerTimeout on_rtp_server_timeout(String stream, String ssrc, String mediaServerId) {
|
|
||||||
HookSubscribeForRtpServerTimeout hookSubscribe = new HookSubscribeForRtpServerTimeout();
|
|
||||||
JSONObject subscribeKey = new com.alibaba.fastjson2.JSONObject();
|
|
||||||
subscribeKey.put("stream_id", stream);
|
|
||||||
subscribeKey.put("ssrc", ssrc);
|
|
||||||
subscribeKey.put("mediaServerId", mediaServerId);
|
|
||||||
hookSubscribe.setContent(subscribeKey);
|
|
||||||
|
|
||||||
return hookSubscribe;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static HookSubscribeForStreamPush on_publish(String app, String stream, String scheam, String mediaServerId) {
|
|
||||||
HookSubscribeForStreamPush hookSubscribe = new HookSubscribeForStreamPush();
|
|
||||||
JSONObject subscribeKey = new JSONObject();
|
|
||||||
subscribeKey.put("app", app);
|
|
||||||
subscribeKey.put("stream", stream);
|
|
||||||
if (scheam != null) {
|
|
||||||
subscribeKey.put("schema", scheam);
|
|
||||||
}
|
|
||||||
subscribeKey.put("mediaServerId", mediaServerId);
|
|
||||||
hookSubscribe.setContent(subscribeKey);
|
|
||||||
|
|
||||||
return hookSubscribe;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static HookSubscribeForServerStarted on_server_started() {
|
|
||||||
HookSubscribeForServerStarted hookSubscribe = new HookSubscribeForServerStarted();
|
|
||||||
hookSubscribe.setContent(new JSONObject());
|
|
||||||
|
|
||||||
return hookSubscribe;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static HookSubscribeForRecordMp4 on_record_mp4(String mediaServerId, String app, String stream) {
|
|
||||||
HookSubscribeForRecordMp4 hookSubscribe = new HookSubscribeForRecordMp4();
|
|
||||||
JSONObject subscribeKey = new com.alibaba.fastjson2.JSONObject();
|
|
||||||
subscribeKey.put("app", app);
|
|
||||||
subscribeKey.put("stream", stream);
|
|
||||||
subscribeKey.put("mediaServerId", mediaServerId);
|
|
||||||
hookSubscribe.setContent(subscribeKey);
|
|
||||||
|
|
||||||
return hookSubscribe;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,44 +0,0 @@
|
|||||||
package com.genersoft.iot.vmp.media.zlm.dto;
|
|
||||||
|
|
||||||
import com.alibaba.fastjson2.JSONObject;
|
|
||||||
import com.alibaba.fastjson2.annotation.JSONField;
|
|
||||||
|
|
||||||
import java.time.Instant;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* hook订阅-录像完成
|
|
||||||
* @author lin
|
|
||||||
*/
|
|
||||||
public class HookSubscribeForRecordMp4 implements IHookSubscribe{
|
|
||||||
|
|
||||||
private HookType hookType = HookType.on_record_mp4;
|
|
||||||
|
|
||||||
private JSONObject content;
|
|
||||||
|
|
||||||
@JSONField(format="yyyy-MM-dd HH:mm:ss")
|
|
||||||
private Instant expires;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public HookType getHookType() {
|
|
||||||
return hookType;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public JSONObject getContent() {
|
|
||||||
return content;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setContent(JSONObject content) {
|
|
||||||
this.content = content;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Instant getExpires() {
|
|
||||||
return expires;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setExpires(Instant expires) {
|
|
||||||
this.expires = expires;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,44 +0,0 @@
|
|||||||
package com.genersoft.iot.vmp.media.zlm.dto;
|
|
||||||
|
|
||||||
import com.alibaba.fastjson2.JSONObject;
|
|
||||||
import com.alibaba.fastjson2.annotation.JSONField;
|
|
||||||
|
|
||||||
import java.time.Instant;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* hook订阅-收流超时
|
|
||||||
* @author lin
|
|
||||||
*/
|
|
||||||
public class HookSubscribeForRtpServerTimeout implements IHookSubscribe{
|
|
||||||
|
|
||||||
private HookType hookType = HookType.on_rtp_server_timeout;
|
|
||||||
|
|
||||||
private JSONObject content;
|
|
||||||
|
|
||||||
@JSONField(format="yyyy-MM-dd HH:mm:ss")
|
|
||||||
private Instant expires;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public HookType getHookType() {
|
|
||||||
return hookType;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public JSONObject getContent() {
|
|
||||||
return content;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setContent(JSONObject content) {
|
|
||||||
this.content = content;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Instant getExpires() {
|
|
||||||
return expires;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setExpires(Instant expires) {
|
|
||||||
this.expires = expires;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,44 +0,0 @@
|
|||||||
package com.genersoft.iot.vmp.media.zlm.dto;
|
|
||||||
|
|
||||||
import com.alibaba.fastjson2.JSONObject;
|
|
||||||
import com.alibaba.fastjson2.annotation.JSONField;
|
|
||||||
|
|
||||||
import java.time.Instant;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* hook订阅-流变化
|
|
||||||
* @author lin
|
|
||||||
*/
|
|
||||||
public class HookSubscribeForServerStarted implements IHookSubscribe{
|
|
||||||
|
|
||||||
private HookType hookType = HookType.on_server_started;
|
|
||||||
|
|
||||||
private JSONObject content;
|
|
||||||
|
|
||||||
@JSONField(format="yyyy-MM-dd HH:mm:ss")
|
|
||||||
private Instant expires;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public HookType getHookType() {
|
|
||||||
return hookType;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public JSONObject getContent() {
|
|
||||||
return content;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setContent(JSONObject content) {
|
|
||||||
this.content = content;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Instant getExpires() {
|
|
||||||
return expires;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setExpires(Instant expires) {
|
|
||||||
this.expires = expires;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,44 +0,0 @@
|
|||||||
package com.genersoft.iot.vmp.media.zlm.dto;
|
|
||||||
|
|
||||||
import com.alibaba.fastjson2.JSONObject;
|
|
||||||
import com.alibaba.fastjson2.annotation.JSONField;
|
|
||||||
|
|
||||||
import java.time.Instant;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* hook订阅-流变化
|
|
||||||
* @author lin
|
|
||||||
*/
|
|
||||||
public class HookSubscribeForStreamChange implements IHookSubscribe{
|
|
||||||
|
|
||||||
private HookType hookType = HookType.on_stream_changed;
|
|
||||||
|
|
||||||
private JSONObject content;
|
|
||||||
|
|
||||||
@JSONField(format="yyyy-MM-dd HH:mm:ss")
|
|
||||||
private Instant expires;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public HookType getHookType() {
|
|
||||||
return hookType;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public JSONObject getContent() {
|
|
||||||
return content;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setContent(JSONObject content) {
|
|
||||||
this.content = content;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Instant getExpires() {
|
|
||||||
return expires;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setExpires(Instant expires) {
|
|
||||||
this.expires = expires;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,43 +0,0 @@
|
|||||||
package com.genersoft.iot.vmp.media.zlm.dto;
|
|
||||||
|
|
||||||
|
|
||||||
import com.alibaba.fastjson2.JSONObject;
|
|
||||||
|
|
||||||
import java.time.Instant;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* hook订阅-开始推流
|
|
||||||
* @author lin
|
|
||||||
*/
|
|
||||||
public class HookSubscribeForStreamPush implements IHookSubscribe{
|
|
||||||
|
|
||||||
private HookType hookType = HookType.on_publish;
|
|
||||||
|
|
||||||
private JSONObject content;
|
|
||||||
|
|
||||||
private Instant expires;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public HookType getHookType() {
|
|
||||||
return hookType;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public JSONObject getContent() {
|
|
||||||
return content;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setContent(JSONObject content) {
|
|
||||||
this.content = content;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Instant getExpires() {
|
|
||||||
return expires;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setExpires(Instant expires) {
|
|
||||||
this.expires = expires;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,26 +0,0 @@
|
|||||||
package com.genersoft.iot.vmp.media.zlm.dto;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* hook类型
|
|
||||||
* @author lin
|
|
||||||
*/
|
|
||||||
|
|
||||||
public enum HookType {
|
|
||||||
|
|
||||||
on_flow_report,
|
|
||||||
on_http_access,
|
|
||||||
on_play,
|
|
||||||
on_publish,
|
|
||||||
on_record_mp4,
|
|
||||||
on_rtsp_auth,
|
|
||||||
on_rtsp_realm,
|
|
||||||
on_shell_login,
|
|
||||||
on_stream_changed,
|
|
||||||
on_stream_none_reader,
|
|
||||||
on_stream_not_found,
|
|
||||||
on_server_started,
|
|
||||||
|
|
||||||
on_rtp_server_timeout,
|
|
||||||
on_server_keepalive,
|
|
||||||
on_send_rtp_stopped
|
|
||||||
}
|
|
||||||
@ -1,36 +0,0 @@
|
|||||||
package com.genersoft.iot.vmp.media.zlm.dto;
|
|
||||||
|
|
||||||
import com.alibaba.fastjson2.JSONObject;
|
|
||||||
|
|
||||||
import java.time.Instant;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* zlm hook事件的参数
|
|
||||||
* @author lin
|
|
||||||
*/
|
|
||||||
public interface IHookSubscribe {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取hook类型
|
|
||||||
* @return hook类型
|
|
||||||
*/
|
|
||||||
HookType getHookType();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取hook的具体内容
|
|
||||||
* @return hook的具体内容
|
|
||||||
*/
|
|
||||||
JSONObject getContent();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 设置过期时间
|
|
||||||
* @param instant 过期时间
|
|
||||||
*/
|
|
||||||
void setExpires(Instant instant);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取过期时间
|
|
||||||
* @return 过期时间
|
|
||||||
*/
|
|
||||||
Instant getExpires();
|
|
||||||
}
|
|
||||||
@ -1,168 +0,0 @@
|
|||||||
package com.genersoft.iot.vmp.media.zlm.dto;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 精简的MediaServerItem信息,方便给前端返回数据
|
|
||||||
*/
|
|
||||||
public class MediaServerItemLite {
|
|
||||||
|
|
||||||
private String id;
|
|
||||||
|
|
||||||
private String ip;
|
|
||||||
|
|
||||||
private String hookIp;
|
|
||||||
|
|
||||||
private String sdpIp;
|
|
||||||
|
|
||||||
private String streamIp;
|
|
||||||
|
|
||||||
private int httpPort;
|
|
||||||
|
|
||||||
private int httpSSlPort;
|
|
||||||
|
|
||||||
private int rtmpPort;
|
|
||||||
|
|
||||||
private int rtmpSSlPort;
|
|
||||||
|
|
||||||
private int rtpProxyPort;
|
|
||||||
|
|
||||||
private int rtspPort;
|
|
||||||
|
|
||||||
private int rtspSSLPort;
|
|
||||||
|
|
||||||
private String secret;
|
|
||||||
|
|
||||||
private int recordAssistPort;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public MediaServerItemLite(MediaServerItem mediaServerItem) {
|
|
||||||
this.id = mediaServerItem.getId();
|
|
||||||
this.ip = mediaServerItem.getIp();
|
|
||||||
this.hookIp = mediaServerItem.getHookIp();
|
|
||||||
this.sdpIp = mediaServerItem.getSdpIp();
|
|
||||||
this.streamIp = mediaServerItem.getStreamIp();
|
|
||||||
this.httpPort = mediaServerItem.getHttpPort();
|
|
||||||
this.httpSSlPort = mediaServerItem.getHttpSSlPort();
|
|
||||||
this.rtmpPort = mediaServerItem.getRtmpPort();
|
|
||||||
this.rtmpSSlPort = mediaServerItem.getRtmpSSlPort();
|
|
||||||
this.rtpProxyPort = mediaServerItem.getRtpProxyPort();
|
|
||||||
this.rtspPort = mediaServerItem.getRtspPort();
|
|
||||||
this.rtspSSLPort = mediaServerItem.getRtspSSLPort();
|
|
||||||
this.secret = mediaServerItem.getSecret();
|
|
||||||
this.recordAssistPort = mediaServerItem.getRecordAssistPort();
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getId() {
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setId(String id) {
|
|
||||||
this.id = id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getIp() {
|
|
||||||
return ip;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setIp(String ip) {
|
|
||||||
this.ip = ip;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getHookIp() {
|
|
||||||
return hookIp;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setHookIp(String hookIp) {
|
|
||||||
this.hookIp = hookIp;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getSdpIp() {
|
|
||||||
return sdpIp;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setSdpIp(String sdpIp) {
|
|
||||||
this.sdpIp = sdpIp;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getStreamIp() {
|
|
||||||
return streamIp;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setStreamIp(String streamIp) {
|
|
||||||
this.streamIp = streamIp;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getHttpPort() {
|
|
||||||
return httpPort;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setHttpPort(int httpPort) {
|
|
||||||
this.httpPort = httpPort;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getHttpSSlPort() {
|
|
||||||
return httpSSlPort;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setHttpSSlPort(int httpSSlPort) {
|
|
||||||
this.httpSSlPort = httpSSlPort;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getRtmpPort() {
|
|
||||||
return rtmpPort;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setRtmpPort(int rtmpPort) {
|
|
||||||
this.rtmpPort = rtmpPort;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getRtmpSSlPort() {
|
|
||||||
return rtmpSSlPort;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setRtmpSSlPort(int rtmpSSlPort) {
|
|
||||||
this.rtmpSSlPort = rtmpSSlPort;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getRtpProxyPort() {
|
|
||||||
return rtpProxyPort;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setRtpProxyPort(int rtpProxyPort) {
|
|
||||||
this.rtpProxyPort = rtpProxyPort;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getRtspPort() {
|
|
||||||
return rtspPort;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setRtspPort(int rtspPort) {
|
|
||||||
this.rtspPort = rtspPort;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getRtspSSLPort() {
|
|
||||||
return rtspSSLPort;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setRtspSSLPort(int rtspSSLPort) {
|
|
||||||
this.rtspSSLPort = rtspSSLPort;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public String getSecret() {
|
|
||||||
return secret;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setSecret(String secret) {
|
|
||||||
this.secret = secret;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getRecordAssistPort() {
|
|
||||||
return recordAssistPort;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setRecordAssistPort(int recordAssistPort) {
|
|
||||||
this.recordAssistPort = recordAssistPort;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,7 +1,6 @@
|
|||||||
package com.genersoft.iot.vmp.media.zlm.dto;
|
package com.genersoft.iot.vmp.media.zlm.dto;
|
||||||
|
|
||||||
import com.genersoft.iot.vmp.media.zlm.dto.hook.OnPublishHookParam;
|
import com.genersoft.iot.vmp.media.event.media.MediaArrivalEvent;
|
||||||
import com.genersoft.iot.vmp.media.zlm.dto.hook.OnStreamChangedHookParam;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 流的鉴权信息
|
* 流的鉴权信息
|
||||||
@ -97,21 +96,23 @@ public class StreamAuthorityInfo {
|
|||||||
this.sign = sign;
|
this.sign = sign;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static StreamAuthorityInfo getInstanceByHook(OnPublishHookParam hookParam) {
|
public static StreamAuthorityInfo getInstanceByHook(String app, String stream, String id) {
|
||||||
StreamAuthorityInfo streamAuthorityInfo = new StreamAuthorityInfo();
|
StreamAuthorityInfo streamAuthorityInfo = new StreamAuthorityInfo();
|
||||||
streamAuthorityInfo.setApp(hookParam.getApp());
|
streamAuthorityInfo.setApp(app);
|
||||||
streamAuthorityInfo.setStream(hookParam.getStream());
|
streamAuthorityInfo.setStream(stream);
|
||||||
streamAuthorityInfo.setId(hookParam.getId());
|
streamAuthorityInfo.setId(id);
|
||||||
return streamAuthorityInfo;
|
return streamAuthorityInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static StreamAuthorityInfo getInstanceByHook(OnStreamChangedHookParam onStreamChangedHookParam) {
|
public static StreamAuthorityInfo getInstanceByHook(MediaArrivalEvent event) {
|
||||||
StreamAuthorityInfo streamAuthorityInfo = new StreamAuthorityInfo();
|
StreamAuthorityInfo streamAuthorityInfo = new StreamAuthorityInfo();
|
||||||
streamAuthorityInfo.setApp(onStreamChangedHookParam.getApp());
|
streamAuthorityInfo.setApp(event.getApp());
|
||||||
streamAuthorityInfo.setStream(onStreamChangedHookParam.getStream());
|
streamAuthorityInfo.setStream(event.getStream());
|
||||||
streamAuthorityInfo.setId(onStreamChangedHookParam.getMediaServerId());
|
streamAuthorityInfo.setId(event.getMediaServer().getId());
|
||||||
streamAuthorityInfo.setOriginType(onStreamChangedHookParam.getOriginType());
|
if (event.getMediaInfo() != null) {
|
||||||
streamAuthorityInfo.setOriginTypeStr(onStreamChangedHookParam.getOriginTypeStr());
|
streamAuthorityInfo.setOriginType(event.getMediaInfo().getOriginType());
|
||||||
|
}
|
||||||
|
|
||||||
return streamAuthorityInfo;
|
return streamAuthorityInfo;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
package com.genersoft.iot.vmp.media.zlm.dto;
|
package com.genersoft.iot.vmp.media.zlm.dto;
|
||||||
|
|
||||||
|
import com.genersoft.iot.vmp.common.StreamInfo;
|
||||||
import com.genersoft.iot.vmp.gb28181.bean.GbStream;
|
import com.genersoft.iot.vmp.gb28181.bean.GbStream;
|
||||||
|
import com.genersoft.iot.vmp.media.event.media.MediaArrivalEvent;
|
||||||
import com.genersoft.iot.vmp.media.zlm.dto.hook.OnStreamChangedHookParam;
|
import com.genersoft.iot.vmp.media.zlm.dto.hook.OnStreamChangedHookParam;
|
||||||
import com.genersoft.iot.vmp.utils.DateUtil;
|
import com.genersoft.iot.vmp.utils.DateUtil;
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
@ -150,6 +152,47 @@ public class StreamPushItem extends GbStream implements Comparable<StreamPushIte
|
|||||||
- DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(streamPushItem.getCreateTime())).intValue();
|
- DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(streamPushItem.getCreateTime())).intValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public StreamPushItem getInstance(StreamInfo streamInfo) {
|
||||||
|
StreamPushItem streamPushItem = new StreamPushItem();
|
||||||
|
streamPushItem.setApp(streamInfo.getApp());
|
||||||
|
streamPushItem.setMediaServerId(streamInfo.getMediaServerId());
|
||||||
|
streamPushItem.setStream(streamInfo.getStream());
|
||||||
|
streamPushItem.setAliveSecond(streamInfo.getMediaInfo().getAliveSecond());
|
||||||
|
// streamPushItem.setOriginSock(streamInfo.getMediaInfo().getOriginSock());
|
||||||
|
streamPushItem.setTotalReaderCount(streamInfo.getMediaInfo().getReaderCount() + "");
|
||||||
|
streamPushItem.setOriginType(streamInfo.getOriginType());
|
||||||
|
// streamPushItem.setOriginTypeStr(streamInfo.getMediaInfo().getOriginTypeStr());
|
||||||
|
// streamPushItem.setOriginUrl(streamInfo.getMediaInfo().getOriginUrl());
|
||||||
|
streamPushItem.setCreateTime(DateUtil.getNow());
|
||||||
|
streamPushItem.setAliveSecond(streamInfo.getMediaInfo().getAliveSecond());
|
||||||
|
streamPushItem.setStatus(true);
|
||||||
|
streamPushItem.setStreamType("push");
|
||||||
|
// streamPushItem.setVhost(streamInfo.getVhost());
|
||||||
|
streamPushItem.setServerId(streamInfo.getMediaServerId());
|
||||||
|
return streamPushItem;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static StreamPushItem getInstance(MediaArrivalEvent event, String serverId){
|
||||||
|
StreamPushItem streamPushItem = new StreamPushItem();
|
||||||
|
streamPushItem.setApp(event.getApp());
|
||||||
|
streamPushItem.setMediaServerId(event.getMediaServer().getId());
|
||||||
|
streamPushItem.setStream(event.getStream());
|
||||||
|
streamPushItem.setAliveSecond(event.getMediaInfo().getAliveSecond());
|
||||||
|
// streamPushItem.setOriginSock(streamInfo.getMediaInfo().getOriginSock());
|
||||||
|
streamPushItem.setTotalReaderCount(event.getMediaInfo().getReaderCount() + "");
|
||||||
|
streamPushItem.setOriginType(event.getMediaInfo().getOriginType());
|
||||||
|
// streamPushItem.setOriginTypeStr(streamInfo.getMediaInfo().getOriginTypeStr());
|
||||||
|
// streamPushItem.setOriginUrl(streamInfo.getMediaInfo().getOriginUrl());
|
||||||
|
streamPushItem.setCreateTime(DateUtil.getNow());
|
||||||
|
streamPushItem.setAliveSecond(event.getMediaInfo().getAliveSecond());
|
||||||
|
streamPushItem.setStatus(true);
|
||||||
|
streamPushItem.setStreamType("push");
|
||||||
|
// streamPushItem.setVhost(streamInfo.getVhost());
|
||||||
|
streamPushItem.setServerId(serverId);
|
||||||
|
return streamPushItem;
|
||||||
|
}
|
||||||
|
|
||||||
public static class MediaSchema {
|
public static class MediaSchema {
|
||||||
private String schema;
|
private String schema;
|
||||||
private Long bytesSpeed;
|
private Long bytesSpeed;
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
package com.genersoft.iot.vmp.media.zlm;
|
package com.genersoft.iot.vmp.media.zlm.dto;
|
||||||
|
|
||||||
import com.alibaba.fastjson2.annotation.JSONField;
|
import com.alibaba.fastjson2.annotation.JSONField;
|
||||||
import com.genersoft.iot.vmp.media.zlm.dto.hook.HookParam;
|
import com.genersoft.iot.vmp.media.zlm.dto.hook.HookParam;
|
||||||
@ -7,6 +7,8 @@ package com.genersoft.iot.vmp.media.zlm.dto.hook;
|
|||||||
public class HookParam {
|
public class HookParam {
|
||||||
private String mediaServerId;
|
private String mediaServerId;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public String getMediaServerId() {
|
public String getMediaServerId() {
|
||||||
return mediaServerId;
|
return mediaServerId;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -18,8 +18,8 @@ public class HookResult {
|
|||||||
return new HookResult(0, "success");
|
return new HookResult(0, "success");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static HookResult Fail(){
|
public static HookResultForOnPublish Fail(){
|
||||||
return new HookResult(-1, "fail");
|
return new HookResultForOnPublish(-1, "fail");
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getCode() {
|
public int getCode() {
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
package com.genersoft.iot.vmp.media.zlm.dto.hook;
|
package com.genersoft.iot.vmp.media.zlm.dto.hook;
|
||||||
|
|
||||||
|
import com.genersoft.iot.vmp.media.bean.ResultForOnPublish;
|
||||||
|
|
||||||
public class HookResultForOnPublish extends HookResult{
|
public class HookResultForOnPublish extends HookResult{
|
||||||
|
|
||||||
private boolean enable_audio;
|
private boolean enable_audio;
|
||||||
@ -16,6 +18,17 @@ public class HookResultForOnPublish extends HookResult{
|
|||||||
return new HookResultForOnPublish(0, "success");
|
return new HookResultForOnPublish(0, "success");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static HookResultForOnPublish getInstance(ResultForOnPublish resultForOnPublish){
|
||||||
|
HookResultForOnPublish successResult = new HookResultForOnPublish(0, "success");
|
||||||
|
successResult.setEnable_audio(resultForOnPublish.isEnable_audio());
|
||||||
|
successResult.setEnable_mp4(resultForOnPublish.isEnable_mp4());
|
||||||
|
successResult.setModify_stamp(resultForOnPublish.getModify_stamp());
|
||||||
|
successResult.setStream_replace(resultForOnPublish.getStream_replace());
|
||||||
|
successResult.setMp4_max_second(resultForOnPublish.getMp4_max_second());
|
||||||
|
successResult.setMp4_save_path(resultForOnPublish.getMp4_save_path());
|
||||||
|
return successResult;
|
||||||
|
}
|
||||||
|
|
||||||
public HookResultForOnPublish(int code, String msg) {
|
public HookResultForOnPublish(int code, String msg) {
|
||||||
setCode(code);
|
setCode(code);
|
||||||
setMsg(msg);
|
setMsg(msg);
|
||||||
|
|||||||
@ -32,7 +32,7 @@ public class OnStreamChangedHookParam extends HookParam{
|
|||||||
/**
|
/**
|
||||||
* 观看总人数,包括hls/rtsp/rtmp/http-flv/ws-flv
|
* 观看总人数,包括hls/rtsp/rtmp/http-flv/ws-flv
|
||||||
*/
|
*/
|
||||||
private String totalReaderCount;
|
private int totalReaderCount;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 协议 包括hls/rtsp/rtmp/http-flv/ws-flv
|
* 协议 包括hls/rtsp/rtmp/http-flv/ws-flv
|
||||||
@ -374,11 +374,11 @@ public class OnStreamChangedHookParam extends HookParam{
|
|||||||
this.stream = stream;
|
this.stream = stream;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getTotalReaderCount() {
|
public int getTotalReaderCount() {
|
||||||
return totalReaderCount;
|
return totalReaderCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setTotalReaderCount(String totalReaderCount) {
|
public void setTotalReaderCount(int totalReaderCount) {
|
||||||
this.totalReaderCount = totalReaderCount;
|
this.totalReaderCount = totalReaderCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,24 @@
|
|||||||
|
package com.genersoft.iot.vmp.media.zlm.event;
|
||||||
|
|
||||||
|
import com.genersoft.iot.vmp.media.bean.MediaServer;
|
||||||
|
import org.springframework.context.ApplicationEvent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* zlm 心跳事件
|
||||||
|
*/
|
||||||
|
public class HookZlmServerKeepaliveEvent extends ApplicationEvent {
|
||||||
|
|
||||||
|
public HookZlmServerKeepaliveEvent(Object source) {
|
||||||
|
super(source);
|
||||||
|
}
|
||||||
|
|
||||||
|
private MediaServer mediaServerItem;
|
||||||
|
|
||||||
|
public MediaServer getMediaServerItem() {
|
||||||
|
return mediaServerItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMediaServerItem(MediaServer mediaServerItem) {
|
||||||
|
this.mediaServerItem = mediaServerItem;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,24 @@
|
|||||||
|
package com.genersoft.iot.vmp.media.zlm.event;
|
||||||
|
|
||||||
|
import com.genersoft.iot.vmp.media.bean.MediaServer;
|
||||||
|
import org.springframework.context.ApplicationEvent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* zlm server_start事件
|
||||||
|
*/
|
||||||
|
public class HookZlmServerStartEvent extends ApplicationEvent {
|
||||||
|
|
||||||
|
public HookZlmServerStartEvent(Object source) {
|
||||||
|
super(source);
|
||||||
|
}
|
||||||
|
|
||||||
|
private MediaServer mediaServerItem;
|
||||||
|
|
||||||
|
public MediaServer getMediaServerItem() {
|
||||||
|
return mediaServerItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMediaServerItem(MediaServer mediaServerItem) {
|
||||||
|
this.mediaServerItem = mediaServerItem;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,11 +0,0 @@
|
|||||||
package com.genersoft.iot.vmp.media.zlm.event;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* zlm离线事件类
|
|
||||||
*/
|
|
||||||
public class ZLMOfflineEvent extends ZLMEventAbstract {
|
|
||||||
|
|
||||||
public ZLMOfflineEvent(Object source) {
|
|
||||||
super(source);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,11 +0,0 @@
|
|||||||
package com.genersoft.iot.vmp.media.zlm.event;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* zlm在线事件
|
|
||||||
*/
|
|
||||||
public class ZLMOnlineEvent extends ZLMEventAbstract {
|
|
||||||
|
|
||||||
public ZLMOnlineEvent(Object source) {
|
|
||||||
super(source);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,8 +1,7 @@
|
|||||||
package com.genersoft.iot.vmp.service;
|
package com.genersoft.iot.vmp.service;
|
||||||
|
|
||||||
import com.alibaba.fastjson2.JSONArray;
|
import com.alibaba.fastjson2.JSONArray;
|
||||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
import com.genersoft.iot.vmp.media.bean.MediaServer;
|
||||||
import com.genersoft.iot.vmp.media.zlm.dto.hook.OnRecordMp4HookParam;
|
|
||||||
import com.genersoft.iot.vmp.service.bean.CloudRecordItem;
|
import com.genersoft.iot.vmp.service.bean.CloudRecordItem;
|
||||||
import com.genersoft.iot.vmp.service.bean.DownloadFileInfo;
|
import com.genersoft.iot.vmp.service.bean.DownloadFileInfo;
|
||||||
import com.github.pagehelper.PageInfo;
|
import com.github.pagehelper.PageInfo;
|
||||||
@ -18,22 +17,17 @@ public interface ICloudRecordService {
|
|||||||
/**
|
/**
|
||||||
* 分页回去云端录像列表
|
* 分页回去云端录像列表
|
||||||
*/
|
*/
|
||||||
PageInfo<CloudRecordItem> getList(int page, int count, String query, String app, String stream, String startTime, String endTime, List<MediaServerItem> mediaServerItems);
|
PageInfo<CloudRecordItem> getList(int page, int count, String query, String app, String stream, String startTime, String endTime, List<MediaServer> mediaServerItems);
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据hook消息增加一条记录
|
|
||||||
*/
|
|
||||||
void addRecord(OnRecordMp4HookParam param);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取所有的日期
|
* 获取所有的日期
|
||||||
*/
|
*/
|
||||||
List<String> getDateList(String app, String stream, int year, int month, List<MediaServerItem> mediaServerItems);
|
List<String> getDateList(String app, String stream, int year, int month, List<MediaServer> mediaServerItems);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 添加合并任务
|
* 添加合并任务
|
||||||
*/
|
*/
|
||||||
String addTask(String app, String stream, MediaServerItem mediaServerItem, String startTime,
|
String addTask(String app, String stream, MediaServer mediaServerItem, String startTime,
|
||||||
String endTime, String callId, String remoteHost, boolean filterMediaServer);
|
String endTime, String callId, String remoteHost, boolean filterMediaServer);
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -1,100 +0,0 @@
|
|||||||
package com.genersoft.iot.vmp.service;
|
|
||||||
|
|
||||||
import com.genersoft.iot.vmp.common.CommonCallback;
|
|
||||||
import com.genersoft.iot.vmp.media.zlm.ZLMServerConfig;
|
|
||||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
|
||||||
import com.genersoft.iot.vmp.media.zlm.dto.ServerKeepaliveData;
|
|
||||||
import com.genersoft.iot.vmp.service.bean.MediaServerLoad;
|
|
||||||
import com.genersoft.iot.vmp.service.bean.SSRCInfo;
|
|
||||||
import com.genersoft.iot.vmp.vmanager.bean.RecordFile;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 媒体服务节点
|
|
||||||
*/
|
|
||||||
public interface IMediaServerService {
|
|
||||||
|
|
||||||
List<MediaServerItem> getAll();
|
|
||||||
|
|
||||||
List<MediaServerItem> getAllFromDatabase();
|
|
||||||
|
|
||||||
List<MediaServerItem> getAllOnline();
|
|
||||||
|
|
||||||
MediaServerItem getOne(String generalMediaServerId);
|
|
||||||
|
|
||||||
void syncCatchFromDatabase();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 新的节点加入
|
|
||||||
* @param zlmServerConfig
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
void zlmServerOnline(ZLMServerConfig zlmServerConfig);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 节点离线
|
|
||||||
* @param mediaServerId
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
void zlmServerOffline(String mediaServerId);
|
|
||||||
|
|
||||||
MediaServerItem getMediaServerForMinimumLoad(Boolean hasAssist);
|
|
||||||
|
|
||||||
void setZLMConfig(MediaServerItem mediaServerItem, boolean restart);
|
|
||||||
|
|
||||||
void updateVmServer(List<MediaServerItem> mediaServerItemList);
|
|
||||||
|
|
||||||
SSRCInfo openRTPServer(MediaServerItem mediaServerItem, String streamId, String presetSsrc, boolean ssrcCheck,
|
|
||||||
boolean isPlayback, Integer port, Boolean onlyAuto, Boolean reUsePort, Integer tcpMode);
|
|
||||||
|
|
||||||
SSRCInfo openRTPServer(MediaServerItem mediaServerItem, String streamId, String ssrc, boolean ssrcCheck, boolean isPlayback, Integer port, Boolean onlyAuto);
|
|
||||||
|
|
||||||
void closeRTPServer(MediaServerItem mediaServerItem, String streamId);
|
|
||||||
|
|
||||||
void closeRTPServer(MediaServerItem mediaServerItem, String streamId, CommonCallback<Boolean> callback);
|
|
||||||
Boolean updateRtpServerSSRC(MediaServerItem mediaServerItem, String streamId, String ssrc);
|
|
||||||
|
|
||||||
void closeRTPServer(String mediaServerId, String streamId);
|
|
||||||
|
|
||||||
void clearRTPServer(MediaServerItem mediaServerItem);
|
|
||||||
|
|
||||||
void update(MediaServerItem mediaSerItem);
|
|
||||||
|
|
||||||
void addCount(String mediaServerId);
|
|
||||||
|
|
||||||
void removeCount(String mediaServerId);
|
|
||||||
|
|
||||||
void releaseSsrc(String mediaServerItemId, String ssrc);
|
|
||||||
|
|
||||||
void clearMediaServerForOnline();
|
|
||||||
|
|
||||||
void add(MediaServerItem mediaSerItem);
|
|
||||||
|
|
||||||
int addToDatabase(MediaServerItem mediaSerItem);
|
|
||||||
|
|
||||||
int updateToDatabase(MediaServerItem mediaSerItem);
|
|
||||||
|
|
||||||
void resetOnlineServerItem(MediaServerItem serverItem);
|
|
||||||
|
|
||||||
MediaServerItem checkMediaServer(String ip, int port, String secret);
|
|
||||||
|
|
||||||
boolean checkMediaRecordServer(String ip, int port);
|
|
||||||
|
|
||||||
void delete(String id);
|
|
||||||
|
|
||||||
void deleteDb(String id);
|
|
||||||
|
|
||||||
MediaServerItem getDefaultMediaServer();
|
|
||||||
|
|
||||||
void updateMediaServerKeepalive(String mediaServerId, ServerKeepaliveData data);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取负载信息
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
MediaServerLoad getLoad(MediaServerItem mediaServerItem);
|
|
||||||
|
|
||||||
List<MediaServerItem> getAllWithAssistPort();
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,8 +1,7 @@
|
|||||||
package com.genersoft.iot.vmp.service;
|
package com.genersoft.iot.vmp.service;
|
||||||
|
|
||||||
import com.alibaba.fastjson2.JSONArray;
|
import com.genersoft.iot.vmp.media.bean.ResultForOnPublish;
|
||||||
import com.genersoft.iot.vmp.common.StreamInfo;
|
import com.genersoft.iot.vmp.media.bean.MediaServer;
|
||||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 媒体信息业务
|
* 媒体信息业务
|
||||||
@ -10,35 +9,11 @@ import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
|||||||
public interface IMediaService {
|
public interface IMediaService {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据应用名和流ID获取播放地址, 通过zlm接口检查是否存在
|
* 播放鉴权
|
||||||
* @param app
|
|
||||||
* @param stream
|
|
||||||
* @return
|
|
||||||
*/
|
*/
|
||||||
StreamInfo getStreamInfoByAppAndStreamWithCheck(String app, String stream, String mediaServerId,String addr, boolean authority);
|
boolean authenticatePlay(String app, String stream, String callId);
|
||||||
|
|
||||||
|
ResultForOnPublish authenticatePublish(MediaServer mediaServer, String app, String stream, String params);
|
||||||
|
|
||||||
/**
|
boolean closeStreamOnNoneReader(String mediaServerId, String app, String stream, String schema);
|
||||||
* 根据应用名和流ID获取播放地址, 通过zlm接口检查是否存在, 返回的ip使用远程访问ip,适用与zlm与wvp在一台主机的情况
|
|
||||||
* @param app
|
|
||||||
* @param stream
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
StreamInfo getStreamInfoByAppAndStreamWithCheck(String app, String stream, String mediaServerId, boolean authority);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据应用名和流ID获取播放地址, 只是地址拼接
|
|
||||||
* @param app
|
|
||||||
* @param stream
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
StreamInfo getStreamInfoByAppAndStream(MediaServerItem mediaServerItem, String app, String stream, Object tracks, String callId);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据应用名和流ID获取播放地址, 只是地址拼接,返回的ip使用远程访问ip,适用与zlm与wvp在一台主机的情况
|
|
||||||
* @param app
|
|
||||||
* @param stream
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
StreamInfo getStreamInfoByAppAndStream(MediaServerItem mediaInfo, String app, String stream, Object tracks, String addr, String callId, boolean isPlay);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,8 +3,8 @@ package com.genersoft.iot.vmp.service;
|
|||||||
import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
|
import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
|
||||||
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
|
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
|
||||||
import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
|
import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
|
||||||
import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe;
|
import com.genersoft.iot.vmp.media.event.hook.HookSubscribe;
|
||||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
import com.genersoft.iot.vmp.media.bean.MediaServer;
|
||||||
import com.genersoft.iot.vmp.service.bean.InviteTimeOutCallback;
|
import com.genersoft.iot.vmp.service.bean.InviteTimeOutCallback;
|
||||||
import com.genersoft.iot.vmp.gb28181.bean.SipTransactionInfo;
|
import com.genersoft.iot.vmp.gb28181.bean.SipTransactionInfo;
|
||||||
import com.github.pagehelper.PageInfo;
|
import com.github.pagehelper.PageInfo;
|
||||||
@ -73,13 +73,13 @@ public interface IPlatformService {
|
|||||||
* @param errorEvent 信令错误事件
|
* @param errorEvent 信令错误事件
|
||||||
* @param timeoutCallback 超时事件
|
* @param timeoutCallback 超时事件
|
||||||
*/
|
*/
|
||||||
void broadcastInvite(ParentPlatform platform, String channelId, MediaServerItem mediaServerItem, ZlmHttpHookSubscribe.Event hookEvent,
|
void broadcastInvite(ParentPlatform platform, String channelId, MediaServer mediaServerItem, HookSubscribe.Event hookEvent,
|
||||||
SipSubscribe.Event errorEvent, InviteTimeOutCallback timeoutCallback) throws InvalidArgumentException, ParseException, SipException;
|
SipSubscribe.Event errorEvent, InviteTimeOutCallback timeoutCallback) throws InvalidArgumentException, ParseException, SipException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 语音喊话回复BYE
|
* 语音喊话回复BYE
|
||||||
*/
|
*/
|
||||||
void stopBroadcast(ParentPlatform platform, DeviceChannel channel, String stream,boolean sendBye, MediaServerItem mediaServerItem);
|
void stopBroadcast(ParentPlatform platform, DeviceChannel channel, String stream,boolean sendBye, MediaServer mediaServerItem);
|
||||||
|
|
||||||
void addSimulatedSubscribeInfo(ParentPlatform parentPlatform);
|
void addSimulatedSubscribeInfo(ParentPlatform parentPlatform);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,8 +7,8 @@ import com.genersoft.iot.vmp.gb28181.bean.Device;
|
|||||||
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
|
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
|
||||||
import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
|
import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
|
||||||
import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
|
import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
|
||||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
import com.genersoft.iot.vmp.media.bean.MediaInfo;
|
||||||
import com.genersoft.iot.vmp.media.zlm.dto.hook.HookParam;
|
import com.genersoft.iot.vmp.media.bean.MediaServer;
|
||||||
import com.genersoft.iot.vmp.service.bean.ErrorCallback;
|
import com.genersoft.iot.vmp.service.bean.ErrorCallback;
|
||||||
import com.genersoft.iot.vmp.service.bean.SSRCInfo;
|
import com.genersoft.iot.vmp.service.bean.SSRCInfo;
|
||||||
import com.genersoft.iot.vmp.vmanager.bean.AudioBroadcastResult;
|
import com.genersoft.iot.vmp.vmanager.bean.AudioBroadcastResult;
|
||||||
@ -26,20 +26,20 @@ import java.util.Map;
|
|||||||
*/
|
*/
|
||||||
public interface IPlayService {
|
public interface IPlayService {
|
||||||
|
|
||||||
void play(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, DeviceChannel channelId,
|
void play(MediaServer mediaServerItem, SSRCInfo ssrcInfo, Device device, DeviceChannel channelId,
|
||||||
ErrorCallback<Object> callback);
|
ErrorCallback<Object> callback);
|
||||||
SSRCInfo play(MediaServerItem mediaServerItem, String deviceId, String channelId, String ssrc, ErrorCallback<Object> callback);
|
SSRCInfo play(MediaServer mediaServerItem, String deviceId, String channelId, String ssrc, ErrorCallback<Object> callback);
|
||||||
|
|
||||||
StreamInfo onPublishHandlerForPlay(MediaServerItem mediaServerItem, HookParam hookParam, String deviceId, String channelId);
|
StreamInfo onPublishHandlerForPlay(MediaServer mediaServerItem, MediaInfo mediaInfo, String deviceId, String channelId);
|
||||||
|
|
||||||
MediaServerItem getNewMediaServerItem(Device device);
|
MediaServer getNewMediaServerItem(Device device);
|
||||||
|
|
||||||
void playBack(String deviceId, String channelId, String startTime, String endTime, ErrorCallback<Object> callback);
|
void playBack(String deviceId, String channelId, String startTime, String endTime, ErrorCallback<Object> callback);
|
||||||
void playBack(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, String deviceId, String channelId, String startTime, String endTime, ErrorCallback<Object> callback);
|
void playBack(MediaServer mediaServerItem, SSRCInfo ssrcInfo, String deviceId, String channelId, String startTime, String endTime, ErrorCallback<Object> callback);
|
||||||
void zlmServerOffline(String mediaServerId);
|
void zlmServerOffline(String mediaServerId);
|
||||||
|
|
||||||
void download(String deviceId, String channelId, String startTime, String endTime, int downloadSpeed, ErrorCallback<Object> callback);
|
void download(String deviceId, String channelId, String startTime, String endTime, int downloadSpeed, ErrorCallback<Object> callback);
|
||||||
void download(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo,String deviceId, String channelId, String startTime, String endTime, int downloadSpeed, ErrorCallback<Object> callback);
|
void download(MediaServer mediaServerItem, SSRCInfo ssrcInfo, String deviceId, String channelId, String startTime, String endTime, int downloadSpeed, ErrorCallback<Object> callback);
|
||||||
|
|
||||||
StreamInfo getDownLoadInfo(String deviceId, String channelId, String stream);
|
StreamInfo getDownLoadInfo(String deviceId, String channelId, String stream);
|
||||||
|
|
||||||
@ -47,7 +47,7 @@ public interface IPlayService {
|
|||||||
|
|
||||||
AudioBroadcastResult audioBroadcast(Device device, String channelId, Boolean broadcastMode);
|
AudioBroadcastResult audioBroadcast(Device device, String channelId, Boolean broadcastMode);
|
||||||
|
|
||||||
boolean audioBroadcastCmd(Device device, String channelId, MediaServerItem mediaServerItem, String app, String stream, int timeout, boolean isFromPlatform, AudioBroadcastEvent event) throws InvalidArgumentException, ParseException, SipException;
|
boolean audioBroadcastCmd(Device device, String channelId, MediaServer mediaServerItem, String app, String stream, int timeout, boolean isFromPlatform, AudioBroadcastEvent event) throws InvalidArgumentException, ParseException, SipException;
|
||||||
|
|
||||||
boolean audioBroadcastInUse(Device device, String channelId);
|
boolean audioBroadcastInUse(Device device, String channelId);
|
||||||
|
|
||||||
@ -59,10 +59,9 @@ public interface IPlayService {
|
|||||||
|
|
||||||
void startPushStream(SendRtpItem sendRtpItem, SIPResponse sipResponse, ParentPlatform platform, CallIdHeader callIdHeader);
|
void startPushStream(SendRtpItem sendRtpItem, SIPResponse sipResponse, ParentPlatform platform, CallIdHeader callIdHeader);
|
||||||
|
|
||||||
void startSendRtpStreamHand(SendRtpItem sendRtpItem, Object correlationInfo,
|
void startSendRtpStreamFailHand(SendRtpItem sendRtpItem,ParentPlatform platform, CallIdHeader callIdHeader);
|
||||||
JSONObject jsonObject, Map<String, Object> param, CallIdHeader callIdHeader);
|
|
||||||
|
|
||||||
void talkCmd(Device device, String channelId, MediaServerItem mediaServerItem, String stream, AudioBroadcastEvent event);
|
void talkCmd(Device device, String channelId, MediaServer mediaServerItem, String stream, AudioBroadcastEvent event);
|
||||||
|
|
||||||
void stopTalk(Device device, String channelId, Boolean streamIsReady);
|
void stopTalk(Device device, String channelId, Boolean streamIsReady);
|
||||||
|
|
||||||
|
|||||||
@ -1,13 +1,15 @@
|
|||||||
package com.genersoft.iot.vmp.service;
|
package com.genersoft.iot.vmp.service;
|
||||||
|
|
||||||
import com.alibaba.fastjson2.JSONObject;
|
|
||||||
import com.genersoft.iot.vmp.common.GeneralCallback;
|
import com.genersoft.iot.vmp.common.GeneralCallback;
|
||||||
import com.genersoft.iot.vmp.common.StreamInfo;
|
import com.genersoft.iot.vmp.common.StreamInfo;
|
||||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
import com.genersoft.iot.vmp.media.bean.MediaServer;
|
||||||
import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem;
|
import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem;
|
||||||
import com.genersoft.iot.vmp.vmanager.bean.ResourceBaseInfo;
|
import com.genersoft.iot.vmp.vmanager.bean.ResourceBaseInfo;
|
||||||
|
import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
|
||||||
import com.github.pagehelper.PageInfo;
|
import com.github.pagehelper.PageInfo;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
public interface IStreamProxyService {
|
public interface IStreamProxyService {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -18,17 +20,19 @@ public interface IStreamProxyService {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 添加视频代理到zlm
|
* 添加视频代理到zlm
|
||||||
|
*
|
||||||
* @param param
|
* @param param
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
JSONObject addStreamProxyToZlm(StreamProxyItem param);
|
WVPResult<String> addStreamProxyToZlm(StreamProxyItem param);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 从zlm移除视频代理
|
* 从zlm移除视频代理
|
||||||
|
*
|
||||||
* @param param
|
* @param param
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
JSONObject removeStreamProxyFromZlm(StreamProxyItem param);
|
Boolean removeStreamProxyFromZlm(StreamProxyItem param);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 分页查询
|
* 分页查询
|
||||||
@ -73,9 +77,10 @@ public interface IStreamProxyService {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取ffmpeg.cmd模板
|
* 获取ffmpeg.cmd模板
|
||||||
|
*
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
JSONObject getFFmpegCMDs(MediaServerItem mediaServerItem);
|
Map<String, String> getFFmpegCMDs(MediaServer mediaServerItem);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据app与stream获取streamProxy
|
* 根据app与stream获取streamProxy
|
||||||
|
|||||||
@ -1,9 +1,8 @@
|
|||||||
package com.genersoft.iot.vmp.service;
|
package com.genersoft.iot.vmp.service;
|
||||||
|
|
||||||
import com.genersoft.iot.vmp.gb28181.bean.GbStream;
|
import com.genersoft.iot.vmp.gb28181.bean.GbStream;
|
||||||
import com.genersoft.iot.vmp.media.zlm.dto.hook.OnStreamChangedHookParam;
|
|
||||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
|
||||||
import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem;
|
import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem;
|
||||||
|
import com.genersoft.iot.vmp.media.zlm.dto.hook.OnStreamChangedHookParam;
|
||||||
import com.genersoft.iot.vmp.service.bean.StreamPushItemFromRedis;
|
import com.genersoft.iot.vmp.service.bean.StreamPushItemFromRedis;
|
||||||
import com.genersoft.iot.vmp.vmanager.bean.ResourceBaseInfo;
|
import com.genersoft.iot.vmp.vmanager.bean.ResourceBaseInfo;
|
||||||
import com.github.pagehelper.PageInfo;
|
import com.github.pagehelper.PageInfo;
|
||||||
@ -16,8 +15,6 @@ import java.util.Map;
|
|||||||
*/
|
*/
|
||||||
public interface IStreamPushService {
|
public interface IStreamPushService {
|
||||||
|
|
||||||
List<StreamPushItem> handleJSON(String json, MediaServerItem mediaServerItem);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 将应用名和流ID加入国标关联
|
* 将应用名和流ID加入国标关联
|
||||||
* @param stream
|
* @param stream
|
||||||
|
|||||||
@ -0,0 +1,25 @@
|
|||||||
|
package com.genersoft.iot.vmp.service;
|
||||||
|
|
||||||
|
import com.genersoft.iot.vmp.storager.dao.dto.UserApiKey;
|
||||||
|
import com.github.pagehelper.PageInfo;
|
||||||
|
|
||||||
|
public interface IUserApiKeyService {
|
||||||
|
int addApiKey(UserApiKey userApiKey);
|
||||||
|
|
||||||
|
boolean isApiKeyExists(String apiKey);
|
||||||
|
|
||||||
|
PageInfo<UserApiKey> getUserApiKeys(int page, int count);
|
||||||
|
|
||||||
|
int enable(Integer id);
|
||||||
|
|
||||||
|
int disable(Integer id);
|
||||||
|
|
||||||
|
int remark(Integer id, String remark);
|
||||||
|
|
||||||
|
int delete(Integer id);
|
||||||
|
|
||||||
|
UserApiKey getUserApiKeyById(Integer id);
|
||||||
|
|
||||||
|
int reset(Integer id, String apiKey);
|
||||||
|
|
||||||
|
}
|
||||||
@ -11,6 +11,8 @@ public interface IUserService {
|
|||||||
|
|
||||||
boolean changePassword(int id, String password);
|
boolean changePassword(int id, String password);
|
||||||
|
|
||||||
|
User getUserById(int id);
|
||||||
|
|
||||||
User getUserByUsername(String username);
|
User getUserByUsername(String username);
|
||||||
|
|
||||||
int addUser(User user);
|
int addUser(User user);
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
package com.genersoft.iot.vmp.service.bean;
|
package com.genersoft.iot.vmp.service.bean;
|
||||||
|
|
||||||
|
import com.genersoft.iot.vmp.media.event.media.MediaRecordMp4Event;
|
||||||
import com.genersoft.iot.vmp.media.zlm.dto.hook.OnRecordMp4HookParam;
|
import com.genersoft.iot.vmp.media.zlm.dto.hook.OnRecordMp4HookParam;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -76,18 +77,18 @@ public class CloudRecordItem {
|
|||||||
*/
|
*/
|
||||||
private long timeLen;
|
private long timeLen;
|
||||||
|
|
||||||
public static CloudRecordItem getInstance(OnRecordMp4HookParam param) {
|
public static CloudRecordItem getInstance(MediaRecordMp4Event param) {
|
||||||
CloudRecordItem cloudRecordItem = new CloudRecordItem();
|
CloudRecordItem cloudRecordItem = new CloudRecordItem();
|
||||||
cloudRecordItem.setApp(param.getApp());
|
cloudRecordItem.setApp(param.getApp());
|
||||||
cloudRecordItem.setStream(param.getStream());
|
cloudRecordItem.setStream(param.getStream());
|
||||||
cloudRecordItem.setStartTime(param.getStart_time()*1000);
|
cloudRecordItem.setStartTime(param.getRecordInfo().getStartTime()*1000);
|
||||||
cloudRecordItem.setFileName(param.getFile_name());
|
cloudRecordItem.setFileName(param.getRecordInfo().getFileName());
|
||||||
cloudRecordItem.setFolder(param.getFolder());
|
cloudRecordItem.setFolder(param.getRecordInfo().getFolder());
|
||||||
cloudRecordItem.setFileSize(param.getFile_size());
|
cloudRecordItem.setFileSize(param.getRecordInfo().getFileSize());
|
||||||
cloudRecordItem.setFilePath(param.getFile_path());
|
cloudRecordItem.setFilePath(param.getRecordInfo().getFilePath());
|
||||||
cloudRecordItem.setMediaServerId(param.getMediaServerId());
|
cloudRecordItem.setMediaServerId(param.getMediaServer().getId());
|
||||||
cloudRecordItem.setTimeLen((long) param.getTime_len() * 1000);
|
cloudRecordItem.setTimeLen((long) param.getRecordInfo().getTimeLen() * 1000);
|
||||||
cloudRecordItem.setEndTime((param.getStart_time() + (long)param.getTime_len()) * 1000);
|
cloudRecordItem.setEndTime((param.getRecordInfo().getStartTime() + (long)param.getRecordInfo().getTimeLen()) * 1000);
|
||||||
return cloudRecordItem;
|
return cloudRecordItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -2,7 +2,7 @@ package com.genersoft.iot.vmp.service.bean;
|
|||||||
|
|
||||||
import com.alibaba.fastjson2.JSONObject;
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
|
import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
|
||||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
import com.genersoft.iot.vmp.media.bean.MediaServer;
|
||||||
|
|
||||||
import java.util.EventObject;
|
import java.util.EventObject;
|
||||||
|
|
||||||
@ -15,7 +15,7 @@ public class PlayBackResult<T> {
|
|||||||
|
|
||||||
private String msg;
|
private String msg;
|
||||||
private T data;
|
private T data;
|
||||||
private MediaServerItem mediaServerItem;
|
private MediaServer mediaServerItem;
|
||||||
private JSONObject response;
|
private JSONObject response;
|
||||||
private SipSubscribe.EventResult<EventObject> event;
|
private SipSubscribe.EventResult<EventObject> event;
|
||||||
|
|
||||||
@ -35,11 +35,11 @@ public class PlayBackResult<T> {
|
|||||||
this.data = data;
|
this.data = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
public MediaServerItem getMediaServerItem() {
|
public MediaServer getMediaServerItem() {
|
||||||
return mediaServerItem;
|
return mediaServerItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setMediaServerItem(MediaServerItem mediaServerItem) {
|
public void setMediaServerItem(MediaServer mediaServerItem) {
|
||||||
this.mediaServerItem = mediaServerItem;
|
this.mediaServerItem = mediaServerItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
package com.genersoft.iot.vmp.service.bean;
|
package com.genersoft.iot.vmp.service.bean;
|
||||||
|
|
||||||
|
import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* redis消息:请求下级推送流信息
|
* redis消息:请求下级推送流信息
|
||||||
* @author lin
|
* @author lin
|
||||||
@ -80,6 +82,22 @@ public class RequestPushStreamMsg {
|
|||||||
return requestPushStreamMsg;
|
return requestPushStreamMsg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static RequestPushStreamMsg getInstance(SendRtpItem sendRtpItem) {
|
||||||
|
RequestPushStreamMsg requestPushStreamMsg = new RequestPushStreamMsg();
|
||||||
|
requestPushStreamMsg.setMediaServerId(sendRtpItem.getMediaServerId());
|
||||||
|
requestPushStreamMsg.setApp(sendRtpItem.getApp());
|
||||||
|
requestPushStreamMsg.setStream(sendRtpItem.getStream());
|
||||||
|
requestPushStreamMsg.setIp(sendRtpItem.getIp());
|
||||||
|
requestPushStreamMsg.setPort(sendRtpItem.getPort());
|
||||||
|
requestPushStreamMsg.setSsrc(sendRtpItem.getSsrc());
|
||||||
|
requestPushStreamMsg.setTcp(sendRtpItem.isTcp());
|
||||||
|
requestPushStreamMsg.setSrcPort(sendRtpItem.getLocalPort());
|
||||||
|
requestPushStreamMsg.setPt(sendRtpItem.getPt());
|
||||||
|
requestPushStreamMsg.setPs(sendRtpItem.isUsePs());
|
||||||
|
requestPushStreamMsg.setOnlyAudio(sendRtpItem.isOnlyAudio());
|
||||||
|
return requestPushStreamMsg;
|
||||||
|
}
|
||||||
|
|
||||||
public String getMediaServerId() {
|
public String getMediaServerId() {
|
||||||
return mediaServerId;
|
return mediaServerId;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
package com.genersoft.iot.vmp.service.bean;
|
package com.genersoft.iot.vmp.service.bean;
|
||||||
|
|
||||||
import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
|
import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
|
||||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
import com.genersoft.iot.vmp.media.bean.MediaServer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* redis消息:下级回复推送信息
|
* redis消息:下级回复推送信息
|
||||||
@ -11,7 +11,7 @@ public class ResponseSendItemMsg {
|
|||||||
|
|
||||||
private SendRtpItem sendRtpItem;
|
private SendRtpItem sendRtpItem;
|
||||||
|
|
||||||
private MediaServerItem mediaServerItem;
|
private MediaServer mediaServerItem;
|
||||||
|
|
||||||
public SendRtpItem getSendRtpItem() {
|
public SendRtpItem getSendRtpItem() {
|
||||||
return sendRtpItem;
|
return sendRtpItem;
|
||||||
@ -21,11 +21,11 @@ public class ResponseSendItemMsg {
|
|||||||
this.sendRtpItem = sendRtpItem;
|
this.sendRtpItem = sendRtpItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
public MediaServerItem getMediaServerItem() {
|
public MediaServer getMediaServerItem() {
|
||||||
return mediaServerItem;
|
return mediaServerItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setMediaServerItem(MediaServerItem mediaServerItem) {
|
public void setMediaServerItem(MediaServer mediaServerItem) {
|
||||||
this.mediaServerItem = mediaServerItem;
|
this.mediaServerItem = mediaServerItem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user