添加zlm集群支持
This commit is contained in:
parent
06d78575cc
commit
89a9ab4534
10
pom.xml
10
pom.xml
@ -196,6 +196,16 @@
|
||||
<version>1.12</version>
|
||||
</dependency>
|
||||
|
||||
<!-- <!– 检测文件编码 –>-->
|
||||
<!-- <!– https://mvnrepository.com/artifact/cpdetector/cpdetector –>-->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>cpdetector</groupId>-->
|
||||
<!-- <artifactId>cpdetector</artifactId>-->
|
||||
<!-- <version>1.0.8</version>-->
|
||||
<!-- </dependency>-->
|
||||
|
||||
|
||||
|
||||
<!-- onvif协议栈 -->
|
||||
<dependency>
|
||||
<groupId>be.teletask</groupId>
|
||||
|
@ -138,6 +138,7 @@ create table stream_proxy
|
||||
timeout_ms int null,
|
||||
ffmpeg_cmd_key varchar(255) null,
|
||||
rtp_type varchar(50) null,
|
||||
mediaServerId varchar(50) null,
|
||||
enable_hls bit(1) null,
|
||||
enable_mp4 bit(1) null,
|
||||
enable bit(1) not null,
|
||||
@ -167,3 +168,27 @@ create table user
|
||||
);
|
||||
|
||||
insert into user (username, password, roleId, create_time) values ('admin', '21232f297a57a5a743894a0e4a801fc3', '0', '2021-04-13 14:14:57');
|
||||
|
||||
create table media_server (
|
||||
id varchar(255)
|
||||
primary key,
|
||||
ip varchar(50) NOT NULL,
|
||||
hookIp varchar(50) NOT NULL,
|
||||
sdpIp varchar(50) NOT NULL,
|
||||
streamIp varchar(50) NOT NULL,
|
||||
httpPort int NOT NULL,
|
||||
httpSSlPort int NOT NULL,
|
||||
rtmpPort int NOT NULL,
|
||||
rtmpSSlPort int NOT NULL,
|
||||
rtpProxyPort int NOT NULL,
|
||||
rtspPort int NOT NULL,
|
||||
rtspSSLPort int NOT NULL,
|
||||
autoConfig int NOT NULL,
|
||||
secret varchar(50) NOT NULL,
|
||||
streamNoneReaderDelayMS int NOT NULL,
|
||||
rtpEnable int NOT NULL,
|
||||
rtpPortRange varchar(50) NOT NULL,
|
||||
recordAssistPort int NOT NULL,
|
||||
createTime varchar(50) not null,
|
||||
updateTime varchar(50) not null
|
||||
);
|
@ -19,6 +19,7 @@ public class StreamInfo {
|
||||
private String rtmp;
|
||||
private String rtsp;
|
||||
private String rtc;
|
||||
private String mediaServerId;
|
||||
private JSONArray tracks;
|
||||
|
||||
public static class TransactionInfo{
|
||||
@ -165,4 +166,12 @@ public class StreamInfo {
|
||||
public void setTransactionInfo(TransactionInfo transactionInfo) {
|
||||
this.transactionInfo = transactionInfo;
|
||||
}
|
||||
|
||||
public String getMediaServerId() {
|
||||
return mediaServerId;
|
||||
}
|
||||
|
||||
public void setMediaServerId(String mediaServerId) {
|
||||
this.mediaServerId = mediaServerId;
|
||||
}
|
||||
}
|
||||
|
@ -10,33 +10,31 @@ public class VideoManagerConstants {
|
||||
|
||||
public static final String WVP_SERVER_PREFIX = "VMP_wvp_server";
|
||||
|
||||
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_STREAM_PREFIX = "VMP_media_stream";
|
||||
public static final String MEDIA_STREAM_PREFIX = "VMP_MEDIA_STREAM";
|
||||
|
||||
public static final String DEVICE_PREFIX = "VMP_device_";
|
||||
public static final String DEVICE_PREFIX = "VMP_DEVICE_";
|
||||
|
||||
public static final String CACHEKEY_PREFIX = "VMP_channel_";
|
||||
public static final String CACHEKEY_PREFIX = "VMP_CHANNEL_";
|
||||
|
||||
public static final String KEEPLIVEKEY_PREFIX = "VMP_keeplive_";
|
||||
|
||||
public static final String PLAYER_PREFIX = "VMP_player_";
|
||||
public static final String PLAYER_PREFIX = "VMP_PLAYER_";
|
||||
|
||||
public static final String PLAY_BLACK_PREFIX = "VMP_playback_";
|
||||
public static final String PLAY_BLACK_PREFIX = "VMP_PLAYBACK_";
|
||||
|
||||
public static final String PLATFORM_PREFIX = "VMP_platform";
|
||||
public static final String PLATFORM_KEEPLIVEKEY_PREFIX = "VMP_PLATFORM_KEEPLIVE_";
|
||||
|
||||
public static final String PLATFORM_KEEPLIVEKEY_PREFIX = "VMP_platform_keeplive_";
|
||||
public static final String PLATFORM_CATCH_PREFIX = "VMP_PLATFORM_CATCH_";
|
||||
|
||||
public static final String PLATFORM_CATCH_PREFIX = "VMP_platform_catch_";
|
||||
public static final String PLATFORM_REGISTER_PREFIX = "VMP_PLATFORM_REGISTER_";
|
||||
|
||||
public static final String PLATFORM_REGISTER_PREFIX = "VMP_platform_register_";
|
||||
public static final String PLATFORM_REGISTER_INFO_PREFIX = "VMP_PLATFORM_REGISTER_INFO_";
|
||||
|
||||
public static final String PLATFORM_REGISTER_INFO_PREFIX = "VMP_platform_register_info_";
|
||||
public static final String PLATFORM_SEND_RTP_INFO_PREFIX = "VMP_PLATFORM_SEND_RTP_INFO_";
|
||||
|
||||
public static final String PLATFORM_SEND_RTP_INFO_PREFIX = "VMP_platform_send_rtp_info_";
|
||||
|
||||
public static final String Pattern_Topic = "VMP_keeplive_platform_";
|
||||
public static final String Pattern_Topic = "VMP_KEEPLIVE_PLATFORM_";
|
||||
|
||||
public static final String EVENT_ONLINE_REGISTER = "1";
|
||||
|
||||
|
@ -1,11 +1,16 @@
|
||||
package com.genersoft.iot.vmp.conf;
|
||||
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
@Configuration("mediaConfig")
|
||||
public class MediaConfig {
|
||||
public class MediaConfig implements IMediaServerItem {
|
||||
|
||||
@Value("${media.id:}")
|
||||
private String id;
|
||||
|
||||
@Value("${media.ip}")
|
||||
private String ip;
|
||||
@ -25,22 +30,22 @@ public class MediaConfig {
|
||||
@Value("${media.http-port}")
|
||||
private Integer httpPort;
|
||||
|
||||
@Value("${media.http-ssl-port:}")
|
||||
@Value("${media.http-ssl-port:0}")
|
||||
private Integer httpSSlPort;
|
||||
|
||||
@Value("${media.rtmp-port:}")
|
||||
@Value("${media.rtmp-port:0}")
|
||||
private Integer rtmpPort;
|
||||
|
||||
@Value("${media.rtmp-ssl-port:}")
|
||||
@Value("${media.rtmp-ssl-port:0}")
|
||||
private Integer rtmpSSlPort;
|
||||
|
||||
@Value("${media.rtp-proxy-port:}")
|
||||
@Value("${media.rtp-proxy-port:0}")
|
||||
private Integer rtpProxyPort;
|
||||
|
||||
@Value("${media.rtsp-port:}")
|
||||
@Value("${media.rtsp-port:0}")
|
||||
private Integer rtspPort;
|
||||
|
||||
@Value("${media.rtsp-ssl-port:}")
|
||||
@Value("${media.rtsp-ssl-port:0}")
|
||||
private Integer rtspSSLPort;
|
||||
|
||||
@Value("${media.auto-config:true}")
|
||||
@ -61,6 +66,23 @@ public class MediaConfig {
|
||||
@Value("${media.record-assist-port:0}")
|
||||
private Integer recordAssistPort;
|
||||
|
||||
private String updateTime;
|
||||
|
||||
private String createTime;
|
||||
|
||||
private boolean docker = false;
|
||||
|
||||
private int count;
|
||||
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getIp() {
|
||||
return ip;
|
||||
}
|
||||
@ -82,82 +104,114 @@ public class MediaConfig {
|
||||
this.hookIp = hookIp;
|
||||
}
|
||||
|
||||
public String getSdpIp() {
|
||||
if (StringUtils.isEmpty(sdpIp)){
|
||||
return ip;
|
||||
}else {
|
||||
return sdpIp;
|
||||
}
|
||||
public String getSipIp() {
|
||||
return sipIp;
|
||||
}
|
||||
|
||||
public void setSipIp(String sipIp) {
|
||||
this.sipIp = sipIp;
|
||||
}
|
||||
|
||||
public void setSdpIp(String sdpIp) {
|
||||
this.sdpIp = sdpIp;
|
||||
}
|
||||
|
||||
public String getStreamIp() {
|
||||
if (StringUtils.isEmpty(streamIp)){
|
||||
return ip;
|
||||
}else {
|
||||
return streamIp;
|
||||
}
|
||||
}
|
||||
|
||||
public void setStreamIp(String streamIp) {
|
||||
this.streamIp = streamIp;
|
||||
}
|
||||
|
||||
public Integer getHttpPort() {
|
||||
public int getHttpPort() {
|
||||
return httpPort;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setHttpPort(int httpPort) {
|
||||
|
||||
}
|
||||
|
||||
public void setHttpPort(Integer httpPort) {
|
||||
this.httpPort = httpPort;
|
||||
}
|
||||
|
||||
public Integer getHttpSSlPort() {
|
||||
public int getHttpSSlPort() {
|
||||
return httpSSlPort;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setHttpSSlPort(int httpSSlPort) {
|
||||
|
||||
}
|
||||
|
||||
public void setHttpSSlPort(Integer httpSSlPort) {
|
||||
this.httpSSlPort = httpSSlPort;
|
||||
}
|
||||
|
||||
public Integer getRtmpPort() {
|
||||
public int getRtmpPort() {
|
||||
return rtmpPort;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRtmpPort(int rtmpPort) {
|
||||
|
||||
}
|
||||
|
||||
public void setRtmpPort(Integer rtmpPort) {
|
||||
this.rtmpPort = rtmpPort;
|
||||
}
|
||||
|
||||
public Integer getRtmpSSlPort() {
|
||||
public int getRtmpSSlPort() {
|
||||
return rtmpSSlPort;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRtmpSSlPort(int rtmpSSlPort) {
|
||||
|
||||
}
|
||||
|
||||
public void setRtmpSSlPort(Integer rtmpSSlPort) {
|
||||
this.rtmpSSlPort = rtmpSSlPort;
|
||||
}
|
||||
|
||||
public Integer getRtpProxyPort() {
|
||||
return rtpProxyPort;
|
||||
public int getRtpProxyPort() {
|
||||
if (rtpProxyPort == null) {
|
||||
return 0;
|
||||
}else {
|
||||
return rtpProxyPort;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRtpProxyPort(int rtpProxyPort) {
|
||||
|
||||
}
|
||||
|
||||
public void setRtpProxyPort(Integer rtpProxyPort) {
|
||||
this.rtpProxyPort = rtpProxyPort;
|
||||
}
|
||||
|
||||
public Integer getRtspPort() {
|
||||
public int getRtspPort() {
|
||||
return rtspPort;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRtspPort(int rtspPort) {
|
||||
|
||||
}
|
||||
|
||||
public void setRtspPort(Integer rtspPort) {
|
||||
this.rtspPort = rtspPort;
|
||||
}
|
||||
|
||||
public Integer getRtspSSLPort() {
|
||||
public int getRtspSSLPort() {
|
||||
return rtspSSLPort;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRtspSSLPort(int rtspSSLPort) {
|
||||
|
||||
}
|
||||
|
||||
public void setRtspSSLPort(Integer rtspSSLPort) {
|
||||
this.rtspSSLPort = rtspSSLPort;
|
||||
}
|
||||
@ -202,11 +256,101 @@ public class MediaConfig {
|
||||
this.rtpPortRange = rtpPortRange;
|
||||
}
|
||||
|
||||
public Integer getRecordAssistPort() {
|
||||
public int getRecordAssistPort() {
|
||||
return recordAssistPort;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRecordAssistPort(int recordAssistPort) {
|
||||
|
||||
}
|
||||
|
||||
public void setRecordAssistPort(Integer recordAssistPort) {
|
||||
this.recordAssistPort = recordAssistPort;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDocker() {
|
||||
return docker;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDocker(boolean docker) {
|
||||
this.docker = docker;
|
||||
}
|
||||
|
||||
public String getSdpIp() {
|
||||
if (StringUtils.isEmpty(sdpIp)){
|
||||
return ip;
|
||||
}else {
|
||||
return sdpIp;
|
||||
}
|
||||
}
|
||||
|
||||
public String getStreamIp() {
|
||||
if (StringUtils.isEmpty(streamIp)){
|
||||
return ip;
|
||||
}else {
|
||||
return streamIp;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public MediaServerItem getMediaSerItem(){
|
||||
MediaServerItem mediaServerItem = new MediaServerItem();
|
||||
mediaServerItem.setId(id);
|
||||
mediaServerItem.setIp(ip);
|
||||
mediaServerItem.setDocker(true);
|
||||
mediaServerItem.setHookIp(hookIp);
|
||||
mediaServerItem.setSdpIp(sdpIp);
|
||||
mediaServerItem.setStreamIp(streamIp);
|
||||
mediaServerItem.setHttpPort(httpPort);
|
||||
mediaServerItem.setHttpSSlPort(httpSSlPort);
|
||||
mediaServerItem.setRtmpPort(rtmpPort);
|
||||
mediaServerItem.setRtmpSSlPort(rtmpSSlPort);
|
||||
mediaServerItem.setRtpProxyPort(rtpProxyPort);
|
||||
mediaServerItem.setRtspPort(rtspPort);
|
||||
mediaServerItem.setRtspSSLPort(rtspSSLPort);
|
||||
mediaServerItem.setAutoConfig(autoConfig);
|
||||
mediaServerItem.setSecret(secret);
|
||||
mediaServerItem.setStreamNoneReaderDelayMS(streamNoneReaderDelayMS);
|
||||
mediaServerItem.setRtpEnable(rtpEnable);
|
||||
mediaServerItem.setRtpPortRange(rtpPortRange);
|
||||
mediaServerItem.setRecordAssistPort(recordAssistPort);
|
||||
mediaServerItem.setCreateTime(createTime);
|
||||
mediaServerItem.setUpdateTime(updateTime);
|
||||
mediaServerItem.setCount(count);
|
||||
return mediaServerItem;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUpdateTime() {
|
||||
return updateTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUpdateTime(String updateTime) {
|
||||
this.updateTime = updateTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCreateTime() {
|
||||
return createTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCreateTime(String createTime) {
|
||||
this.createTime = createTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return count;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCount(int count) {
|
||||
this.count = count;
|
||||
}
|
||||
}
|
||||
|
@ -1,12 +1,16 @@
|
||||
package com.genersoft.iot.vmp.conf;
|
||||
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
|
||||
import com.genersoft.iot.vmp.service.IMediaServerService;
|
||||
import org.apache.catalina.connector.ClientAbortException;
|
||||
import org.apache.http.HttpHost;
|
||||
import org.apache.http.HttpRequest;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.catalina.connector.ClientAbortException;
|
||||
import org.mitre.dsmiley.httpproxy.ProxyServlet;
|
||||
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.boot.web.servlet.ServletRegistrationBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
@ -24,13 +28,16 @@ public class ProxyServletConfig {
|
||||
private final static Logger logger = LoggerFactory.getLogger(ProxyServletConfig.class);
|
||||
|
||||
@Autowired
|
||||
private MediaConfig mediaConfig;
|
||||
private IMediaServerService mediaServerService;
|
||||
|
||||
@Value("${server.port}")
|
||||
private int serverPort;
|
||||
|
||||
@Bean
|
||||
public ServletRegistrationBean zlmServletRegistrationBean(){
|
||||
ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new ZLMProxySerlet(),"/zlm/*");
|
||||
servletRegistrationBean.setName("zlm_Proxy");
|
||||
servletRegistrationBean.addInitParameter("targetUri", String.format("http://%s:%s", mediaConfig.getIp(), mediaConfig.getHttpPort()));
|
||||
servletRegistrationBean.addInitParameter("targetUri", "http://127.0.0.1:6080");
|
||||
servletRegistrationBean.addUrlMappings();
|
||||
if (logger.isDebugEnabled()) {
|
||||
servletRegistrationBean.addInitParameter("log", "true");
|
||||
@ -38,24 +45,26 @@ public class ProxyServletConfig {
|
||||
return servletRegistrationBean;
|
||||
}
|
||||
|
||||
class ZLMProxySerlet extends ProxyServlet{
|
||||
|
||||
|
||||
|
||||
class ZLMProxySerlet extends ProxyServlet{
|
||||
@Override
|
||||
protected String rewriteQueryStringFromRequest(HttpServletRequest servletRequest, String queryString) {
|
||||
String queryStr = super.rewriteQueryStringFromRequest(servletRequest, queryString);
|
||||
if (!StringUtils.isEmpty(queryStr)) {
|
||||
queryStr += "&secret=" + mediaConfig.getSecret();
|
||||
}else {
|
||||
queryStr = "secret=" + mediaConfig.getSecret();
|
||||
IMediaServerItem mediaInfo = getMediaInfoByUri(servletRequest.getRequestURI());
|
||||
if (mediaInfo != null) {
|
||||
if (!StringUtils.isEmpty(queryStr)) {
|
||||
queryStr += "&secret=" + mediaInfo.getSecret();
|
||||
}else {
|
||||
queryStr = "secret=" + mediaInfo.getSecret();
|
||||
}
|
||||
}
|
||||
return queryStr;
|
||||
}
|
||||
|
||||
/**
|
||||
* 异常处理
|
||||
*/
|
||||
@Override
|
||||
protected void handleRequestException(HttpRequest proxyRequest, HttpResponse proxyResonse, Exception e){
|
||||
//System.out.println(e.getMessage());
|
||||
try {
|
||||
super.handleRequestException(proxyRequest, proxyResonse, e);
|
||||
} catch (ServletException servletException) {
|
||||
@ -72,6 +81,64 @@ public class ProxyServletConfig {
|
||||
logger.error("zlm 代理失败: ", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 对于为按照格式请求的可以直接返回404
|
||||
*/
|
||||
@Override
|
||||
protected String getTargetUri(HttpServletRequest servletRequest) {
|
||||
String requestURI = servletRequest.getRequestURI();
|
||||
IMediaServerItem mediaInfo = getMediaInfoByUri(requestURI);
|
||||
|
||||
String uri = null;
|
||||
if (mediaInfo != null) {
|
||||
// String realRequestURI = requestURI.substring(requestURI.indexOf(mediaInfo.getId())+ mediaInfo.getId().length());
|
||||
uri = String.format("http://%s:%s", mediaInfo.getIp(), mediaInfo.getHttpPort());
|
||||
}else {
|
||||
uri = "http://127.0.0.1:" + serverPort +"/index/hook/null"; // 只是一个能返回404的请求而已, 其他的也可以
|
||||
}
|
||||
return uri;
|
||||
}
|
||||
|
||||
/**
|
||||
* 动态替换请求目标
|
||||
*/
|
||||
@Override
|
||||
protected HttpHost getTargetHost(HttpServletRequest servletRequest) {
|
||||
String requestURI = servletRequest.getRequestURI();
|
||||
IMediaServerItem mediaInfo = getMediaInfoByUri(requestURI);
|
||||
HttpHost host;
|
||||
if (mediaInfo != null) {
|
||||
host = new HttpHost(mediaInfo.getIp(), mediaInfo.getHttpPort());
|
||||
}else {
|
||||
host = new HttpHost("127.0.0.1", serverPort);
|
||||
}
|
||||
return host;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据uri获取流媒体信息
|
||||
*/
|
||||
IMediaServerItem getMediaInfoByUri(String uri){
|
||||
String[] split = uri.split("/");
|
||||
String mediaServerId = split[2];
|
||||
return mediaServerService.getOne(mediaServerId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 去掉url中的标志信息
|
||||
*/
|
||||
@Override
|
||||
protected String rewriteUrlFromRequest(HttpServletRequest servletRequest) {
|
||||
String requestURI = servletRequest.getRequestURI();
|
||||
IMediaServerItem mediaInfo = getMediaInfoByUri(requestURI);
|
||||
String url = super.rewriteUrlFromRequest(servletRequest);
|
||||
if (mediaInfo == null) {
|
||||
return url;
|
||||
}
|
||||
return url.replace(mediaInfo.getId() + "/", "");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -95,20 +95,43 @@ public class SipLayer implements SipListener {
|
||||
tcpListeningPoint = sipStack.createListeningPoint(sipConfig.getMonitorIp(), sipConfig.getSipPort(), "TCP");
|
||||
tcpSipProvider = sipStack.createSipProvider(tcpListeningPoint);
|
||||
tcpSipProvider.addSipListener(this);
|
||||
logger.info("Sip Server TCP 启动成功 port {" + sipConfig.getSipPort() + "}");
|
||||
} catch (TransportNotSupportedException | InvalidArgumentException | TooManyListenersException | ObjectInUseException e) {
|
||||
logger.error(String.format("创建SIP服务失败: %s", e.getMessage()));
|
||||
logger.info("Sip Server TCP 启动成功 port {" + sipConfig.getMonitorIp() + ":" + sipConfig.getSipPort() + "}");
|
||||
// } catch (TransportNotSupportedException | InvalidArgumentException | TooManyListenersException | ObjectInUseException e) {
|
||||
// logger.error(String.format("创建SIP服务失败: %s", e.getMessage()));
|
||||
// }
|
||||
} catch (TransportNotSupportedException e) {
|
||||
e.printStackTrace();
|
||||
} catch (InvalidArgumentException e) {
|
||||
logger.error("无法使用 [ {}:{} ]作为SIP[ TCP ]服务,可排查: 1. sip.monitor-ip 是否为本机网卡IP; 2. sip.port 是否已被占用"
|
||||
, sipConfig.getMonitorIp(), sipConfig.getSipPort());
|
||||
} catch (TooManyListenersException e) {
|
||||
e.printStackTrace();
|
||||
} catch (ObjectInUseException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return tcpSipProvider;
|
||||
}
|
||||
|
||||
@Bean("udpSipProvider")
|
||||
@DependsOn("sipStack")
|
||||
private SipProvider startUdpListener() throws Exception {
|
||||
ListeningPoint udpListeningPoint = sipStack.createListeningPoint(sipConfig.getMonitorIp(), sipConfig.getSipPort(), "UDP");
|
||||
SipProvider udpSipProvider = sipStack.createSipProvider(udpListeningPoint);
|
||||
udpSipProvider.addSipListener(this);
|
||||
logger.info("Sip Server UDP 启动成功 port {" + sipConfig.getSipPort() + "}");
|
||||
private SipProvider startUdpListener() {
|
||||
ListeningPoint udpListeningPoint = null;
|
||||
SipProvider udpSipProvider = null;
|
||||
try {
|
||||
udpListeningPoint = sipStack.createListeningPoint(sipConfig.getMonitorIp(), sipConfig.getSipPort(), "UDP");
|
||||
udpSipProvider = sipStack.createSipProvider(udpListeningPoint);
|
||||
udpSipProvider.addSipListener(this);
|
||||
} catch (TransportNotSupportedException e) {
|
||||
e.printStackTrace();
|
||||
} catch (InvalidArgumentException e) {
|
||||
logger.error("无法使用 [ {}:{} ]作为SIP[ UDP ]服务,可排查: 1. sip.monitor-ip 是否为本机网卡IP; 2. sip.port 是否已被占用"
|
||||
, sipConfig.getMonitorIp(), sipConfig.getSipPort());
|
||||
} catch (TooManyListenersException e) {
|
||||
e.printStackTrace();
|
||||
} catch (ObjectInUseException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
logger.info("Sip Server UDP 启动成功 port [" + sipConfig.getMonitorIp() + ":" + sipConfig.getSipPort() + "]");
|
||||
return udpSipProvider;
|
||||
}
|
||||
|
||||
|
@ -94,6 +94,11 @@ public class Device {
|
||||
*/
|
||||
private String updateTime;
|
||||
|
||||
/**
|
||||
* 设备使用的媒体id, 默认为null
|
||||
*/
|
||||
private String mediaServerId;
|
||||
|
||||
public String getDeviceId() {
|
||||
return deviceId;
|
||||
}
|
||||
@ -229,4 +234,12 @@ public class Device {
|
||||
public void setUpdateTime(String updateTime) {
|
||||
this.updateTime = updateTime;
|
||||
}
|
||||
|
||||
public String getMediaServerId() {
|
||||
return mediaServerId;
|
||||
}
|
||||
|
||||
public void setMediaServerId(String mediaServerId) {
|
||||
this.mediaServerId = mediaServerId;
|
||||
}
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ public class GbStream extends PlatformGbStream{
|
||||
private String stream;
|
||||
private String gbId;
|
||||
private String name;
|
||||
private String mediaServerId;
|
||||
private double longitude;
|
||||
private double latitude;
|
||||
private String streamType;
|
||||
@ -77,4 +78,12 @@ public class GbStream extends PlatformGbStream{
|
||||
public void setStatus(boolean status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public String getMediaServerId() {
|
||||
return mediaServerId;
|
||||
}
|
||||
|
||||
public void setMediaServerId(String mediaServerId) {
|
||||
this.mediaServerId = mediaServerId;
|
||||
}
|
||||
}
|
||||
|
@ -66,6 +66,11 @@ public class SendRtpItem {
|
||||
*/
|
||||
private int localPort;
|
||||
|
||||
/**
|
||||
* 使用的流媒体
|
||||
*/
|
||||
private String mediaServerId;
|
||||
|
||||
public String getIp() {
|
||||
return ip;
|
||||
}
|
||||
@ -161,4 +166,12 @@ public class SendRtpItem {
|
||||
public void setTcpActive(boolean tcpActive) {
|
||||
this.tcpActive = tcpActive;
|
||||
}
|
||||
|
||||
public String getMediaServerId() {
|
||||
return mediaServerId;
|
||||
}
|
||||
|
||||
public void setMediaServerId(String mediaServerId) {
|
||||
this.mediaServerId = mediaServerId;
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,9 @@ import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
|
||||
import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
|
||||
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform;
|
||||
import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
||||
import com.genersoft.iot.vmp.service.IMediaServerService;
|
||||
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
|
||||
import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
|
||||
import org.slf4j.Logger;
|
||||
@ -32,6 +35,8 @@ public class PlatformNotRegisterEventLister implements ApplicationListener<Platf
|
||||
private IVideoManagerStorager storager;
|
||||
@Autowired
|
||||
private IRedisCatchStorage redisCatchStorage;
|
||||
@Autowired
|
||||
private IMediaServerService mediaServerService;
|
||||
|
||||
@Autowired
|
||||
private SIPCommanderFroPlatform sipCommanderFroPlatform;
|
||||
@ -62,22 +67,24 @@ public class PlatformNotRegisterEventLister implements ApplicationListener<Platf
|
||||
logger.info("停止[ {} ]的所有推流", event.getPlatformGbID());
|
||||
StringBuilder app = new StringBuilder();
|
||||
StringBuilder stream = new StringBuilder();
|
||||
for (int i = 0; i < sendRtpItems.size(); i++) {
|
||||
for (SendRtpItem sendRtpItem : sendRtpItems) {
|
||||
if (app.length() != 0) {
|
||||
app.append(",");
|
||||
}
|
||||
app.append(sendRtpItems.get(i).getApp());
|
||||
app.append(sendRtpItem.getApp());
|
||||
if (stream.length() != 0) {
|
||||
stream.append(",");
|
||||
}
|
||||
stream.append(sendRtpItems.get(i).getStreamId());
|
||||
redisCatchStorage.deleteSendRTPServer(event.getPlatformGbID(), sendRtpItems.get(i).getChannelId());
|
||||
stream.append(sendRtpItem.getStreamId());
|
||||
redisCatchStorage.deleteSendRTPServer(event.getPlatformGbID(), sendRtpItem.getChannelId());
|
||||
IMediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId());
|
||||
Map<String, Object> param = new HashMap<>();
|
||||
param.put("vhost", "__defaultVhost__");
|
||||
param.put("app", app.toString());
|
||||
param.put("stream", stream.toString());
|
||||
zlmrtpServerFactory.stopSendRtpStream(mediaInfo, param);
|
||||
}
|
||||
Map<String, Object> param = new HashMap<>();
|
||||
param.put("vhost","__defaultVhost__");
|
||||
param.put("app", app.toString());
|
||||
param.put("stream", stream.toString());
|
||||
zlmrtpServerFactory.stopSendRtpStream(param);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
@ -9,6 +9,7 @@ import javax.sip.message.Response;
|
||||
|
||||
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform;
|
||||
import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
|
||||
import com.genersoft.iot.vmp.service.IMediaServerService;
|
||||
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
|
||||
import com.genersoft.iot.vmp.gb28181.transmit.response.impl.*;
|
||||
import com.genersoft.iot.vmp.service.IPlayService;
|
||||
@ -104,6 +105,9 @@ public class SIPProcessorFactory {
|
||||
@Autowired
|
||||
private ZLMRTPServerFactory zlmrtpServerFactory;
|
||||
|
||||
@Autowired
|
||||
private IMediaServerService mediaServerService;
|
||||
|
||||
|
||||
// 注:这里使用注解会导致循环依赖注入,暂用springBean
|
||||
private SipProvider tcpSipProvider;
|
||||
@ -128,6 +132,7 @@ public class SIPProcessorFactory {
|
||||
processor.setStorager(storager);
|
||||
processor.setRedisCatchStorage(redisCatchStorage);
|
||||
processor.setZlmrtpServerFactory(zlmrtpServerFactory);
|
||||
processor.setMediaServerService(mediaServerService);
|
||||
return processor;
|
||||
} else if (Request.REGISTER.equals(method)) {
|
||||
RegisterRequestProcessor processor = new RegisterRequestProcessor();
|
||||
@ -148,6 +153,7 @@ public class SIPProcessorFactory {
|
||||
processor.setRequestEvent(evt);
|
||||
processor.setRedisCatchStorage(redisCatchStorage);
|
||||
processor.setZlmrtpServerFactory(zlmrtpServerFactory);
|
||||
processor.setMediaServerService(mediaServerService);
|
||||
return processor;
|
||||
} else if (Request.BYE.equals(method)) {
|
||||
ByeRequestProcessor processor = new ByeRequestProcessor();
|
||||
@ -155,6 +161,7 @@ public class SIPProcessorFactory {
|
||||
processor.setRedisCatchStorage(redisCatchStorage);
|
||||
processor.setZlmrtpServerFactory(zlmrtpServerFactory);
|
||||
processor.setSIPCommander(cmder);
|
||||
processor.setMediaServerService(mediaServerService);
|
||||
return processor;
|
||||
} else if (Request.CANCEL.equals(method)) {
|
||||
CancelRequestProcessor processor = new CancelRequestProcessor();
|
||||
|
@ -3,6 +3,8 @@ package com.genersoft.iot.vmp.gb28181.transmit.cmd;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.Device;
|
||||
import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
|
||||
import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
||||
|
||||
/**
|
||||
* @Description:设备能力接口,用于定义设备的控制、查询能力
|
||||
@ -90,7 +92,7 @@ public interface ISIPCommander {
|
||||
* @param device 视频设备
|
||||
* @param channelId 预览通道
|
||||
*/
|
||||
void playStreamCmd(Device device, String channelId, ZLMHttpHookSubscribe.Event event, SipSubscribe.Event errorEvent);
|
||||
void playStreamCmd(IMediaServerItem mediaServerItem, Device device, String channelId, ZLMHttpHookSubscribe.Event event, SipSubscribe.Event errorEvent);
|
||||
|
||||
/**
|
||||
* 请求回放视频流
|
||||
@ -100,7 +102,7 @@ public interface ISIPCommander {
|
||||
* @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss
|
||||
* @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss
|
||||
*/
|
||||
void playbackStreamCmd(Device device, String channelId, String startTime, String endTime, ZLMHttpHookSubscribe.Event event, SipSubscribe.Event errorEvent);
|
||||
void playbackStreamCmd(IMediaServerItem mediaServerItem,Device device, String channelId, String startTime, String endTime, ZLMHttpHookSubscribe.Event event, SipSubscribe.Event errorEvent);
|
||||
|
||||
/**
|
||||
* 视频流停止
|
||||
@ -288,12 +290,4 @@ public interface ISIPCommander {
|
||||
* @return true = 命令发送成功
|
||||
*/
|
||||
boolean alarmSubscribe(Device device, int expires, String startPriority, String endPriority, String alarmMethod, String alarmType, String startTime, String endTime);
|
||||
|
||||
|
||||
/**
|
||||
* 释放rtpserver
|
||||
* @param device
|
||||
* @param channelId
|
||||
*/
|
||||
void closeRTPServer(Device device, String channelId);
|
||||
}
|
||||
|
@ -13,11 +13,10 @@ import com.alibaba.fastjson.JSONObject;
|
||||
import com.genersoft.iot.vmp.common.StreamInfo;
|
||||
import com.genersoft.iot.vmp.conf.MediaConfig;
|
||||
import com.genersoft.iot.vmp.conf.UserSetup;
|
||||
import com.genersoft.iot.vmp.media.zlm.ZLMServerConfig;
|
||||
import com.genersoft.iot.vmp.media.zlm.*;
|
||||
import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
|
||||
import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe;
|
||||
import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
|
||||
import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
||||
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
|
||||
import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
|
||||
import gov.nist.javax.sip.message.SIPRequest;
|
||||
@ -37,6 +36,7 @@ import com.genersoft.iot.vmp.gb28181.transmit.cmd.SIPRequestHeaderProvider;
|
||||
import com.genersoft.iot.vmp.gb28181.utils.DateUtil;
|
||||
import com.genersoft.iot.vmp.gb28181.utils.NumericUtil;
|
||||
import com.genersoft.iot.vmp.gb28181.utils.XmlUtil;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* @Description:设备能力接口,用于定义设备的控制、查询能力
|
||||
@ -77,12 +77,6 @@ public class SIPCommander implements ISIPCommander {
|
||||
@Autowired
|
||||
private ZLMRTPServerFactory zlmrtpServerFactory;
|
||||
|
||||
@Autowired
|
||||
private ZLMRESTfulUtils zlmresTfulUtils;
|
||||
|
||||
@Autowired
|
||||
private MediaConfig mediaConfig;
|
||||
|
||||
@Autowired
|
||||
private UserSetup userSetup;
|
||||
|
||||
@ -340,48 +334,45 @@ public class SIPCommander implements ISIPCommander {
|
||||
* @param errorEvent sip错误订阅
|
||||
*/
|
||||
@Override
|
||||
public void playStreamCmd(Device device, String channelId, ZLMHttpHookSubscribe.Event event, SipSubscribe.Event errorEvent) {
|
||||
public void playStreamCmd(IMediaServerItem mediaServerItem, Device device, String channelId, ZLMHttpHookSubscribe.Event event, SipSubscribe.Event errorEvent) {
|
||||
String streamId = null;
|
||||
try {
|
||||
if (device == null) return;
|
||||
String streamMode = device.getStreamMode().toUpperCase();
|
||||
|
||||
String ssrc = streamSession.createPlaySsrc();
|
||||
if (mediaConfig.isRtpEnable()) {
|
||||
if (mediaServerItem.isRtpEnable()) {
|
||||
streamId = String.format("gb_play_%s_%s", device.getDeviceId(), channelId);
|
||||
}else {
|
||||
streamId = String.format("%08x", Integer.parseInt(ssrc)).toUpperCase();
|
||||
}
|
||||
String streamMode = device.getStreamMode().toUpperCase();
|
||||
ZLMServerConfig mediaInfo = redisCatchStorage.getMediaInfo();
|
||||
if (mediaInfo == null) {
|
||||
logger.warn("点播时发现ZLM尚未连接...");
|
||||
return;
|
||||
}
|
||||
Integer mediaPort = null;
|
||||
// 使用动态udp端口
|
||||
if (mediaConfig.isRtpEnable()) {
|
||||
mediaPort = zlmrtpServerFactory.createRTPServer(streamId);
|
||||
if (mediaServerItem.isRtpEnable()) {
|
||||
mediaPort = zlmrtpServerFactory.createRTPServer(mediaServerItem, streamId);
|
||||
}else {
|
||||
mediaPort = mediaInfo.getRtpProxyPort();
|
||||
mediaPort = mediaServerItem.getRtpProxyPort();
|
||||
}
|
||||
|
||||
logger.info("{} 分配的ZLM为: {} [{}:{}]", streamId, mediaServerItem.getId(), mediaServerItem.getIp(), mediaPort);
|
||||
// 添加订阅
|
||||
JSONObject subscribeKey = new JSONObject();
|
||||
subscribeKey.put("app", "rtp");
|
||||
subscribeKey.put("stream", streamId);
|
||||
subscribeKey.put("regist", true);
|
||||
|
||||
subscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey, json->{
|
||||
subscribeKey.put("mediaServerId", mediaServerItem.getId());
|
||||
subscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey,
|
||||
(IMediaServerItem mediaServerItemInUse, JSONObject json)->{
|
||||
if (userSetup.isWaitTrack() && json.getJSONArray("tracks") == null) return;
|
||||
event.response(json);
|
||||
event.response(mediaServerItemInUse, json);
|
||||
subscribe.removeSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey);
|
||||
});
|
||||
//
|
||||
StringBuffer content = new StringBuffer(200);
|
||||
content.append("v=0\r\n");
|
||||
// content.append("o=" + sipConfig.getSipId() + " 0 0 IN IP4 "+mediaInfo.getWanIp()+"\r\n");
|
||||
content.append("o="+"00000"+" 0 0 IN IP4 "+mediaInfo.getSdpIp()+"\r\n");
|
||||
content.append("o="+"00000"+" 0 0 IN IP4 "+ mediaServerItem.getSdpIp() +"\r\n");
|
||||
content.append("s=Play\r\n");
|
||||
content.append("c=IN IP4 "+mediaInfo.getSdpIp()+"\r\n");
|
||||
content.append("c=IN IP4 "+ mediaServerItem.getSdpIp() +"\r\n");
|
||||
content.append("t=0 0\r\n");
|
||||
|
||||
if (userSetup.isSeniorSdp()) {
|
||||
@ -459,21 +450,32 @@ public class SIPCommander implements ISIPCommander {
|
||||
* @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss
|
||||
*/
|
||||
@Override
|
||||
public void playbackStreamCmd(Device device, String channelId, String startTime, String endTime, ZLMHttpHookSubscribe.Event event
|
||||
public void playbackStreamCmd(IMediaServerItem mediaServerItem,Device device, String channelId, String startTime, String endTime, ZLMHttpHookSubscribe.Event event
|
||||
, SipSubscribe.Event errorEvent) {
|
||||
try {
|
||||
ZLMServerConfig mediaInfo = redisCatchStorage.getMediaInfo();
|
||||
String ssrc = streamSession.createPlayBackSsrc();
|
||||
String streamId = String.format("%08x", Integer.parseInt(ssrc)).toUpperCase();
|
||||
|
||||
Integer mediaPort = null;
|
||||
// 使用动态udp端口
|
||||
if (mediaServerItem.isRtpEnable()) {
|
||||
mediaPort = zlmrtpServerFactory.createRTPServer(mediaServerItem, streamId);
|
||||
}else {
|
||||
mediaPort = mediaServerItem.getRtpProxyPort();
|
||||
}
|
||||
logger.info("{} 分配的ZLM为: {} [{}:{}]", streamId, mediaServerItem.getId(), mediaServerItem.getIp(), mediaPort);
|
||||
|
||||
// 添加订阅
|
||||
JSONObject subscribeKey = new JSONObject();
|
||||
subscribeKey.put("app", "rtp");
|
||||
subscribeKey.put("stream", streamId);
|
||||
subscribeKey.put("regist", true);
|
||||
subscribeKey.put("mediaServerId", mediaServerItem.getId());
|
||||
logger.debug("录像回放添加订阅,订阅内容:" + subscribeKey.toString());
|
||||
subscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey, json->{
|
||||
subscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey,
|
||||
(IMediaServerItem mediaServerItemInUse, JSONObject json)->{
|
||||
if (userSetup.isWaitTrack() && json.getJSONArray("tracks") == null) return;
|
||||
event.response(json);
|
||||
event.response(mediaServerItemInUse, json);
|
||||
subscribe.removeSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey);
|
||||
});
|
||||
|
||||
@ -482,16 +484,12 @@ public class SIPCommander implements ISIPCommander {
|
||||
content.append("o="+sipConfig.getSipId()+" 0 0 IN IP4 "+sipConfig.getSipIp()+"\r\n");
|
||||
content.append("s=Playback\r\n");
|
||||
content.append("u="+channelId+":0\r\n");
|
||||
content.append("c=IN IP4 "+mediaInfo.getSdpIp()+"\r\n");
|
||||
content.append("c=IN IP4 "+mediaServerItem.getSdpIp()+"\r\n");
|
||||
content.append("t="+DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(startTime)+" "
|
||||
+DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(endTime) +"\r\n");
|
||||
Integer mediaPort = null;
|
||||
// 使用动态udp端口
|
||||
if (mediaConfig.isRtpEnable()) {
|
||||
mediaPort = zlmrtpServerFactory.createRTPServer(streamId);
|
||||
}else {
|
||||
mediaPort = mediaInfo.getRtpProxyPort();
|
||||
}
|
||||
|
||||
|
||||
|
||||
String streamMode = device.getStreamMode().toUpperCase();
|
||||
|
||||
if (userSetup.isSeniorSdp()) {
|
||||
@ -560,56 +558,63 @@ public class SIPCommander implements ISIPCommander {
|
||||
|
||||
|
||||
/**
|
||||
* 视频流停止
|
||||
*
|
||||
* 视频流停止, 不使用回调
|
||||
*/
|
||||
@Override
|
||||
public void streamByeCmd(String deviceId, String channelId) {
|
||||
streamByeCmd(deviceId, channelId, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 视频流停止
|
||||
*/
|
||||
@Override
|
||||
public void streamByeCmd(String deviceId, String channelId, SipSubscribe.Event okEvent) {
|
||||
|
||||
StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(deviceId, channelId);
|
||||
try {
|
||||
ClientTransaction transaction = streamSession.getTransaction(deviceId, channelId);
|
||||
// 服务重启后, 无法直接发送bye, 通过手动构建发送
|
||||
// if (transaction == null) {
|
||||
//
|
||||
// if (streamInfo != null) {
|
||||
// MediaServerItem mediaServerItem = redisCatchStorage.getMediaInfo(streamInfo.getMediaServerId());
|
||||
// JSONObject mediaList = zlmresTfulUtils.getMediaList(mediaServerItem,streamInfo.getApp(), streamInfo.getStreamId());
|
||||
// if (mediaList != null) { // 仍在推流才发送
|
||||
// if (mediaList.getInteger("code") == 0) {
|
||||
// JSONArray data = mediaList.getJSONArray("data");
|
||||
// if (data != null && data.size() > 0) {
|
||||
// Device device = storager.queryVideoDevice(deviceId);
|
||||
// if (device != null) {
|
||||
// StreamInfo.TransactionInfo transactionInfo = streamInfo.getTransactionInfo();
|
||||
// try {
|
||||
// Request byteRequest = headerProvider.createByteRequest(device, channelId,
|
||||
// transactionInfo.branch,
|
||||
// transactionInfo.localTag,
|
||||
// transactionInfo.remoteTag,
|
||||
// transactionInfo.callId);
|
||||
// transmitRequest(device, byteRequest);
|
||||
// } catch (InvalidArgumentException e) {
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// redisCatchStorage.stopPlay(streamInfo);
|
||||
// }
|
||||
//
|
||||
// if (okEvent != null) {
|
||||
// okEvent.response(null);
|
||||
// }
|
||||
// return;
|
||||
// }
|
||||
if (transaction == null) {
|
||||
|
||||
StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(deviceId, channelId);
|
||||
if (streamInfo != null) {
|
||||
JSONObject mediaList = zlmresTfulUtils.getMediaList(streamInfo.getApp(), streamInfo.getStreamId());
|
||||
if (mediaList != null) { // 仍在推流才发送
|
||||
if (mediaList.getInteger("code") == 0) {
|
||||
JSONArray data = mediaList.getJSONArray("data");
|
||||
if (data != null && data.size() > 0) {
|
||||
Device device = storager.queryVideoDevice(deviceId);
|
||||
if (device != null) {
|
||||
StreamInfo.TransactionInfo transactionInfo = streamInfo.getTransactionInfo();
|
||||
try {
|
||||
Request byteRequest = headerProvider.createByteRequest(device, channelId,
|
||||
transactionInfo.branch,
|
||||
transactionInfo.localTag,
|
||||
transactionInfo.remoteTag,
|
||||
transactionInfo.callId);
|
||||
transmitRequest(device, byteRequest);
|
||||
} catch (InvalidArgumentException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
redisCatchStorage.stopPlay(streamInfo);
|
||||
}
|
||||
|
||||
if (okEvent != null) {
|
||||
okEvent.response(null);
|
||||
}
|
||||
logger.warn("[ {} -> {}]停止视频流的时候发现事务已丢失", deviceId, channelId);
|
||||
return;
|
||||
}
|
||||
|
||||
Dialog dialog = transaction.getDialog();
|
||||
if (dialog == null) {
|
||||
logger.warn("[ {} -> {}]停止视频流的时候发现对话已丢失", deviceId, channelId);
|
||||
return;
|
||||
}
|
||||
Request byeRequest = dialog.createRequest(Request.BYE);
|
||||
@ -632,7 +637,7 @@ public class SIPCommander implements ISIPCommander {
|
||||
}
|
||||
|
||||
dialog.sendRequest(clientTransaction);
|
||||
zlmrtpServerFactory.closeRTPServer(streamSession.getStreamId(deviceId, channelId));
|
||||
|
||||
streamSession.remove(deviceId, channelId);
|
||||
} catch (SipException | ParseException e) {
|
||||
e.printStackTrace();
|
||||
@ -721,7 +726,7 @@ public class SIPCommander implements ISIPCommander {
|
||||
cmdXml.append("<Control>\r\n");
|
||||
cmdXml.append("<CmdType>DeviceControl</CmdType>\r\n");
|
||||
cmdXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
|
||||
if (XmlUtil.isEmpty(channelId)) {
|
||||
if (StringUtils.isEmpty(channelId)) {
|
||||
cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
|
||||
} else {
|
||||
cmdXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
|
||||
@ -821,16 +826,16 @@ public class SIPCommander implements ISIPCommander {
|
||||
cmdXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
|
||||
cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
|
||||
cmdXml.append("<AlarmCmd>ResetAlarm</AlarmCmd>\r\n");
|
||||
if (!XmlUtil.isEmpty(alarmMethod) || !XmlUtil.isEmpty(alarmType)) {
|
||||
if (!StringUtils.isEmpty(alarmMethod) || !StringUtils.isEmpty(alarmType)) {
|
||||
cmdXml.append("<Info>\r\n");
|
||||
}
|
||||
if (!XmlUtil.isEmpty(alarmMethod)) {
|
||||
if (!StringUtils.isEmpty(alarmMethod)) {
|
||||
cmdXml.append("<AlarmMethod>" + alarmMethod + "</AlarmMethod>\r\n");
|
||||
}
|
||||
if (!XmlUtil.isEmpty(alarmType)) {
|
||||
if (!StringUtils.isEmpty(alarmType)) {
|
||||
cmdXml.append("<AlarmType>" + alarmType + "</AlarmType>\r\n");
|
||||
}
|
||||
if (!XmlUtil.isEmpty(alarmMethod) || !XmlUtil.isEmpty(alarmType)) {
|
||||
if (!StringUtils.isEmpty(alarmMethod) || !StringUtils.isEmpty(alarmType)) {
|
||||
cmdXml.append("</Info>\r\n");
|
||||
}
|
||||
cmdXml.append("</Control>\r\n");
|
||||
@ -863,7 +868,7 @@ public class SIPCommander implements ISIPCommander {
|
||||
cmdXml.append("<Control>\r\n");
|
||||
cmdXml.append("<CmdType>DeviceControl</CmdType>\r\n");
|
||||
cmdXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
|
||||
if (XmlUtil.isEmpty(channelId)) {
|
||||
if (StringUtils.isEmpty(channelId)) {
|
||||
cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
|
||||
} else {
|
||||
cmdXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
|
||||
@ -901,7 +906,7 @@ public class SIPCommander implements ISIPCommander {
|
||||
cmdXml.append("<Control>\r\n");
|
||||
cmdXml.append("<CmdType>DeviceControl</CmdType>\r\n");
|
||||
cmdXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
|
||||
if (XmlUtil.isEmpty(channelId)) {
|
||||
if (StringUtils.isEmpty(channelId)) {
|
||||
cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
|
||||
} else {
|
||||
cmdXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
|
||||
@ -969,13 +974,13 @@ public class SIPCommander implements ISIPCommander {
|
||||
cmdXml.append("<Control>\r\n");
|
||||
cmdXml.append("<CmdType>DeviceConfig</CmdType>\r\n");
|
||||
cmdXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
|
||||
if (XmlUtil.isEmpty(channelId)) {
|
||||
if (StringUtils.isEmpty(channelId)) {
|
||||
cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
|
||||
} else {
|
||||
cmdXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
|
||||
}
|
||||
cmdXml.append("<BasicParam>\r\n");
|
||||
if (!XmlUtil.isEmpty(name)) {
|
||||
if (!StringUtils.isEmpty(name)) {
|
||||
cmdXml.append("<Name>" + name + "</Name>\r\n");
|
||||
}
|
||||
if (NumericUtil.isInteger(expiration)) {
|
||||
@ -1169,22 +1174,22 @@ public class SIPCommander implements ISIPCommander {
|
||||
cmdXml.append("<CmdType>Alarm</CmdType>\r\n");
|
||||
cmdXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
|
||||
cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
|
||||
if (!XmlUtil.isEmpty(startPriority)) {
|
||||
if (!StringUtils.isEmpty(startPriority)) {
|
||||
cmdXml.append("<StartAlarmPriority>" + startPriority + "</StartAlarmPriority>\r\n");
|
||||
}
|
||||
if (!XmlUtil.isEmpty(endPriority)) {
|
||||
if (!StringUtils.isEmpty(endPriority)) {
|
||||
cmdXml.append("<EndAlarmPriority>" + endPriority + "</EndAlarmPriority>\r\n");
|
||||
}
|
||||
if (!XmlUtil.isEmpty(alarmMethod)) {
|
||||
if (!StringUtils.isEmpty(alarmMethod)) {
|
||||
cmdXml.append("<AlarmMethod>" + alarmMethod + "</AlarmMethod>\r\n");
|
||||
}
|
||||
if (!XmlUtil.isEmpty(alarmType)) {
|
||||
if (!StringUtils.isEmpty(alarmType)) {
|
||||
cmdXml.append("<AlarmType>" + alarmType + "</AlarmType>\r\n");
|
||||
}
|
||||
if (!XmlUtil.isEmpty(startTime)) {
|
||||
if (!StringUtils.isEmpty(startTime)) {
|
||||
cmdXml.append("<StartAlarmTime>" + startTime + "</StartAlarmTime>\r\n");
|
||||
}
|
||||
if (!XmlUtil.isEmpty(endTime)) {
|
||||
if (!StringUtils.isEmpty(endTime)) {
|
||||
cmdXml.append("<EndAlarmTime>" + endTime + "</EndAlarmTime>\r\n");
|
||||
}
|
||||
cmdXml.append("</Query>\r\n");
|
||||
@ -1218,7 +1223,7 @@ public class SIPCommander implements ISIPCommander {
|
||||
cmdXml.append("<Query>\r\n");
|
||||
cmdXml.append("<CmdType>ConfigDownload</CmdType>\r\n");
|
||||
cmdXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
|
||||
if (XmlUtil.isEmpty(channelId)) {
|
||||
if (StringUtils.isEmpty(channelId)) {
|
||||
cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
|
||||
} else {
|
||||
cmdXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
|
||||
@ -1253,7 +1258,7 @@ public class SIPCommander implements ISIPCommander {
|
||||
cmdXml.append("<Query>\r\n");
|
||||
cmdXml.append("<CmdType>PresetQuery</CmdType>\r\n");
|
||||
cmdXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
|
||||
if (XmlUtil.isEmpty(channelId)) {
|
||||
if (StringUtils.isEmpty(channelId)) {
|
||||
cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
|
||||
} else {
|
||||
cmdXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
|
||||
@ -1365,22 +1370,22 @@ public class SIPCommander implements ISIPCommander {
|
||||
cmdXml.append("<CmdType>Alarm</CmdType>\r\n");
|
||||
cmdXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
|
||||
cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
|
||||
if (!XmlUtil.isEmpty(startPriority)) {
|
||||
if (!StringUtils.isEmpty(startPriority)) {
|
||||
cmdXml.append("<StartAlarmPriority>" + startPriority + "</StartAlarmPriority>\r\n");
|
||||
}
|
||||
if (!XmlUtil.isEmpty(endPriority)) {
|
||||
if (!StringUtils.isEmpty(endPriority)) {
|
||||
cmdXml.append("<EndAlarmPriority>" + endPriority + "</EndAlarmPriority>\r\n");
|
||||
}
|
||||
if (!XmlUtil.isEmpty(alarmMethod)) {
|
||||
if (!StringUtils.isEmpty(alarmMethod)) {
|
||||
cmdXml.append("<AlarmMethod>" + alarmMethod + "</AlarmMethod>\r\n");
|
||||
}
|
||||
if (!XmlUtil.isEmpty(alarmType)) {
|
||||
if (!StringUtils.isEmpty(alarmType)) {
|
||||
cmdXml.append("<AlarmType>" + alarmType + "</AlarmType>\r\n");
|
||||
}
|
||||
if (!XmlUtil.isEmpty(startTime)) {
|
||||
if (!StringUtils.isEmpty(startTime)) {
|
||||
cmdXml.append("<StartAlarmTime>" + startTime + "</StartAlarmTime>\r\n");
|
||||
}
|
||||
if (!XmlUtil.isEmpty(endTime)) {
|
||||
if (!StringUtils.isEmpty(endTime)) {
|
||||
cmdXml.append("<EndAlarmTime>" + endTime + "</EndAlarmTime>\r\n");
|
||||
}
|
||||
cmdXml.append("</Query>\r\n");
|
||||
@ -1431,16 +1436,4 @@ public class SIPCommander implements ISIPCommander {
|
||||
clientTransaction.sendRequest();
|
||||
return clientTransaction;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public void closeRTPServer(Device device, String channelId) {
|
||||
if (mediaConfig.isRtpEnable()) {
|
||||
String streamId = String.format("gb_play_%s_%s", device.getDeviceId(), channelId);
|
||||
zlmrtpServerFactory.closeRTPServer(streamId);
|
||||
}
|
||||
streamSession.remove(device.getDeviceId(), channelId);
|
||||
}
|
||||
}
|
||||
|
@ -16,6 +16,8 @@ import javax.sip.message.Request;
|
||||
import gov.nist.javax.sip.SipStackImpl;
|
||||
import gov.nist.javax.sip.message.SIPRequest;
|
||||
import gov.nist.javax.sip.stack.SIPServerTransaction;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* @Description:处理接收IPCamera发来的SIP协议请求消息
|
||||
@ -24,6 +26,8 @@ import gov.nist.javax.sip.stack.SIPServerTransaction;
|
||||
*/
|
||||
public abstract class SIPRequestAbstractProcessor implements ISIPRequestProcessor {
|
||||
|
||||
private final static Logger logger = LoggerFactory.getLogger(SIPRequestAbstractProcessor.class);
|
||||
|
||||
protected RequestEvent evt;
|
||||
|
||||
private SipProvider tcpSipProvider;
|
||||
@ -64,9 +68,9 @@ public abstract class SIPRequestAbstractProcessor implements ISIPRequestProcesso
|
||||
}
|
||||
}
|
||||
} catch (TransactionAlreadyExistsException e) {
|
||||
e.printStackTrace();
|
||||
logger.error(e.getMessage());
|
||||
} catch (TransactionUnavailableException e) {
|
||||
e.printStackTrace();
|
||||
logger.error(e.getMessage());
|
||||
}
|
||||
}
|
||||
return serverTransaction;
|
||||
|
@ -13,6 +13,9 @@ import com.genersoft.iot.vmp.common.StreamInfo;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
|
||||
import com.genersoft.iot.vmp.gb28181.transmit.request.SIPRequestAbstractProcessor;
|
||||
import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
||||
import com.genersoft.iot.vmp.service.IMediaServerService;
|
||||
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@ -30,6 +33,8 @@ public class AckRequestProcessor extends SIPRequestAbstractProcessor {
|
||||
|
||||
private ZLMRTPServerFactory zlmrtpServerFactory;
|
||||
|
||||
private IMediaServerService mediaServerService;
|
||||
|
||||
/**
|
||||
* 处理 ACK请求
|
||||
*
|
||||
@ -76,18 +81,22 @@ public class AckRequestProcessor extends SIPRequestAbstractProcessor {
|
||||
while (!rtpPushed) {
|
||||
try {
|
||||
if (System.currentTimeMillis() - startTime < 30 * 1000) {
|
||||
if (zlmrtpServerFactory.isStreamReady(streamInfo.getApp(), streamInfo.getStreamId())) {
|
||||
IMediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId());
|
||||
if (zlmrtpServerFactory.isStreamReady(mediaInfo, streamInfo.getApp(), streamInfo.getStreamId())) {
|
||||
rtpPushed = true;
|
||||
logger.info("已获取设备推流,开始向上级推流");
|
||||
zlmrtpServerFactory.startSendRtpStream(param);
|
||||
logger.info("已获取设备推流[{}/{}],开始向上级推流[{}:{}]",
|
||||
streamInfo.getApp() ,streamInfo.getStreamId(), sendRtpItem.getIp(), sendRtpItem.getPort());
|
||||
zlmrtpServerFactory.startSendRtpStream(mediaInfo, param);
|
||||
} else {
|
||||
logger.info("等待设备推流.......");
|
||||
logger.info("等待设备推流[{}/{}].......",
|
||||
streamInfo.getApp() ,streamInfo.getStreamId());
|
||||
Thread.sleep(1000);
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
rtpPushed = true;
|
||||
logger.info("设备推流超时,终止向上级推流");
|
||||
logger.info("设备推流[{}/{}]超时,终止向上级推流",
|
||||
streamInfo.getApp() ,streamInfo.getStreamId());
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
@ -123,4 +132,12 @@ public class AckRequestProcessor extends SIPRequestAbstractProcessor {
|
||||
public void setZlmrtpServerFactory(ZLMRTPServerFactory zlmrtpServerFactory) {
|
||||
this.zlmrtpServerFactory = zlmrtpServerFactory;
|
||||
}
|
||||
|
||||
public IMediaServerService getMediaServerService() {
|
||||
return mediaServerService;
|
||||
}
|
||||
|
||||
public void setMediaServerService(IMediaServerService mediaServerService) {
|
||||
this.mediaServerService = mediaServerService;
|
||||
}
|
||||
}
|
||||
|
@ -15,6 +15,9 @@ import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
|
||||
import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander;
|
||||
import com.genersoft.iot.vmp.gb28181.transmit.request.SIPRequestAbstractProcessor;
|
||||
import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
||||
import com.genersoft.iot.vmp.service.IMediaServerService;
|
||||
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@ -38,6 +41,8 @@ public class ByeRequestProcessor extends SIPRequestAbstractProcessor {
|
||||
|
||||
private ZLMRTPServerFactory zlmrtpServerFactory;
|
||||
|
||||
private IMediaServerService mediaServerService;
|
||||
|
||||
/**
|
||||
* 处理BYE请求
|
||||
* @param evt
|
||||
@ -60,9 +65,10 @@ public class ByeRequestProcessor extends SIPRequestAbstractProcessor {
|
||||
param.put("stream",streamId);
|
||||
param.put("ssrc",sendRtpItem.getSsrc());
|
||||
logger.info("停止向上级推流:" + streamId);
|
||||
zlmrtpServerFactory.stopSendRtpStream(param);
|
||||
IMediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId());
|
||||
zlmrtpServerFactory.stopSendRtpStream(mediaInfo, param);
|
||||
redisCatchStorage.deleteSendRTPServer(platformGbId, channelId);
|
||||
if (zlmrtpServerFactory.totalReaderCount(sendRtpItem.getApp(), streamId) == 0) {
|
||||
if (zlmrtpServerFactory.totalReaderCount(mediaInfo, sendRtpItem.getApp(), streamId) == 0) {
|
||||
logger.info(streamId + "无其它观看者,通知设备停止推流");
|
||||
cmder.streamByeCmd(sendRtpItem.getDeviceId(), channelId);
|
||||
}
|
||||
@ -112,4 +118,11 @@ public class ByeRequestProcessor extends SIPRequestAbstractProcessor {
|
||||
this.cmder = cmder;
|
||||
}
|
||||
|
||||
public IMediaServerService getMediaServerService() {
|
||||
return mediaServerService;
|
||||
}
|
||||
|
||||
public void setMediaServerService(IMediaServerService mediaServerService) {
|
||||
this.mediaServerService = mediaServerService;
|
||||
}
|
||||
}
|
||||
|
@ -11,12 +11,16 @@ import javax.sip.header.*;
|
||||
import javax.sip.message.Request;
|
||||
import javax.sip.message.Response;
|
||||
|
||||
import com.genersoft.iot.vmp.common.StreamInfo;
|
||||
import com.genersoft.iot.vmp.media.zlm.ZLMServerConfig;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.*;
|
||||
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
|
||||
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform;
|
||||
import com.genersoft.iot.vmp.gb28181.transmit.request.SIPRequestAbstractProcessor;
|
||||
import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
||||
import com.genersoft.iot.vmp.service.IMediaServerService;
|
||||
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
|
||||
import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
|
||||
import com.genersoft.iot.vmp.vmanager.gb28181.play.bean.PlayResult;
|
||||
@ -51,6 +55,8 @@ public class InviteRequestProcessor extends SIPRequestAbstractProcessor {
|
||||
|
||||
private ZLMRTPServerFactory zlmrtpServerFactory;
|
||||
|
||||
private IMediaServerService mediaServerService;
|
||||
|
||||
public ZLMRTPServerFactory getZlmrtpServerFactory() {
|
||||
return zlmrtpServerFactory;
|
||||
}
|
||||
@ -91,6 +97,7 @@ public class InviteRequestProcessor extends SIPRequestAbstractProcessor {
|
||||
// 查询平台下是否有该通道
|
||||
DeviceChannel channel = storager.queryChannelInParentPlatform(requesterId, channelId);
|
||||
GbStream gbStream = storager.queryStreamInParentPlatform(requesterId, channelId);
|
||||
IMediaServerItem mediaServerItem = null;
|
||||
// 不是通道可能是直播流
|
||||
if (channel != null && gbStream == null ) {
|
||||
if (channel.getStatus() == 0) {
|
||||
@ -100,8 +107,15 @@ public class InviteRequestProcessor extends SIPRequestAbstractProcessor {
|
||||
}
|
||||
responseAck(evt, Response.CALL_IS_BEING_FORWARDED); // 通道存在,发181,呼叫转接中
|
||||
}else if(channel == null && gbStream != null){
|
||||
Boolean streamReady = zlmrtpServerFactory.isStreamReady(gbStream.getApp(), gbStream.getStream());
|
||||
if (!streamReady) {
|
||||
String mediaServerId = gbStream.getMediaServerId();
|
||||
mediaServerItem = mediaServerService.getOne(mediaServerId);
|
||||
if (mediaServerItem == null) {
|
||||
logger.info("[ app={}, stream={} ]zlm找不到,返回410",gbStream.getApp(), gbStream.getStream());
|
||||
responseAck(evt, Response.GONE, "media server not found");
|
||||
return;
|
||||
}
|
||||
Boolean streamReady = zlmrtpServerFactory.isStreamReady(mediaServerItem, gbStream.getApp(), gbStream.getStream());
|
||||
if (!streamReady ) {
|
||||
logger.info("[ app={}, stream={} ]通道离线,返回400",gbStream.getApp(), gbStream.getStream());
|
||||
responseAck(evt, Response.BAD_REQUEST, "channel [" + gbStream.getGbId() + "] offline");
|
||||
return;
|
||||
@ -130,8 +144,8 @@ public class InviteRequestProcessor extends SIPRequestAbstractProcessor {
|
||||
//boolean recvonly = false;
|
||||
boolean mediaTransmissionTCP = false;
|
||||
Boolean tcpActive = null;
|
||||
for (int i = 0; i < mediaDescriptions.size(); i++) {
|
||||
MediaDescription mediaDescription = (MediaDescription)mediaDescriptions.get(i);
|
||||
for (Object description : mediaDescriptions) {
|
||||
MediaDescription mediaDescription = (MediaDescription) description;
|
||||
Media media = mediaDescription.getMedia();
|
||||
|
||||
Vector mediaFormats = media.getMediaFormats(false);
|
||||
@ -147,7 +161,7 @@ public class InviteRequestProcessor extends SIPRequestAbstractProcessor {
|
||||
mediaTransmissionTCP = true;
|
||||
if ("active".equals(setup)) {
|
||||
tcpActive = true;
|
||||
}else if ("passive".equals(setup)) {
|
||||
} else if ("passive".equals(setup)) {
|
||||
tcpActive = false;
|
||||
}
|
||||
}
|
||||
@ -174,7 +188,13 @@ public class InviteRequestProcessor extends SIPRequestAbstractProcessor {
|
||||
responseAck(evt, Response.SERVER_INTERNAL_ERROR);
|
||||
return;
|
||||
}
|
||||
SendRtpItem sendRtpItem = zlmrtpServerFactory.createSendRtpItem(addressStr, port, ssrc, requesterId,
|
||||
mediaServerItem = playService.getNewMediaServerItem(device);
|
||||
if (mediaServerItem == null) {
|
||||
logger.warn("未找到可用的zlm");
|
||||
responseAck(evt, Response.BUSY_HERE);
|
||||
return;
|
||||
}
|
||||
SendRtpItem sendRtpItem = zlmrtpServerFactory.createSendRtpItem(mediaServerItem, addressStr, port, ssrc, requesterId,
|
||||
device.getDeviceId(), channelId,
|
||||
mediaTransmissionTCP);
|
||||
if (tcpActive != null) {
|
||||
@ -189,18 +209,18 @@ public class InviteRequestProcessor extends SIPRequestAbstractProcessor {
|
||||
// 写入redis, 超时时回复
|
||||
redisCatchStorage.updateSendRTPSever(sendRtpItem);
|
||||
// 通知下级推流,
|
||||
PlayResult playResult = playService.play(device.getDeviceId(), channelId, (responseJSON)->{
|
||||
PlayResult playResult = playService.play(mediaServerItem,device.getDeviceId(), channelId, (mediaServerItemInUSe, responseJSON)->{
|
||||
// 收到推流, 回复200OK, 等待ack
|
||||
// if (sendRtpItem == null) return;
|
||||
sendRtpItem.setStatus(1);
|
||||
redisCatchStorage.updateSendRTPSever(sendRtpItem);
|
||||
// TODO 添加对tcp的支持
|
||||
ZLMServerConfig mediaInfo = redisCatchStorage.getMediaInfo();
|
||||
|
||||
StringBuffer content = new StringBuffer(200);
|
||||
content.append("v=0\r\n");
|
||||
content.append("o="+"00000"+" 0 0 IN IP4 "+mediaInfo.getSdpIp()+"\r\n");
|
||||
content.append("o="+"00000"+" 0 0 IN IP4 "+mediaServerItemInUSe.getSdpIp()+"\r\n");
|
||||
content.append("s=Play\r\n");
|
||||
content.append("c=IN IP4 "+mediaInfo.getSdpIp()+"\r\n");
|
||||
content.append("c=IN IP4 "+mediaServerItemInUSe.getSdpIp()+"\r\n");
|
||||
content.append("t=0 0\r\n");
|
||||
content.append("m=video "+ sendRtpItem.getLocalPort()+" RTP/AVP 96\r\n");
|
||||
content.append("a=sendonly\r\n");
|
||||
@ -217,7 +237,7 @@ public class InviteRequestProcessor extends SIPRequestAbstractProcessor {
|
||||
} catch (ParseException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
} ,(event -> {
|
||||
} ,((event) -> {
|
||||
// 未知错误。直接转发设备点播的错误
|
||||
Response response = null;
|
||||
try {
|
||||
@ -232,7 +252,7 @@ public class InviteRequestProcessor extends SIPRequestAbstractProcessor {
|
||||
}
|
||||
|
||||
}else if (gbStream != null) {
|
||||
SendRtpItem sendRtpItem = zlmrtpServerFactory.createSendRtpItem(addressStr, port, ssrc, requesterId,
|
||||
SendRtpItem sendRtpItem = zlmrtpServerFactory.createSendRtpItem(mediaServerItem, addressStr, port, ssrc, requesterId,
|
||||
gbStream.getApp(), gbStream.getStream(), channelId,
|
||||
mediaTransmissionTCP);
|
||||
|
||||
@ -251,12 +271,11 @@ public class InviteRequestProcessor extends SIPRequestAbstractProcessor {
|
||||
sendRtpItem.setStatus(1);
|
||||
redisCatchStorage.updateSendRTPSever(sendRtpItem);
|
||||
// TODO 添加对tcp的支持
|
||||
ZLMServerConfig mediaInfo = redisCatchStorage.getMediaInfo();
|
||||
StringBuffer content = new StringBuffer(200);
|
||||
content.append("v=0\r\n");
|
||||
content.append("o="+"00000"+" 0 0 IN IP4 "+mediaInfo.getSdpIp()+"\r\n");
|
||||
content.append("o="+"00000"+" 0 0 IN IP4 "+mediaServerItem.getSdpIp()+"\r\n");
|
||||
content.append("s=Play\r\n");
|
||||
content.append("c=IN IP4 "+mediaInfo.getSdpIp()+"\r\n");
|
||||
content.append("c=IN IP4 "+mediaServerItem.getSdpIp()+"\r\n");
|
||||
content.append("t=0 0\r\n");
|
||||
content.append("m=video "+ sendRtpItem.getLocalPort()+" RTP/AVP 96\r\n");
|
||||
content.append("a=sendonly\r\n");
|
||||
@ -444,4 +463,12 @@ public class InviteRequestProcessor extends SIPRequestAbstractProcessor {
|
||||
public void setRedisCatchStorage(IRedisCatchStorage redisCatchStorage) {
|
||||
this.redisCatchStorage = redisCatchStorage;
|
||||
}
|
||||
|
||||
public IMediaServerService getMediaServerService() {
|
||||
return mediaServerService;
|
||||
}
|
||||
|
||||
public void setMediaServerService(IMediaServerService mediaServerService) {
|
||||
this.mediaServerService = mediaServerService;
|
||||
}
|
||||
}
|
||||
|
@ -282,7 +282,7 @@ public class MessageRequestProcessor extends SIPRequestAbstractProcessor {
|
||||
//String result = XmlUtil.getText(rootElement, "Result");
|
||||
// 回复200 OK
|
||||
responseAck(evt);
|
||||
if (rootElement.getName().equals("Response")) {//} !XmlUtil.isEmpty(result)) {
|
||||
if (rootElement.getName().equals("Response")) {//} !StringUtils.isEmpty(result)) {
|
||||
// 此处是对本平台发出DeviceControl指令的应答
|
||||
JSONObject json = new JSONObject();
|
||||
XmlUtil.node2Json(rootElement, json);
|
||||
@ -299,7 +299,7 @@ public class MessageRequestProcessor extends SIPRequestAbstractProcessor {
|
||||
String platformId = ((SipURI) ((HeaderAddress) evt.getRequest().getHeader(FromHeader.NAME)).getAddress().getURI()).getUser();
|
||||
String targetGBId = ((SipURI) ((HeaderAddress) evt.getRequest().getHeader(ToHeader.NAME)).getAddress().getURI()).getUser();
|
||||
// 远程启动功能
|
||||
if (!XmlUtil.isEmpty(XmlUtil.getText(rootElement, "TeleBoot"))) {
|
||||
if (!StringUtils.isEmpty(XmlUtil.getText(rootElement, "TeleBoot"))) {
|
||||
if (deviceId.equals(targetGBId)) {
|
||||
// 远程启动本平台:需要在重新启动程序后先对SipStack解绑
|
||||
logger.info("执行远程启动本平台命令");
|
||||
@ -337,7 +337,7 @@ public class MessageRequestProcessor extends SIPRequestAbstractProcessor {
|
||||
}
|
||||
}
|
||||
// 云台/前端控制命令
|
||||
if (!XmlUtil.isEmpty(XmlUtil.getText(rootElement,"PTZCmd")) && !deviceId.equals(targetGBId)) {
|
||||
if (!StringUtils.isEmpty(XmlUtil.getText(rootElement,"PTZCmd")) && !deviceId.equals(targetGBId)) {
|
||||
String cmdString = XmlUtil.getText(rootElement,"PTZCmd");
|
||||
Device device = storager.queryVideoDeviceByPlatformIdAndChannelId(platformId, deviceId);
|
||||
cmder.fronEndCmd(device, deviceId, cmdString);
|
||||
@ -421,7 +421,7 @@ public class MessageRequestProcessor extends SIPRequestAbstractProcessor {
|
||||
String deviceId = XmlUtil.getText(rootElement, "DeviceID");
|
||||
// 回复200 OK
|
||||
responseAck(evt);
|
||||
if (rootElement.getName().equals("Response")) {// !XmlUtil.isEmpty(result)) {
|
||||
if (rootElement.getName().equals("Response")) {// !StringUtils.isEmpty(result)) {
|
||||
// 此处是对本平台发出DeviceControl指令的应答
|
||||
JSONObject json = new JSONObject();
|
||||
XmlUtil.node2Json(rootElement, json);
|
||||
@ -718,7 +718,7 @@ public class MessageRequestProcessor extends SIPRequestAbstractProcessor {
|
||||
deviceAlarm.setLatitude(0.00);
|
||||
}
|
||||
|
||||
if (!XmlUtil.isEmpty(deviceAlarm.getAlarmMethod())) {
|
||||
if (!StringUtils.isEmpty(deviceAlarm.getAlarmMethod())) {
|
||||
if ( deviceAlarm.getAlarmMethod().equals("4")) {
|
||||
MobilePosition mobilePosition = new MobilePosition();
|
||||
mobilePosition.setDeviceId(deviceAlarm.getDeviceId());
|
||||
|
@ -17,6 +17,7 @@ import org.dom4j.Element;
|
||||
import org.dom4j.io.SAXReader;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* 基于dom4j的工具包
|
||||
@ -114,12 +115,12 @@ public class XmlUtil {
|
||||
// 如果是属性
|
||||
for (Object o : element.attributes()) {
|
||||
Attribute attr = (Attribute) o;
|
||||
if (!isEmpty(attr.getValue())) {
|
||||
if (!StringUtils.isEmpty(attr.getValue())) {
|
||||
json.put("@" + attr.getName(), attr.getValue());
|
||||
}
|
||||
}
|
||||
List<Element> chdEl = element.elements();
|
||||
if (chdEl.isEmpty() && !isEmpty(element.getText())) {// 如果没有子元素,只有一个值
|
||||
if (chdEl.isEmpty() && !StringUtils.isEmpty(element.getText())) {// 如果没有子元素,只有一个值
|
||||
json.put(element.getName(), element.getText());
|
||||
}
|
||||
|
||||
@ -150,7 +151,7 @@ public class XmlUtil {
|
||||
} else { // 子元素没有子元素
|
||||
for (Object o : element.attributes()) {
|
||||
Attribute attr = (Attribute) o;
|
||||
if (!isEmpty(attr.getValue())) {
|
||||
if (!StringUtils.isEmpty(attr.getValue())) {
|
||||
json.put("@" + attr.getName(), attr.getValue());
|
||||
}
|
||||
}
|
||||
@ -160,11 +161,4 @@ public class XmlUtil {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isEmpty(String str) {
|
||||
if (str == null || str.trim().isEmpty() || "null".equals(str)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -1,54 +0,0 @@
|
||||
//package com.genersoft.iot.vmp.media.zlm;
|
||||
//
|
||||
//import com.genersoft.iot.vmp.conf.MediaConfig;
|
||||
//import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
|
||||
//import org.springframework.beans.factory.annotation.Autowired;
|
||||
//import org.springframework.beans.factory.annotation.Value;
|
||||
//import org.springframework.web.bind.annotation.*;
|
||||
//import org.springframework.web.client.HttpClientErrorException;
|
||||
//import org.springframework.web.client.RestTemplate;
|
||||
//
|
||||
//import javax.servlet.http.HttpServletRequest;
|
||||
//import javax.servlet.http.HttpServletResponse;
|
||||
//
|
||||
//@RestController
|
||||
//@RequestMapping("/zlm")
|
||||
//public class ZLMHTTPProxyController {
|
||||
//
|
||||
//
|
||||
// // private final static Logger logger = LoggerFactory.getLogger(ZLMHTTPProxyController.class);
|
||||
//
|
||||
// @Autowired
|
||||
// private IRedisCatchStorage redisCatchStorage;
|
||||
//
|
||||
// @Autowired
|
||||
// private MediaConfig mediaConfig;
|
||||
//
|
||||
// @ResponseBody
|
||||
// @RequestMapping(value = "/**/**/**", produces = "application/json;charset=UTF-8")
|
||||
// public Object proxy(HttpServletRequest request, HttpServletResponse response){
|
||||
//
|
||||
// if (redisCatchStorage.getMediaInfo() == null) {
|
||||
// return "未接入流媒体";
|
||||
// }
|
||||
// ZLMServerConfig mediaInfo = redisCatchStorage.getMediaInfo();
|
||||
// String requestURI = String.format("http://%s:%s%s?%s&%s",
|
||||
// mediaInfo.getLocalIP(),
|
||||
// mediaConfig.getHttpPort(),
|
||||
// request.getRequestURI().replace("/zlm",""),
|
||||
// mediaInfo.getHookAdminParams(),
|
||||
// request.getQueryString()
|
||||
// );
|
||||
// // 发送请求
|
||||
// RestTemplate restTemplate = new RestTemplate();
|
||||
// //将指定的url返回的参数自动封装到自定义好的对应类对象中
|
||||
// Object result = null;
|
||||
// try {
|
||||
// result = restTemplate.getForObject(requestURI,Object.class);
|
||||
//
|
||||
// }catch (HttpClientErrorException httpClientErrorException) {
|
||||
// response.setStatus(httpClientErrorException.getStatusCode().value());
|
||||
// }
|
||||
// return result;
|
||||
// }
|
||||
//}
|
@ -9,6 +9,9 @@ import com.genersoft.iot.vmp.common.StreamInfo;
|
||||
import com.genersoft.iot.vmp.conf.MediaConfig;
|
||||
import com.genersoft.iot.vmp.conf.UserSetup;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.Device;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
||||
import com.genersoft.iot.vmp.service.IMediaServerService;
|
||||
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
|
||||
import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
|
||||
import com.genersoft.iot.vmp.service.IPlayService;
|
||||
@ -53,10 +56,10 @@ public class ZLMHttpHookListener {
|
||||
private IRedisCatchStorage redisCatchStorage;
|
||||
|
||||
@Autowired
|
||||
private ZLMRESTfulUtils zlmresTfulUtils;
|
||||
private IMediaServerService mediaServerService;
|
||||
|
||||
@Autowired
|
||||
private ZLMServerManger zlmServerManger;
|
||||
private ZLMRESTfulUtils zlmresTfulUtils;
|
||||
|
||||
@Autowired
|
||||
private ZLMMediaListManager zlmMediaListManager;
|
||||
@ -81,6 +84,7 @@ public class ZLMHttpHookListener {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("ZLM HOOK on_flow_report API调用,参数:" + json.toString());
|
||||
}
|
||||
String mediaServerId = json.getString("mediaServerId");
|
||||
JSONObject ret = new JSONObject();
|
||||
ret.put("code", 0);
|
||||
ret.put("msg", "success");
|
||||
@ -98,6 +102,7 @@ public class ZLMHttpHookListener {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("ZLM HOOK on_http_access API 调用,参数:" + json.toString());
|
||||
}
|
||||
String mediaServerId = json.getString("mediaServerId");
|
||||
JSONObject ret = new JSONObject();
|
||||
ret.put("code", 0);
|
||||
ret.put("err", "");
|
||||
@ -117,9 +122,14 @@ public class ZLMHttpHookListener {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("ZLM HOOK on_play API调用,参数:" + json.toString());
|
||||
}
|
||||
String mediaServerId = json.getString("mediaServerId");
|
||||
ZLMHttpHookSubscribe.Event subscribe = this.subscribe.getSubscribe(ZLMHttpHookSubscribe.HookType.on_play, json);
|
||||
if (subscribe != null ) {
|
||||
subscribe.response(json);
|
||||
IMediaServerItem mediaInfo = mediaServerService.getOne(mediaServerId);
|
||||
if (mediaInfo != null) {
|
||||
subscribe.response(mediaInfo, json);
|
||||
}
|
||||
|
||||
}
|
||||
JSONObject ret = new JSONObject();
|
||||
ret.put("code", 0);
|
||||
@ -133,20 +143,25 @@ public class ZLMHttpHookListener {
|
||||
*/
|
||||
@ResponseBody
|
||||
@PostMapping(value = "/on_publish", produces = "application/json;charset=UTF-8")
|
||||
public ResponseEntity<String> onPublish(@RequestBody JSONObject json){
|
||||
public ResponseEntity<String> onPublish(@RequestBody JSONObject json) {
|
||||
|
||||
logger.debug("ZLM HOOK on_publish API调用,参数:" + json.toString());
|
||||
|
||||
String mediaServerId = json.getString("mediaServerId");
|
||||
ZLMHttpHookSubscribe.Event subscribe = this.subscribe.getSubscribe(ZLMHttpHookSubscribe.HookType.on_publish, json);
|
||||
if (subscribe != null) subscribe.response(json);
|
||||
|
||||
if (subscribe != null) {
|
||||
IMediaServerItem mediaInfo = mediaServerService.getOne(mediaServerId);
|
||||
if (mediaInfo != null) {
|
||||
subscribe.response(mediaInfo, json);
|
||||
}
|
||||
}
|
||||
JSONObject ret = new JSONObject();
|
||||
ret.put("code", 0);
|
||||
ret.put("msg", "success");
|
||||
ret.put("enableHls", true);
|
||||
ret.put("enableMP4", userSetup.isRecordPushLive());
|
||||
ret.put("enableRtxp", true);
|
||||
return new ResponseEntity<String>(ret.toString(),HttpStatus.OK);
|
||||
return new ResponseEntity<String>(ret.toString(), HttpStatus.OK);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -160,6 +175,7 @@ public class ZLMHttpHookListener {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("ZLM HOOK on_record_mp4 API调用,参数:" + json.toString());
|
||||
}
|
||||
String mediaServerId = json.getString("mediaServerId");
|
||||
JSONObject ret = new JSONObject();
|
||||
ret.put("code", 0);
|
||||
ret.put("msg", "success");
|
||||
@ -177,6 +193,7 @@ public class ZLMHttpHookListener {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("ZLM HOOK on_rtsp_realm API调用,参数:" + json.toString());
|
||||
}
|
||||
String mediaServerId = json.getString("mediaServerId");
|
||||
JSONObject ret = new JSONObject();
|
||||
ret.put("code", 0);
|
||||
ret.put("realm", "");
|
||||
@ -195,6 +212,7 @@ public class ZLMHttpHookListener {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("ZLM HOOK on_rtsp_auth API调用,参数:" + json.toString());
|
||||
}
|
||||
String mediaServerId = json.getString("mediaServerId");
|
||||
JSONObject ret = new JSONObject();
|
||||
ret.put("code", 0);
|
||||
ret.put("encrypted", false);
|
||||
@ -216,9 +234,15 @@ public class ZLMHttpHookListener {
|
||||
// TODO 如果是带有rtpstream则开启按需拉流
|
||||
// String app = json.getString("app");
|
||||
// String stream = json.getString("stream");
|
||||
|
||||
String mediaServerId = json.getString("mediaServerId");
|
||||
ZLMHttpHookSubscribe.Event subscribe = this.subscribe.getSubscribe(ZLMHttpHookSubscribe.HookType.on_shell_login, json);
|
||||
if (subscribe != null) subscribe.response(json);
|
||||
if (subscribe != null ) {
|
||||
IMediaServerItem mediaInfo = mediaServerService.getOne(mediaServerId);
|
||||
if (mediaInfo != null) {
|
||||
subscribe.response(mediaInfo, json);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
JSONObject ret = new JSONObject();
|
||||
ret.put("code", 0);
|
||||
@ -237,9 +261,15 @@ public class ZLMHttpHookListener {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("ZLM HOOK on_stream_changed API调用,参数:" + json.toString());
|
||||
}
|
||||
|
||||
String mediaServerId = json.getString("mediaServerId");
|
||||
ZLMHttpHookSubscribe.Event subscribe = this.subscribe.getSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, json);
|
||||
if (subscribe != null) subscribe.response(json);
|
||||
if (subscribe != null ) {
|
||||
IMediaServerItem mediaInfo = mediaServerService.getOne(mediaServerId);
|
||||
if (mediaInfo != null) {
|
||||
subscribe.response(mediaInfo, json);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 流消失移除redis play
|
||||
String app = json.getString("app");
|
||||
@ -251,6 +281,11 @@ public class ZLMHttpHookListener {
|
||||
logger.info("[stream: " + streamId + "] on_stream_changed->>" + schema);
|
||||
}
|
||||
if ("rtmp".equals(schema)){
|
||||
if (regist) {
|
||||
mediaServerService.addCount(mediaServerId);
|
||||
}else {
|
||||
mediaServerService.removeCount(mediaServerId);
|
||||
}
|
||||
if ("rtp".equals(app) && !regist ) {
|
||||
StreamInfo streamInfo = redisCatchStorage.queryPlayByStreamId(streamId);
|
||||
if (streamInfo!=null){
|
||||
@ -262,10 +297,11 @@ public class ZLMHttpHookListener {
|
||||
}
|
||||
}else {
|
||||
if (!"rtp".equals(app) ){
|
||||
IMediaServerItem mediaServerItem = mediaServerService.getOne(mediaServerId);
|
||||
if (regist) {
|
||||
zlmMediaListManager.addMedia(app, streamId);
|
||||
zlmMediaListManager.addMedia(mediaServerItem, app, streamId);
|
||||
}else {
|
||||
zlmMediaListManager.removeMedia(app, streamId);
|
||||
zlmMediaListManager.removeMedia( app, streamId);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -288,7 +324,7 @@ public class ZLMHttpHookListener {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("ZLM HOOK on_stream_none_reader API调用,参数:" + json.toString());
|
||||
}
|
||||
|
||||
String mediaServerId = json.getString("mediaServerId");
|
||||
String streamId = json.getString("stream");
|
||||
String app = json.getString("app");
|
||||
|
||||
@ -329,11 +365,12 @@ public class ZLMHttpHookListener {
|
||||
@ResponseBody
|
||||
@PostMapping(value = "/on_stream_not_found", produces = "application/json;charset=UTF-8")
|
||||
public ResponseEntity<String> onStreamNotFound(@RequestBody JSONObject json){
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("ZLM HOOK on_stream_not_found API调用,参数:" + json.toString());
|
||||
}
|
||||
if (userSetup.isAutoApplyPlay()) {
|
||||
String mediaServerId = json.getString("mediaServerId");
|
||||
IMediaServerItem mediaInfo = mediaServerService.getOne(mediaServerId);
|
||||
if (userSetup.isAutoApplyPlay() && mediaInfo != null) {
|
||||
String app = json.getString("app");
|
||||
String streamId = json.getString("stream");
|
||||
if ("rtp".equals(app) && streamId.contains("gb_play") ) {
|
||||
@ -344,9 +381,9 @@ public class ZLMHttpHookListener {
|
||||
Device device = storager.queryVideoDevice(deviceId);
|
||||
if (device != null) {
|
||||
UUID uuid = UUID.randomUUID();
|
||||
cmder.playStreamCmd(device, channelId, (JSONObject response) -> {
|
||||
cmder.playStreamCmd(mediaInfo, device, channelId, (IMediaServerItem mediaServerItemInuse, JSONObject response) -> {
|
||||
logger.info("收到订阅消息: " + response.toJSONString());
|
||||
playService.onPublishHandlerForPlay(response, deviceId, channelId, uuid.toString());
|
||||
playService.onPublishHandlerForPlay(mediaServerItemInuse, response, deviceId, channelId, uuid.toString());
|
||||
}, null);
|
||||
}
|
||||
|
||||
@ -367,26 +404,19 @@ public class ZLMHttpHookListener {
|
||||
*/
|
||||
@ResponseBody
|
||||
@PostMapping(value = "/on_server_started", produces = "application/json;charset=UTF-8")
|
||||
public ResponseEntity<String> onServerStarted(HttpServletRequest request, @RequestBody JSONObject json){
|
||||
public ResponseEntity<String> onServerStarted(HttpServletRequest request, @RequestBody JSONObject jsonObject){
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("ZLM HOOK on_server_started API调用,参数:" + json.toString());
|
||||
logger.debug("ZLM HOOK on_server_started API调用,参数:" + jsonObject.toString());
|
||||
}
|
||||
|
||||
// String data = json.getString("data");
|
||||
// List<MediaServerConfig> mediaServerConfigs = JSON.parseArray(JSON.toJSONString(json), MediaServerConfig.class);
|
||||
// MediaServerConfig mediaServerConfig = mediaServerConfigs.get(0);
|
||||
|
||||
String remoteAddr = request.getRemoteAddr();
|
||||
jsonObject.put("ip", remoteAddr);
|
||||
List<ZLMHttpHookSubscribe.Event> subscribes = this.subscribe.getSubscribes(ZLMHttpHookSubscribe.HookType.on_server_started);
|
||||
if (subscribes != null && subscribes.size() > 0) {
|
||||
if (subscribes != null && subscribes.size() > 0) {
|
||||
for (ZLMHttpHookSubscribe.Event subscribe : subscribes) {
|
||||
subscribe.response(json);
|
||||
subscribe.response(null, jsonObject);
|
||||
}
|
||||
}
|
||||
ZLMServerConfig ZLMServerConfig = JSON.toJavaObject(json, ZLMServerConfig.class);
|
||||
zlmServerManger.updateServerCatch(ZLMServerConfig);
|
||||
// 重新发起代理
|
||||
|
||||
JSONObject ret = new JSONObject();
|
||||
ret.put("code", 0);
|
||||
ret.put("msg", "success");
|
||||
|
@ -1,6 +1,8 @@
|
||||
package com.genersoft.iot.vmp.media.zlm;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.*;
|
||||
@ -30,7 +32,7 @@ public class ZLMHttpHookSubscribe {
|
||||
}
|
||||
|
||||
public interface Event{
|
||||
void response(JSONObject response);
|
||||
void response(IMediaServerItem mediaServerItem, JSONObject response);
|
||||
}
|
||||
|
||||
private Map<HookType, Map<JSONObject, ZLMHttpHookSubscribe.Event>> allSubscribes = new ConcurrentHashMap<>();
|
||||
|
@ -2,6 +2,8 @@ package com.genersoft.iot.vmp.media.zlm;
|
||||
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.GbStream;
|
||||
@ -45,11 +47,11 @@ public class ZLMMediaListManager {
|
||||
private ZLMHttpHookSubscribe subscribe;
|
||||
|
||||
|
||||
public void updateMediaList() {
|
||||
public void updateMediaList(MediaServerItem mediaServerItem) {
|
||||
storager.clearMediaList();
|
||||
|
||||
// 使用异步的当时更新媒体流列表
|
||||
zlmresTfulUtils.getMediaList((mediaList ->{
|
||||
zlmresTfulUtils.getMediaList(mediaServerItem, (mediaList ->{
|
||||
if (mediaList == null) return;
|
||||
String dataStr = mediaList.getString("data");
|
||||
|
||||
@ -57,10 +59,10 @@ public class ZLMMediaListManager {
|
||||
Map<String, StreamPushItem> result = new HashMap<>();
|
||||
List<StreamPushItem> streamPushItems = null;
|
||||
// 获取所有的国标关联
|
||||
List<GbStream> gbStreams = gbStreamMapper.selectAll();
|
||||
// List<GbStream> gbStreams = gbStreamMapper.selectAllByMediaServerId(mediaServerItem.getId());
|
||||
if (code == 0 ) {
|
||||
if (dataStr != null) {
|
||||
streamPushItems = streamPushService.handleJSON(dataStr);
|
||||
streamPushItems = streamPushService.handleJSON(dataStr, mediaServerItem);
|
||||
}
|
||||
}else {
|
||||
logger.warn("更新视频流失败,错误code: " + code);
|
||||
@ -72,24 +74,27 @@ public class ZLMMediaListManager {
|
||||
JSONObject jsonObject = new JSONObject();
|
||||
jsonObject.put("app", streamPushItem.getApp());
|
||||
jsonObject.put("stream", streamPushItem.getStream());
|
||||
subscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_play,jsonObject,(response)->{
|
||||
updateMedia(response.getString("app"), response.getString("stream"));
|
||||
});
|
||||
jsonObject.put("mediaServerId", mediaServerItem.getId());
|
||||
subscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_play,jsonObject,
|
||||
(IMediaServerItem mediaServerItemInuse, JSONObject response)->{
|
||||
updateMedia(mediaServerItem, response.getString("app"), response.getString("stream"));
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
}
|
||||
|
||||
public void addMedia(String app, String streamId) {
|
||||
public void addMedia(IMediaServerItem mediaServerItem, String app, String streamId) {
|
||||
//使用异步更新推流
|
||||
updateMedia(app, streamId);
|
||||
updateMedia(mediaServerItem, app, streamId);
|
||||
}
|
||||
|
||||
|
||||
public void updateMedia(String app, String streamId) {
|
||||
public void updateMedia(IMediaServerItem mediaServerItem, String app, String streamId) {
|
||||
//使用异步更新推流
|
||||
zlmresTfulUtils.getMediaList(app, streamId, "rtmp", json->{
|
||||
zlmresTfulUtils.getMediaList(mediaServerItem, app, streamId, "rtmp", json->{
|
||||
|
||||
if (json == null) return;
|
||||
String dataStr = json.getString("data");
|
||||
@ -99,7 +104,7 @@ public class ZLMMediaListManager {
|
||||
List<StreamPushItem> streamPushItems = null;
|
||||
if (code == 0 ) {
|
||||
if (dataStr != null) {
|
||||
streamPushItems = streamPushService.handleJSON(dataStr);
|
||||
streamPushItems = streamPushService.handleJSON(dataStr, mediaServerItem);
|
||||
}
|
||||
}else {
|
||||
logger.warn("更新视频流失败,错误code: " + code);
|
||||
@ -122,32 +127,32 @@ public class ZLMMediaListManager {
|
||||
}
|
||||
}
|
||||
|
||||
public void clearAllSessions() {
|
||||
logger.info("清空所有国标相关的session");
|
||||
JSONObject allSessionJSON = zlmresTfulUtils.getAllSession();
|
||||
ZLMServerConfig mediaInfo = redisCatchStorage.getMediaInfo();
|
||||
HashSet<String> allLocalPorts = new HashSet();
|
||||
if (allSessionJSON.getInteger("code") == 0) {
|
||||
JSONArray data = allSessionJSON.getJSONArray("data");
|
||||
if (data.size() > 0) {
|
||||
for (int i = 0; i < data.size(); i++) {
|
||||
JSONObject sessionJOSN = data.getJSONObject(i);
|
||||
Integer local_port = sessionJOSN.getInteger("local_port");
|
||||
if (!local_port.equals(Integer.valueOf(mediaInfo.getHttpPort())) &&
|
||||
!local_port.equals(Integer.valueOf(mediaInfo.getHttpSSLport())) &&
|
||||
!local_port.equals(Integer.valueOf(mediaInfo.getRtmpPort())) &&
|
||||
!local_port.equals(Integer.valueOf(mediaInfo.getRtspPort())) &&
|
||||
!local_port.equals(Integer.valueOf(mediaInfo.getRtspSSlport())) &&
|
||||
!local_port.equals(Integer.valueOf(mediaInfo.getHookOnFlowReport()))){
|
||||
allLocalPorts.add(sessionJOSN.getInteger("local_port") + "");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (allLocalPorts.size() > 0) {
|
||||
List<String> result = new ArrayList<>(allLocalPorts);
|
||||
String localPortSStr = String.join(",", result);
|
||||
zlmresTfulUtils.kickSessions(localPortSStr);
|
||||
}
|
||||
}
|
||||
// public void clearAllSessions() {
|
||||
// logger.info("清空所有国标相关的session");
|
||||
// JSONObject allSessionJSON = zlmresTfulUtils.getAllSession();
|
||||
// ZLMServerConfig mediaInfo = redisCatchStorage.getMediaInfo();
|
||||
// HashSet<String> allLocalPorts = new HashSet();
|
||||
// if (allSessionJSON.getInteger("code") == 0) {
|
||||
// JSONArray data = allSessionJSON.getJSONArray("data");
|
||||
// if (data.size() > 0) {
|
||||
// for (int i = 0; i < data.size(); i++) {
|
||||
// JSONObject sessionJOSN = data.getJSONObject(i);
|
||||
// Integer local_port = sessionJOSN.getInteger("local_port");
|
||||
// if (!local_port.equals(Integer.valueOf(mediaInfo.getHttpPort())) &&
|
||||
// !local_port.equals(Integer.valueOf(mediaInfo.getHttpSSLport())) &&
|
||||
// !local_port.equals(Integer.valueOf(mediaInfo.getRtmpPort())) &&
|
||||
// !local_port.equals(Integer.valueOf(mediaInfo.getRtspPort())) &&
|
||||
// !local_port.equals(Integer.valueOf(mediaInfo.getRtspSSlport())) &&
|
||||
// !local_port.equals(Integer.valueOf(mediaInfo.getHookOnFlowReport()))){
|
||||
// allLocalPorts.add(sessionJOSN.getInteger("local_port") + "");
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// if (allLocalPorts.size() > 0) {
|
||||
// List<String> result = new ArrayList<>(allLocalPorts);
|
||||
// String localPortSStr = String.join(",", result);
|
||||
// zlmresTfulUtils.kickSessions(localPortSStr);
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
@ -3,6 +3,8 @@ package com.genersoft.iot.vmp.media.zlm;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.genersoft.iot.vmp.conf.MediaConfig;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
||||
import okhttp3.*;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.slf4j.Logger;
|
||||
@ -21,23 +23,18 @@ public class ZLMRESTfulUtils {
|
||||
|
||||
private final static Logger logger = LoggerFactory.getLogger(ZLMRESTfulUtils.class);
|
||||
|
||||
@Autowired
|
||||
private MediaConfig mediaConfig;
|
||||
|
||||
|
||||
|
||||
public interface RequestCallback{
|
||||
void run(JSONObject response);
|
||||
}
|
||||
|
||||
public JSONObject sendPost(String api, Map<String, Object> param, RequestCallback callback) {
|
||||
public JSONObject sendPost(IMediaServerItem mediaServerItem, String api, Map<String, Object> param, RequestCallback callback) {
|
||||
OkHttpClient client = new OkHttpClient();
|
||||
String url = String.format("http://%s:%s/index/api/%s", mediaConfig.getIp(), mediaConfig.getHttpPort(), api);
|
||||
String url = String.format("http://%s:%s/index/api/%s", mediaServerItem.getIp(), mediaServerItem.getHttpPort(), api);
|
||||
JSONObject responseJSON = null;
|
||||
logger.debug(url);
|
||||
|
||||
FormBody.Builder builder = new FormBody.Builder();
|
||||
builder.add("secret",mediaConfig.getSecret());
|
||||
builder.add("secret",mediaServerItem.getSecret());
|
||||
if (param != null && param.keySet().size() > 0) {
|
||||
for (String key : param.keySet()){
|
||||
if (param.get(key) != null) {
|
||||
@ -96,14 +93,14 @@ public class ZLMRESTfulUtils {
|
||||
}
|
||||
|
||||
|
||||
public void sendPostForImg(String api, Map<String, Object> param, String targetPath, String fileName) {
|
||||
public void sendPostForImg(IMediaServerItem mediaServerItem, String api, Map<String, Object> param, String targetPath, String fileName) {
|
||||
OkHttpClient client = new OkHttpClient();
|
||||
String url = String.format("http://%s:%s/index/api/%s", mediaConfig.getIp(), mediaConfig.getHttpPort(), api);
|
||||
String url = String.format("http://%s:%s/index/api/%s", mediaServerItem.getIp(), mediaServerItem.getHttpPort(), api);
|
||||
JSONObject responseJSON = null;
|
||||
logger.debug(url);
|
||||
|
||||
FormBody.Builder builder = new FormBody.Builder();
|
||||
builder.add("secret",mediaConfig.getSecret());
|
||||
builder.add("secret",mediaServerItem.getSecret());
|
||||
if (param != null && param.keySet().size() > 0) {
|
||||
for (String key : param.keySet()){
|
||||
if (param.get(key) != null) {
|
||||
@ -142,39 +139,39 @@ public class ZLMRESTfulUtils {
|
||||
}
|
||||
|
||||
|
||||
public JSONObject getMediaList(String app, String stream, String schema, RequestCallback callback){
|
||||
public JSONObject getMediaList(IMediaServerItem mediaServerItem,String app, String stream, String schema, RequestCallback callback){
|
||||
Map<String, Object> param = new HashMap<>();
|
||||
if (app != null) param.put("app",app);
|
||||
if (stream != null) param.put("stream",stream);
|
||||
if (schema != null) param.put("schema",schema);
|
||||
param.put("vhost","__defaultVhost__");
|
||||
return sendPost("getMediaList",param, callback);
|
||||
return sendPost(mediaServerItem, "getMediaList",param, callback);
|
||||
}
|
||||
|
||||
public JSONObject getMediaList(String app, String stream){
|
||||
return getMediaList(app, stream,null, null);
|
||||
public JSONObject getMediaList(IMediaServerItem mediaServerItem,String app, String stream){
|
||||
return getMediaList(mediaServerItem, app, stream,null, null);
|
||||
}
|
||||
|
||||
public JSONObject getMediaList(RequestCallback callback){
|
||||
return sendPost("getMediaList",null, callback);
|
||||
public JSONObject getMediaList(IMediaServerItem mediaServerItem,RequestCallback callback){
|
||||
return sendPost(mediaServerItem, "getMediaList",null, callback);
|
||||
}
|
||||
|
||||
public JSONObject getMediaInfo(String app, String schema, String stream){
|
||||
public JSONObject getMediaInfo(IMediaServerItem mediaServerItem,String app, String schema, String stream){
|
||||
Map<String, Object> param = new HashMap<>();
|
||||
param.put("app",app);
|
||||
param.put("schema",schema);
|
||||
param.put("stream",stream);
|
||||
param.put("vhost","__defaultVhost__");
|
||||
return sendPost("getMediaInfo",param, null);
|
||||
return sendPost(mediaServerItem, "getMediaInfo",param, null);
|
||||
}
|
||||
|
||||
public JSONObject getRtpInfo(String stream_id){
|
||||
public JSONObject getRtpInfo(IMediaServerItem mediaServerItem,String stream_id){
|
||||
Map<String, Object> param = new HashMap<>();
|
||||
param.put("stream_id",stream_id);
|
||||
return sendPost("getRtpInfo",param, null);
|
||||
return sendPost(mediaServerItem, "getRtpInfo",param, null);
|
||||
}
|
||||
|
||||
public JSONObject addFFmpegSource(String src_url, String dst_url, String timeout_ms,
|
||||
public JSONObject addFFmpegSource(IMediaServerItem mediaServerItem,String src_url, String dst_url, String timeout_ms,
|
||||
boolean enable_hls, boolean enable_mp4, String ffmpeg_cmd_key){
|
||||
logger.info(src_url);
|
||||
logger.info(dst_url);
|
||||
@ -185,44 +182,44 @@ public class ZLMRESTfulUtils {
|
||||
param.put("enable_hls", enable_hls);
|
||||
param.put("enable_mp4", enable_mp4);
|
||||
param.put("ffmpeg_cmd_key", ffmpeg_cmd_key);
|
||||
return sendPost("addFFmpegSource",param, null);
|
||||
return sendPost(mediaServerItem, "addFFmpegSource",param, null);
|
||||
}
|
||||
|
||||
public JSONObject delFFmpegSource(String key){
|
||||
public JSONObject delFFmpegSource(IMediaServerItem mediaServerItem,String key){
|
||||
Map<String, Object> param = new HashMap<>();
|
||||
param.put("key", key);
|
||||
return sendPost("delFFmpegSource",param, null);
|
||||
return sendPost(mediaServerItem, "delFFmpegSource",param, null);
|
||||
}
|
||||
|
||||
public JSONObject getMediaServerConfig(){
|
||||
return sendPost("getServerConfig",null, null);
|
||||
public JSONObject getMediaServerConfig(IMediaServerItem mediaServerItem){
|
||||
return sendPost(mediaServerItem, "getServerConfig",null, null);
|
||||
}
|
||||
|
||||
public JSONObject setServerConfig(Map<String, Object> param){
|
||||
return sendPost("setServerConfig",param, null);
|
||||
public JSONObject setServerConfig(IMediaServerItem mediaServerItem, Map<String, Object> param){
|
||||
return sendPost(mediaServerItem,"setServerConfig",param, null);
|
||||
}
|
||||
|
||||
public JSONObject openRtpServer(Map<String, Object> param){
|
||||
return sendPost("openRtpServer",param, null);
|
||||
public JSONObject openRtpServer(IMediaServerItem mediaServerItem,Map<String, Object> param){
|
||||
return sendPost(mediaServerItem, "openRtpServer",param, null);
|
||||
}
|
||||
|
||||
public JSONObject closeRtpServer(Map<String, Object> param) {
|
||||
return sendPost("closeRtpServer",param, null);
|
||||
public JSONObject closeRtpServer(IMediaServerItem mediaServerItem,Map<String, Object> param) {
|
||||
return sendPost(mediaServerItem, "closeRtpServer",param, null);
|
||||
}
|
||||
|
||||
public JSONObject listRtpServer() {
|
||||
return sendPost("listRtpServer",null, null);
|
||||
public JSONObject listRtpServer(IMediaServerItem mediaServerItem) {
|
||||
return sendPost(mediaServerItem, "listRtpServer",null, null);
|
||||
}
|
||||
|
||||
public JSONObject startSendRtp(Map<String, Object> param) {
|
||||
return sendPost("startSendRtp",param, null);
|
||||
public JSONObject startSendRtp(IMediaServerItem mediaServerItem,Map<String, Object> param) {
|
||||
return sendPost(mediaServerItem, "startSendRtp",param, null);
|
||||
}
|
||||
|
||||
public JSONObject stopSendRtp(Map<String, Object> param) {
|
||||
return sendPost("stopSendRtp",param, null);
|
||||
public JSONObject stopSendRtp(IMediaServerItem mediaServerItem,Map<String, Object> param) {
|
||||
return sendPost(mediaServerItem, "stopSendRtp",param, null);
|
||||
}
|
||||
|
||||
public JSONObject addStreamProxy(String app, String stream, String url, boolean enable_hls, boolean enable_mp4, String rtp_type) {
|
||||
public JSONObject addStreamProxy(IMediaServerItem mediaServerItem,String app, String stream, String url, boolean enable_hls, boolean enable_mp4, String rtp_type) {
|
||||
Map<String, Object> param = new HashMap<>();
|
||||
param.put("vhost", "__defaultVhost__");
|
||||
param.put("app", app);
|
||||
@ -231,33 +228,33 @@ public class ZLMRESTfulUtils {
|
||||
param.put("enable_hls", enable_hls?1:0);
|
||||
param.put("enable_mp4", enable_mp4?1:0);
|
||||
param.put("rtp_type", rtp_type);
|
||||
return sendPost("addStreamProxy",param, null);
|
||||
return sendPost(mediaServerItem, "addStreamProxy",param, null);
|
||||
}
|
||||
|
||||
public JSONObject closeStreams(String app, String stream) {
|
||||
public JSONObject closeStreams(IMediaServerItem mediaServerItem,String app, String stream) {
|
||||
Map<String, Object> param = new HashMap<>();
|
||||
param.put("vhost", "__defaultVhost__");
|
||||
param.put("app", app);
|
||||
param.put("stream", stream);
|
||||
param.put("force", 1);
|
||||
return sendPost("close_streams",param, null);
|
||||
return sendPost(mediaServerItem, "close_streams",param, null);
|
||||
}
|
||||
|
||||
public JSONObject getAllSession() {
|
||||
return sendPost("getAllSession",null, null);
|
||||
public JSONObject getAllSession(IMediaServerItem mediaServerItem) {
|
||||
return sendPost(mediaServerItem, "getAllSession",null, null);
|
||||
}
|
||||
|
||||
public void kickSessions(String localPortSStr) {
|
||||
public void kickSessions(IMediaServerItem mediaServerItem, String localPortSStr) {
|
||||
Map<String, Object> param = new HashMap<>();
|
||||
param.put("local_port", localPortSStr);
|
||||
sendPost("kick_sessions",param, null);
|
||||
sendPost(mediaServerItem, "kick_sessions",param, null);
|
||||
}
|
||||
|
||||
public void getSnap(String flvUrl, int timeout_sec, int expire_sec, String targetPath, String fileName) {
|
||||
public void getSnap(IMediaServerItem mediaServerItem, String flvUrl, int timeout_sec, int expire_sec, String targetPath, String fileName) {
|
||||
Map<String, Object> param = new HashMap<>();
|
||||
param.put("url", flvUrl);
|
||||
param.put("timeout_sec", timeout_sec);
|
||||
param.put("expire_sec", expire_sec);
|
||||
sendPostForImg("getSnap",param, targetPath, fileName);
|
||||
sendPostForImg(mediaServerItem, "getSnap",param, targetPath, fileName);
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,8 @@ import com.alibaba.fastjson.JSONObject;
|
||||
import com.genersoft.iot.vmp.conf.MediaConfig;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
|
||||
import com.genersoft.iot.vmp.gb28181.session.SsrcUtil;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@ -30,10 +32,10 @@ public class ZLMRTPServerFactory {
|
||||
|
||||
private Map<String, Integer> currentStreams = null;
|
||||
|
||||
public int createRTPServer(String streamId) {
|
||||
public int createRTPServer(IMediaServerItem mediaServerItem, String streamId) {
|
||||
if (currentStreams == null) {
|
||||
currentStreams = new HashMap<>();
|
||||
JSONObject jsonObject = zlmresTfulUtils.listRtpServer();
|
||||
JSONObject jsonObject = zlmresTfulUtils.listRtpServer(mediaServerItem);
|
||||
if (jsonObject != null) {
|
||||
JSONArray data = jsonObject.getJSONArray("data");
|
||||
if (data != null) {
|
||||
@ -48,7 +50,7 @@ public class ZLMRTPServerFactory {
|
||||
if (currentStreams.get(streamId) != null) {
|
||||
Map<String, Object> closeRtpServerParam = new HashMap<>();
|
||||
closeRtpServerParam.put("stream_id", streamId);
|
||||
zlmresTfulUtils.closeRtpServer(closeRtpServerParam);
|
||||
zlmresTfulUtils.closeRtpServer(mediaServerItem, closeRtpServerParam);
|
||||
currentStreams.remove(streamId);
|
||||
}
|
||||
|
||||
@ -58,7 +60,7 @@ public class ZLMRTPServerFactory {
|
||||
param.put("port", newPort);
|
||||
param.put("enable_tcp", 1);
|
||||
param.put("stream_id", streamId);
|
||||
JSONObject jsonObject = zlmresTfulUtils.openRtpServer(param);
|
||||
JSONObject jsonObject = zlmresTfulUtils.openRtpServer(mediaServerItem, param);
|
||||
|
||||
if (jsonObject != null) {
|
||||
switch (jsonObject.getInteger("code")){
|
||||
@ -68,11 +70,11 @@ public class ZLMRTPServerFactory {
|
||||
case -300: // id已经存在, 可能已经在其他端口推流
|
||||
Map<String, Object> closeRtpServerParam = new HashMap<>();
|
||||
closeRtpServerParam.put("stream_id", streamId);
|
||||
zlmresTfulUtils.closeRtpServer(closeRtpServerParam);
|
||||
zlmresTfulUtils.closeRtpServer(mediaServerItem, closeRtpServerParam);
|
||||
result = newPort;
|
||||
break;
|
||||
case -400: // 端口占用
|
||||
result= createRTPServer(streamId);
|
||||
result= createRTPServer(mediaServerItem, streamId);
|
||||
break;
|
||||
default:
|
||||
logger.error("创建RTP Server 失败 {}: " + jsonObject.getString("msg"), newPort);
|
||||
@ -85,20 +87,22 @@ public class ZLMRTPServerFactory {
|
||||
return result;
|
||||
}
|
||||
|
||||
public boolean closeRTPServer(String streamId) {
|
||||
public boolean closeRTPServer(IMediaServerItem serverItem, String streamId) {
|
||||
boolean result = false;
|
||||
Map<String, Object> param = new HashMap<>();
|
||||
param.put("stream_id", streamId);
|
||||
JSONObject jsonObject = zlmresTfulUtils.closeRtpServer(param);
|
||||
if (jsonObject != null ) {
|
||||
if (jsonObject.getInteger("code") == 0) {
|
||||
result = jsonObject.getInteger("hit") == 1;
|
||||
if (serverItem !=null){
|
||||
Map<String, Object> param = new HashMap<>();
|
||||
param.put("stream_id", streamId);
|
||||
JSONObject jsonObject = zlmresTfulUtils.closeRtpServer(serverItem, param);
|
||||
if (jsonObject != null ) {
|
||||
if (jsonObject.getInteger("code") == 0) {
|
||||
result = jsonObject.getInteger("hit") == 1;
|
||||
}else {
|
||||
logger.error("关闭RTP Server 失败: " + jsonObject.getString("msg"));
|
||||
}
|
||||
}else {
|
||||
logger.error("关闭RTP Server 失败: " + jsonObject.getString("msg"));
|
||||
// 检查ZLM状态
|
||||
logger.error("关闭RTP Server 失败: 请检查ZLM服务");
|
||||
}
|
||||
}else {
|
||||
// 检查ZLM状态
|
||||
logger.error("关闭RTP Server 失败: 请检查ZLM服务");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@ -131,11 +135,11 @@ public class ZLMRTPServerFactory {
|
||||
* @param tcp 是否为tcp
|
||||
* @return SendRtpItem
|
||||
*/
|
||||
public SendRtpItem createSendRtpItem(String ip, int port, String ssrc, String platformId, String deviceId, String channelId, boolean tcp){
|
||||
public SendRtpItem createSendRtpItem(IMediaServerItem serverItem, String ip, int port, String ssrc, String platformId, String deviceId, String channelId, boolean tcp){
|
||||
String playSsrc = SsrcUtil.getPlaySsrc();
|
||||
int localPort = createRTPServer(SsrcUtil.getPlaySsrc());
|
||||
int localPort = createRTPServer(serverItem, SsrcUtil.getPlaySsrc());
|
||||
if (localPort != -1) {
|
||||
closeRTPServer(playSsrc);
|
||||
closeRTPServer(serverItem, playSsrc);
|
||||
}else {
|
||||
logger.error("没有可用的端口");
|
||||
return null;
|
||||
@ -150,6 +154,7 @@ public class ZLMRTPServerFactory {
|
||||
sendRtpItem.setTcp(tcp);
|
||||
sendRtpItem.setApp("rtp");
|
||||
sendRtpItem.setLocalPort(localPort);
|
||||
sendRtpItem.setMediaServerId(serverItem.getId());
|
||||
return sendRtpItem;
|
||||
}
|
||||
|
||||
@ -163,11 +168,11 @@ public class ZLMRTPServerFactory {
|
||||
* @param tcp 是否为tcp
|
||||
* @return SendRtpItem
|
||||
*/
|
||||
public SendRtpItem createSendRtpItem(String ip, int port, String ssrc, String platformId, String app, String stream, String channelId, boolean tcp){
|
||||
public SendRtpItem createSendRtpItem(IMediaServerItem serverItem, String ip, int port, String ssrc, String platformId, String app, String stream, String channelId, boolean tcp){
|
||||
String playSsrc = SsrcUtil.getPlaySsrc();
|
||||
int localPort = createRTPServer(SsrcUtil.getPlaySsrc());
|
||||
int localPort = createRTPServer(serverItem, SsrcUtil.getPlaySsrc());
|
||||
if (localPort != -1) {
|
||||
closeRTPServer(playSsrc);
|
||||
closeRTPServer(serverItem, playSsrc);
|
||||
}else {
|
||||
logger.error("没有可用的端口");
|
||||
return null;
|
||||
@ -182,21 +187,21 @@ public class ZLMRTPServerFactory {
|
||||
sendRtpItem.setChannelId(channelId);
|
||||
sendRtpItem.setTcp(tcp);
|
||||
sendRtpItem.setLocalPort(localPort);
|
||||
sendRtpItem.setMediaServerId(serverItem.getId());
|
||||
return sendRtpItem;
|
||||
}
|
||||
|
||||
/**
|
||||
* 调用zlm RESTful API —— startSendRtp
|
||||
*/
|
||||
public Boolean startSendRtpStream(Map<String, Object>param) {
|
||||
public Boolean startSendRtpStream(IMediaServerItem mediaServerItem, Map<String, Object>param) {
|
||||
Boolean result = false;
|
||||
JSONObject jsonObject = zlmresTfulUtils.startSendRtp(param);
|
||||
logger.info(jsonObject.toJSONString());
|
||||
JSONObject jsonObject = zlmresTfulUtils.startSendRtp(mediaServerItem, param);
|
||||
if (jsonObject == null) {
|
||||
logger.error("RTP推流失败: 请检查ZLM服务");
|
||||
} else if (jsonObject.getInteger("code") == 0) {
|
||||
result= true;
|
||||
logger.info("RTP推流请求成功,本地推流端口:" + jsonObject.getString("local_port"));
|
||||
logger.info("RTP推流[ {}/{} ]请求成功,本地推流端口:{}" ,param.get("app"), param.get("stream"), jsonObject.getString("local_port"));
|
||||
} else {
|
||||
logger.error("RTP推流失败: " + jsonObject.getString("msg"));
|
||||
}
|
||||
@ -206,16 +211,16 @@ public class ZLMRTPServerFactory {
|
||||
/**
|
||||
* 查询待转推的流是否就绪
|
||||
*/
|
||||
public Boolean isRtpReady(String streamId) {
|
||||
JSONObject mediaInfo = zlmresTfulUtils.getMediaInfo("rtp", "rtmp", streamId);
|
||||
public Boolean isRtpReady(MediaServerItem mediaServerItem, String streamId) {
|
||||
JSONObject mediaInfo = zlmresTfulUtils.getMediaInfo(mediaServerItem,"rtp", "rtmp", streamId);
|
||||
return (mediaInfo.getInteger("code") == 0 && mediaInfo.getBoolean("online"));
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询待转推的流是否就绪
|
||||
*/
|
||||
public Boolean isStreamReady(String app, String streamId) {
|
||||
JSONObject mediaInfo = zlmresTfulUtils.getMediaInfo(app, "rtmp", streamId);
|
||||
public Boolean isStreamReady(IMediaServerItem mediaServerItem, String app, String streamId) {
|
||||
JSONObject mediaInfo = zlmresTfulUtils.getMediaInfo(mediaServerItem, app, "rtmp", streamId);
|
||||
return (mediaInfo.getInteger("code") == 0 && mediaInfo.getBoolean("online"));
|
||||
}
|
||||
|
||||
@ -224,18 +229,17 @@ public class ZLMRTPServerFactory {
|
||||
* @param streamId
|
||||
* @return
|
||||
*/
|
||||
public int totalReaderCount(String app, String streamId) {
|
||||
JSONObject mediaInfo = zlmresTfulUtils.getMediaInfo(app, "rtmp", streamId);
|
||||
public int totalReaderCount(IMediaServerItem mediaServerItem, String app, String streamId) {
|
||||
JSONObject mediaInfo = zlmresTfulUtils.getMediaInfo(mediaServerItem, app, "rtmp", streamId);
|
||||
return mediaInfo.getInteger("totalReaderCount");
|
||||
}
|
||||
|
||||
/**
|
||||
* 调用zlm RESTful API —— stopSendRtp
|
||||
*/
|
||||
public Boolean stopSendRtpStream(Map<String, Object>param) {
|
||||
public Boolean stopSendRtpStream(IMediaServerItem mediaServerItem,Map<String, Object>param) {
|
||||
Boolean result = false;
|
||||
JSONObject jsonObject = zlmresTfulUtils.stopSendRtp(param);
|
||||
logger.info(jsonObject.toJSONString());
|
||||
JSONObject jsonObject = zlmresTfulUtils.stopSendRtp(mediaServerItem, param);
|
||||
if (jsonObject == null) {
|
||||
logger.error("停止RTP推流失败: 请检查ZLM服务");
|
||||
} else if (jsonObject.getInteger("code") == 0) {
|
||||
|
@ -4,7 +4,10 @@ import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.genersoft.iot.vmp.conf.MediaConfig;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
|
||||
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 com.genersoft.iot.vmp.storager.IVideoManagerStorager;
|
||||
import com.genersoft.iot.vmp.service.IStreamProxyService;
|
||||
import org.slf4j.Logger;
|
||||
@ -14,10 +17,10 @@ import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.CommandLineRunner;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import javax.print.attribute.standard.Media;
|
||||
import java.util.*;
|
||||
|
||||
@Component
|
||||
@Order(value=1)
|
||||
@ -25,140 +28,131 @@ public class ZLMRunner implements CommandLineRunner {
|
||||
|
||||
private final static Logger logger = LoggerFactory.getLogger(ZLMRunner.class);
|
||||
|
||||
@Autowired
|
||||
private IVideoManagerStorager storager;
|
||||
|
||||
@Autowired
|
||||
private MediaConfig mediaConfig;
|
||||
|
||||
@Value("${server.port}")
|
||||
private String serverPort;
|
||||
|
||||
@Value("${server.ssl.enabled:false}")
|
||||
private boolean sslEnabled;
|
||||
|
||||
private boolean startGetMedia = false;
|
||||
private Map<String, Boolean> startGetMedia;
|
||||
|
||||
@Autowired
|
||||
private ZLMRESTfulUtils zlmresTfulUtils;
|
||||
|
||||
@Autowired
|
||||
private ZLMMediaListManager zlmMediaListManager;
|
||||
|
||||
@Autowired
|
||||
private ZLMHttpHookSubscribe hookSubscribe;
|
||||
|
||||
@Autowired
|
||||
private ZLMServerManger zlmServerManger;
|
||||
|
||||
@Autowired
|
||||
private IStreamProxyService streamProxyService;
|
||||
|
||||
@Autowired
|
||||
private IMediaServerService mediaServerService;
|
||||
|
||||
@Autowired
|
||||
private MediaConfig mediaConfig;
|
||||
|
||||
@Override
|
||||
public void run(String... strings) throws Exception {
|
||||
// 订阅 zlm启动事件
|
||||
hookSubscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_server_started,null,(response)->{
|
||||
ZLMServerConfig ZLMServerConfig = JSONObject.toJavaObject(response, ZLMServerConfig.class);
|
||||
zLmRunning(ZLMServerConfig);
|
||||
IMediaServerItem presetMediaServer = mediaServerService.getOneByHostAndPort(
|
||||
mediaConfig.getIp(), mediaConfig.getHttpPort());
|
||||
if (presetMediaServer != null) {
|
||||
mediaConfig.setId(presetMediaServer.getId());
|
||||
mediaServerService.update(mediaConfig);
|
||||
}
|
||||
|
||||
// 订阅 zlm启动事件, 新的zlm也会从这里进入系统
|
||||
hookSubscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_server_started,null,
|
||||
(IMediaServerItem mediaServerItem, JSONObject response)->{
|
||||
ZLMServerConfig zlmServerConfig = JSONObject.toJavaObject(response, ZLMServerConfig.class);
|
||||
if (zlmServerConfig !=null ) {
|
||||
startGetMedia.remove(zlmServerConfig.getGeneralMediaServerId());
|
||||
mediaServerService.handLeZLMServerConfig(zlmServerConfig);
|
||||
// zLmRunning(zlmServerConfig);
|
||||
}
|
||||
});
|
||||
|
||||
// 获取zlm信息
|
||||
logger.info("等待zlm接入...");
|
||||
startGetMedia = true;
|
||||
ZLMServerConfig ZLMServerConfig = getMediaServerConfig();
|
||||
logger.info("等待默认zlm接入...");
|
||||
|
||||
if (ZLMServerConfig != null) {
|
||||
zLmRunning(ZLMServerConfig);
|
||||
// 获取所有的zlm, 并开启主动连接
|
||||
List<IMediaServerItem> all = mediaServerService.getAll();
|
||||
if (presetMediaServer == null) {
|
||||
all.add(mediaConfig.getMediaSerItem());
|
||||
}
|
||||
for (IMediaServerItem mediaServerItem : all) {
|
||||
if (startGetMedia == null) startGetMedia = new HashMap<>();
|
||||
startGetMedia.put(mediaServerItem.getId(), true);
|
||||
new Thread(() -> {
|
||||
ZLMServerConfig zlmServerConfig = getMediaServerConfig(mediaServerItem);
|
||||
if (zlmServerConfig != null) {
|
||||
startGetMedia.remove(mediaServerItem.getId());
|
||||
mediaServerService.handLeZLMServerConfig(zlmServerConfig);
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
Timer timer = new Timer();
|
||||
// 1分钟后未连接到则不再去主动连接
|
||||
timer.schedule(new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (startGetMedia != null) {
|
||||
Set<String> allZlmId = startGetMedia.keySet();
|
||||
for (String id : allZlmId) {
|
||||
logger.error("[ {} ]]主动连接失败,不再主动连接", id);
|
||||
startGetMedia.put(id, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}, 60 * 1000 * 2);
|
||||
}
|
||||
|
||||
public ZLMServerConfig getMediaServerConfig() {
|
||||
if (!startGetMedia) return null;
|
||||
JSONObject responseJSON = zlmresTfulUtils.getMediaServerConfig();
|
||||
public ZLMServerConfig getMediaServerConfig(IMediaServerItem mediaServerItem) {
|
||||
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);
|
||||
|
||||
ZLMServerConfig.setIp(mediaServerItem.getIp());
|
||||
}
|
||||
} else {
|
||||
logger.error("getMediaServerConfig失败, 1s后重试");
|
||||
logger.error("[ {} ]-[ {}:{} ]主动连接失败失败, 2s后重试",
|
||||
mediaServerItem.getId(), mediaServerItem.getIp(), mediaServerItem.getHttpPort());
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
Thread.sleep(2000);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
ZLMServerConfig = getMediaServerConfig();
|
||||
ZLMServerConfig = getMediaServerConfig(mediaServerItem);
|
||||
}
|
||||
return ZLMServerConfig;
|
||||
}
|
||||
|
||||
private void saveZLMConfig() {
|
||||
logger.info("设置zlm...");
|
||||
String protocol = sslEnabled ? "https" : "http";
|
||||
String hookPrex = String.format("%s://%s:%s/index/hook", protocol, mediaConfig.getHookIp(), serverPort);
|
||||
String recordHookPrex = null;
|
||||
if (mediaConfig.getRecordAssistPort() != 0) {
|
||||
recordHookPrex = String.format("http://127.0.0.1:%s/api/record", mediaConfig.getRecordAssistPort());
|
||||
}
|
||||
Map<String, Object> param = new HashMap<>();
|
||||
param.put("api.secret",mediaConfig.getSecret()); // -profile:v Baseline
|
||||
param.put("ffmpeg.cmd","%s -fflags nobuffer -rtsp_transport tcp -i %s -c:a aac -strict -2 -ar 44100 -ab 48k -c:v libx264 -f flv %s");
|
||||
param.put("hook.enable","1");
|
||||
param.put("hook.on_flow_report","");
|
||||
param.put("hook.on_play",String.format("%s/on_play", hookPrex));
|
||||
param.put("hook.on_http_access","");
|
||||
param.put("hook.on_publish", String.format("%s/on_publish", hookPrex));
|
||||
param.put("hook.on_record_mp4",recordHookPrex != null? String.format("%s/on_record_mp4", recordHookPrex): "");
|
||||
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", hookPrex));
|
||||
param.put("hook.on_shell_login",String.format("%s/on_shell_login", hookPrex));
|
||||
param.put("hook.on_stream_changed",String.format("%s/on_stream_changed", hookPrex));
|
||||
param.put("hook.on_stream_none_reader",String.format("%s/on_stream_none_reader", hookPrex));
|
||||
param.put("hook.on_stream_not_found",String.format("%s/on_stream_not_found", hookPrex));
|
||||
param.put("hook.timeoutSec","20");
|
||||
param.put("general.streamNoneReaderDelayMS",mediaConfig.getStreamNoneReaderDelayMS());
|
||||
|
||||
JSONObject responseJSON = zlmresTfulUtils.setServerConfig(param);
|
||||
|
||||
if (responseJSON != null && responseJSON.getInteger("code") == 0) {
|
||||
logger.info("设置zlm成功");
|
||||
}else {
|
||||
logger.info("设置zlm失败");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* zlm 连接成功或者zlm重启后
|
||||
*/
|
||||
private void zLmRunning(ZLMServerConfig zlmServerConfig){
|
||||
logger.info( "[ id: " + zlmServerConfig.getGeneralMediaServerId() + "] zlm接入成功...");
|
||||
// 关闭循环获取zlm配置
|
||||
startGetMedia = false;
|
||||
if (mediaConfig.isAutoConfig()) saveZLMConfig();
|
||||
zlmServerManger.updateServerCatch(zlmServerConfig);
|
||||
|
||||
// 清空所有session
|
||||
// zlmMediaListManager.clearAllSessions();
|
||||
|
||||
// 更新流列表
|
||||
zlmMediaListManager.updateMediaList();
|
||||
// 恢复流代理
|
||||
List<StreamProxyItem> streamProxyListForEnable = storager.getStreamProxyListForEnable(true);
|
||||
for (StreamProxyItem streamProxyDto : streamProxyListForEnable) {
|
||||
logger.info("恢复流代理," + streamProxyDto.getApp() + "/" + streamProxyDto.getStream());
|
||||
JSONObject jsonObject = streamProxyService.addStreamProxyToZlm(streamProxyDto);
|
||||
if (jsonObject == null) {
|
||||
// 设置为未启用
|
||||
logger.info("恢复流代理失败,请检查流地址后重新启用" + streamProxyDto.getApp() + "/" + streamProxyDto.getStream());
|
||||
streamProxyService.stop(streamProxyDto.getApp(), streamProxyDto.getStream());
|
||||
}else if (jsonObject.getInteger("code") != 0){ // TODO 将错误信息存入数据库, 前端展示
|
||||
logger.info("恢复流代理失败:" + streamProxyDto.getApp() + "/" + streamProxyDto.getStream() + "[ " + JSONObject.toJSONString(jsonObject) + " ]");
|
||||
streamProxyService.stop(streamProxyDto.getApp(), streamProxyDto.getStream());
|
||||
}
|
||||
}
|
||||
}
|
||||
// private void zLmRunning(ZLMServerConfig zlmServerConfig){
|
||||
// logger.info( "[ id: " + zlmServerConfig.getGeneralMediaServerId() + "] zlm接入成功...");
|
||||
// // 关闭循环获取zlm配置
|
||||
// startGetMedia = false;
|
||||
// MediaServerItem mediaServerItem = new MediaServerItem(zlmServerConfig, sipIp);
|
||||
// storager.updateMediaServer(mediaServerItem);
|
||||
//
|
||||
// if (mediaServerItem.isAutoConfig()) setZLMConfig(mediaServerItem);
|
||||
// zlmServerManger.updateServerCatchFromHook(zlmServerConfig);
|
||||
//
|
||||
// // 清空所有session
|
||||
//// zlmMediaListManager.clearAllSessions();
|
||||
//
|
||||
// // 更新流列表
|
||||
// zlmMediaListManager.updateMediaList(mediaServerItem);
|
||||
// // 恢复流代理, 只查找这个这个流媒体
|
||||
// List<StreamProxyItem> streamProxyListForEnable = storager.getStreamProxyListForEnableInMediaServer(
|
||||
// mediaServerItem.getId(), true);
|
||||
// for (StreamProxyItem streamProxyDto : streamProxyListForEnable) {
|
||||
// logger.info("恢复流代理," + streamProxyDto.getApp() + "/" + streamProxyDto.getStream());
|
||||
// JSONObject jsonObject = streamProxyService.addStreamProxyToZlm(streamProxyDto);
|
||||
// if (jsonObject == null) {
|
||||
// // 设置为未启用
|
||||
// logger.info("恢复流代理失败,请检查流地址后重新启用" + streamProxyDto.getApp() + "/" + streamProxyDto.getStream());
|
||||
// streamProxyService.stop(streamProxyDto.getApp(), streamProxyDto.getStream());
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
@ -34,12 +34,15 @@ public class ZLMServerConfig {
|
||||
@JSONField(name = "general.streamNoneReaderDelayMS")
|
||||
private String generalStreamNoneReaderDelayMS;
|
||||
|
||||
@JSONField(name = "ip")
|
||||
private String ip;
|
||||
|
||||
private String sdpIp;
|
||||
|
||||
private String streamIp;
|
||||
|
||||
private String hookIp;
|
||||
|
||||
private String updateTime;
|
||||
|
||||
private String createTime;
|
||||
@ -66,7 +69,7 @@ public class ZLMServerConfig {
|
||||
private String hookEnable;
|
||||
|
||||
@JSONField(name = "hook.on_flow_report")
|
||||
private Integer hookOnFlowReport;
|
||||
private String hookOnFlowReport;
|
||||
|
||||
@JSONField(name = "hook.on_http_access")
|
||||
private String hookOnHttpAccess;
|
||||
@ -117,7 +120,7 @@ public class ZLMServerConfig {
|
||||
private String httpNotFound;
|
||||
|
||||
@JSONField(name = "http.port")
|
||||
private Integer httpPort;
|
||||
private int httpPort;
|
||||
|
||||
@JSONField(name = "http.rootPath")
|
||||
private String httpRootPath;
|
||||
@ -126,7 +129,7 @@ public class ZLMServerConfig {
|
||||
private String httpSendBufSize;
|
||||
|
||||
@JSONField(name = "http.sslport")
|
||||
private Integer httpSSLport;
|
||||
private int httpSSLport;
|
||||
|
||||
@JSONField(name = "multicast.addrMax")
|
||||
private String multicastAddrMax;
|
||||
@ -159,10 +162,10 @@ public class ZLMServerConfig {
|
||||
private String rtmpModifyStamp;
|
||||
|
||||
@JSONField(name = "rtmp.port")
|
||||
private Integer rtmpPort;
|
||||
private int rtmpPort;
|
||||
|
||||
@JSONField(name = "rtmp.sslport")
|
||||
private Integer rtmpSslPort;
|
||||
private int rtmpSslPort;
|
||||
|
||||
@JSONField(name = "rtp.audioMtuSize")
|
||||
private String rtpAudioMtuSize;
|
||||
@ -186,7 +189,7 @@ public class ZLMServerConfig {
|
||||
private String rtpProxyDumpDir;
|
||||
|
||||
@JSONField(name = "rtp_proxy.port")
|
||||
private Integer rtpProxyPort;
|
||||
private int rtpProxyPort;
|
||||
|
||||
@JSONField(name = "rtp_proxy.timeoutSec")
|
||||
private String rtpProxyTimeoutSec;
|
||||
@ -201,10 +204,10 @@ public class ZLMServerConfig {
|
||||
private String rtspKeepAliveSecond;
|
||||
|
||||
@JSONField(name = "rtsp.port")
|
||||
private Integer rtspPort;
|
||||
private int rtspPort;
|
||||
|
||||
@JSONField(name = "rtsp.sslport")
|
||||
private Integer rtspSSlport;
|
||||
private int rtspSSlport;
|
||||
|
||||
@JSONField(name = "shell.maxReqSize")
|
||||
private String shellMaxReqSize;
|
||||
@ -212,6 +215,15 @@ public class ZLMServerConfig {
|
||||
@JSONField(name = "shell.shell")
|
||||
private String shellPhell;
|
||||
|
||||
|
||||
public String getHookIp() {
|
||||
return hookIp;
|
||||
}
|
||||
|
||||
public void setHookIp(String hookIp) {
|
||||
this.hookIp = hookIp;
|
||||
}
|
||||
|
||||
public String getApiDebug() {
|
||||
return apiDebug;
|
||||
}
|
||||
@ -388,11 +400,11 @@ public class ZLMServerConfig {
|
||||
this.hookEnable = hookEnable;
|
||||
}
|
||||
|
||||
public Integer getHookOnFlowReport() {
|
||||
public String getHookOnFlowReport() {
|
||||
return hookOnFlowReport;
|
||||
}
|
||||
|
||||
public void setHookOnFlowReport(Integer hookOnFlowReport) {
|
||||
public void setHookOnFlowReport(String hookOnFlowReport) {
|
||||
this.hookOnFlowReport = hookOnFlowReport;
|
||||
}
|
||||
|
||||
@ -524,11 +536,11 @@ public class ZLMServerConfig {
|
||||
this.httpNotFound = httpNotFound;
|
||||
}
|
||||
|
||||
public Integer getHttpPort() {
|
||||
public int getHttpPort() {
|
||||
return httpPort;
|
||||
}
|
||||
|
||||
public void setHttpPort(Integer httpPort) {
|
||||
public void setHttpPort(int httpPort) {
|
||||
this.httpPort = httpPort;
|
||||
}
|
||||
|
||||
@ -548,11 +560,11 @@ public class ZLMServerConfig {
|
||||
this.httpSendBufSize = httpSendBufSize;
|
||||
}
|
||||
|
||||
public Integer getHttpSSLport() {
|
||||
public int getHttpSSLport() {
|
||||
return httpSSLport;
|
||||
}
|
||||
|
||||
public void setHttpSSLport(Integer httpSSLport) {
|
||||
public void setHttpSSLport(int httpSSLport) {
|
||||
this.httpSSLport = httpSSLport;
|
||||
}
|
||||
|
||||
@ -636,19 +648,19 @@ public class ZLMServerConfig {
|
||||
this.rtmpModifyStamp = rtmpModifyStamp;
|
||||
}
|
||||
|
||||
public Integer getRtmpPort() {
|
||||
public int getRtmpPort() {
|
||||
return rtmpPort;
|
||||
}
|
||||
|
||||
public void setRtmpPort(Integer rtmpPort) {
|
||||
public void setRtmpPort(int rtmpPort) {
|
||||
this.rtmpPort = rtmpPort;
|
||||
}
|
||||
|
||||
public Integer getRtmpSslPort() {
|
||||
public int getRtmpSslPort() {
|
||||
return rtmpSslPort;
|
||||
}
|
||||
|
||||
public void setRtmpSslPort(Integer rtmpSslPort) {
|
||||
public void setRtmpSslPort(int rtmpSslPort) {
|
||||
this.rtmpSslPort = rtmpSslPort;
|
||||
}
|
||||
|
||||
@ -708,11 +720,11 @@ public class ZLMServerConfig {
|
||||
this.rtpProxyDumpDir = rtpProxyDumpDir;
|
||||
}
|
||||
|
||||
public Integer getRtpProxyPort() {
|
||||
public int getRtpProxyPort() {
|
||||
return rtpProxyPort;
|
||||
}
|
||||
|
||||
public void setRtpProxyPort(Integer rtpProxyPort) {
|
||||
public void setRtpProxyPort(int rtpProxyPort) {
|
||||
this.rtpProxyPort = rtpProxyPort;
|
||||
}
|
||||
|
||||
@ -748,19 +760,19 @@ public class ZLMServerConfig {
|
||||
this.rtspKeepAliveSecond = rtspKeepAliveSecond;
|
||||
}
|
||||
|
||||
public Integer getRtspPort() {
|
||||
public int getRtspPort() {
|
||||
return rtspPort;
|
||||
}
|
||||
|
||||
public void setRtspPort(Integer rtspPort) {
|
||||
public void setRtspPort(int rtspPort) {
|
||||
this.rtspPort = rtspPort;
|
||||
}
|
||||
|
||||
public Integer getRtspSSlport() {
|
||||
public int getRtspSSlport() {
|
||||
return rtspSSlport;
|
||||
}
|
||||
|
||||
public void setRtspSSlport(Integer rtspSSlport) {
|
||||
public void setRtspSSlport(int rtspSSlport) {
|
||||
this.rtspSSlport = rtspSSlport;
|
||||
}
|
||||
|
||||
|
@ -1,45 +0,0 @@
|
||||
package com.genersoft.iot.vmp.media.zlm;
|
||||
|
||||
import com.genersoft.iot.vmp.conf.MediaConfig;
|
||||
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
@Component
|
||||
public class ZLMServerManger {
|
||||
|
||||
@Autowired
|
||||
private IRedisCatchStorage redisCatchStorage;
|
||||
|
||||
@Autowired
|
||||
private MediaConfig mediaConfig;
|
||||
|
||||
public void updateServerCatch(ZLMServerConfig zlmServerConfig) {
|
||||
|
||||
zlmServerConfig.setIp(mediaConfig.getIp());
|
||||
zlmServerConfig.setStreamIp(mediaConfig.getStreamIp());
|
||||
zlmServerConfig.setSdpIp(mediaConfig.getSdpIp());
|
||||
zlmServerConfig.setHttpPort(mediaConfig.getHttpPort());
|
||||
|
||||
if(!StringUtils.isEmpty(mediaConfig.getHttpSSlPort()))
|
||||
zlmServerConfig.setHttpSSLport(mediaConfig.getHttpSSlPort());
|
||||
|
||||
if(!StringUtils.isEmpty(mediaConfig.getRtspPort()))
|
||||
zlmServerConfig.setRtspPort(mediaConfig.getRtspPort());
|
||||
|
||||
if(!StringUtils.isEmpty(mediaConfig.getRtspSSLPort()))
|
||||
zlmServerConfig.setRtspSSlport(mediaConfig.getRtspSSLPort());
|
||||
|
||||
if(!StringUtils.isEmpty(mediaConfig.getRtmpPort()))
|
||||
zlmServerConfig.setRtmpPort(mediaConfig.getRtmpPort());
|
||||
|
||||
if(!StringUtils.isEmpty(mediaConfig.getRtmpSSlPort()))
|
||||
zlmServerConfig.setRtmpSslPort(mediaConfig.getRtmpSSlPort());
|
||||
|
||||
if(!StringUtils.isEmpty(mediaConfig.getRtpProxyPort()))
|
||||
zlmServerConfig.setRtpProxyPort(mediaConfig.getRtpProxyPort());
|
||||
|
||||
redisCatchStorage.updateMediaInfo(zlmServerConfig);
|
||||
}
|
||||
}
|
@ -0,0 +1,92 @@
|
||||
package com.genersoft.iot.vmp.media.zlm.dto;
|
||||
|
||||
public interface IMediaServerItem {
|
||||
|
||||
String getId();
|
||||
|
||||
void setId(String id);
|
||||
|
||||
String getIp();
|
||||
|
||||
void setIp(String ip);
|
||||
|
||||
String getHookIp();
|
||||
|
||||
void setHookIp(String hookIp);
|
||||
|
||||
String getSdpIp();
|
||||
|
||||
void setSdpIp(String sdpIp);
|
||||
|
||||
String getStreamIp();
|
||||
|
||||
void setStreamIp(String streamIp);
|
||||
|
||||
int getHttpPort();
|
||||
|
||||
void setHttpPort(int httpPort);
|
||||
|
||||
int getHttpSSlPort();
|
||||
|
||||
void setHttpSSlPort(int httpSSlPort);
|
||||
|
||||
int getRtmpPort();
|
||||
|
||||
void setRtmpPort(int rtmpPort);
|
||||
|
||||
int getRtmpSSlPort();
|
||||
|
||||
void setRtmpSSlPort(int rtmpSSlPort);
|
||||
|
||||
int getRtpProxyPort();
|
||||
|
||||
void setRtpProxyPort(int rtpProxyPort);
|
||||
|
||||
int getRtspPort();
|
||||
|
||||
void setRtspPort(int rtspPort);
|
||||
|
||||
int getRtspSSLPort();
|
||||
|
||||
void setRtspSSLPort(int rtspSSLPort);
|
||||
|
||||
boolean isAutoConfig();
|
||||
|
||||
void setAutoConfig(boolean autoConfig);
|
||||
|
||||
String getSecret();
|
||||
|
||||
void setSecret(String secret);
|
||||
|
||||
String getStreamNoneReaderDelayMS();
|
||||
|
||||
void setStreamNoneReaderDelayMS(String streamNoneReaderDelayMS);
|
||||
|
||||
boolean isRtpEnable();
|
||||
|
||||
void setRtpEnable(boolean rtpEnable);
|
||||
|
||||
String getRtpPortRange();
|
||||
|
||||
void setRtpPortRange(String rtpPortRange);
|
||||
|
||||
int getRecordAssistPort();
|
||||
|
||||
void setRecordAssistPort(int recordAssistPort);
|
||||
|
||||
boolean isDocker();
|
||||
|
||||
void setDocker(boolean docker);
|
||||
|
||||
String getUpdateTime();
|
||||
|
||||
void setUpdateTime(String updateTime);
|
||||
|
||||
String getCreateTime();
|
||||
|
||||
void setCreateTime(String createTime);
|
||||
|
||||
int getCount();
|
||||
|
||||
void setCount(int count);
|
||||
}
|
@ -78,6 +78,10 @@ public class MediaItem {
|
||||
*/
|
||||
private String vhost;
|
||||
|
||||
/**
|
||||
* 是否是docker部署, docker部署不会自动更新zlm使用的端口,需要自己手动修改
|
||||
*/
|
||||
private boolean docker;
|
||||
|
||||
public static class MediaTrack {
|
||||
/**
|
||||
@ -364,4 +368,12 @@ public class MediaItem {
|
||||
public OriginSock getOriginSock() {
|
||||
return originSock;
|
||||
}
|
||||
|
||||
public boolean isDocker() {
|
||||
return docker;
|
||||
}
|
||||
|
||||
public void setDocker(boolean docker) {
|
||||
this.docker = docker;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,254 @@
|
||||
package com.genersoft.iot.vmp.media.zlm.dto;
|
||||
|
||||
|
||||
import com.genersoft.iot.vmp.media.zlm.ZLMServerConfig;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
public class MediaServerItem implements IMediaServerItem{
|
||||
|
||||
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 boolean autoConfig;
|
||||
|
||||
private String secret;
|
||||
|
||||
private String streamNoneReaderDelayMS;
|
||||
|
||||
private boolean rtpEnable;
|
||||
|
||||
private String rtpPortRange;
|
||||
|
||||
private int recordAssistPort;
|
||||
|
||||
private String createTime;
|
||||
|
||||
private String updateTime;
|
||||
|
||||
private boolean docker;
|
||||
|
||||
private int count;
|
||||
|
||||
public MediaServerItem() {
|
||||
}
|
||||
|
||||
public MediaServerItem(ZLMServerConfig zlmServerConfig, String sipIp) {
|
||||
id = zlmServerConfig.getGeneralMediaServerId();
|
||||
ip = zlmServerConfig.getIp();
|
||||
hookIp = StringUtils.isEmpty(zlmServerConfig.getHookIp())? sipIp: zlmServerConfig.getHookIp();
|
||||
sdpIp = StringUtils.isEmpty(zlmServerConfig.getSdpIp())? zlmServerConfig.getIp(): zlmServerConfig.getSdpIp();
|
||||
streamIp = StringUtils.isEmpty(zlmServerConfig.getStreamIp())? zlmServerConfig.getIp(): zlmServerConfig.getStreamIp();
|
||||
httpPort = zlmServerConfig.getHttpPort();
|
||||
httpSSlPort = zlmServerConfig.getHttpSSLport();
|
||||
rtmpPort = zlmServerConfig.getRtmpPort();
|
||||
rtmpSSlPort = zlmServerConfig.getRtmpSslPort();
|
||||
rtpProxyPort = zlmServerConfig.getRtpProxyPort();
|
||||
rtspPort = zlmServerConfig.getRtspPort();
|
||||
rtspSSLPort = zlmServerConfig.getRtspSSlport();
|
||||
autoConfig = true; // 默认值true;
|
||||
secret = zlmServerConfig.getApiSecret();
|
||||
streamNoneReaderDelayMS = zlmServerConfig.getGeneralStreamNoneReaderDelayMS();
|
||||
rtpEnable = false; // 默认使用单端口;直到用户自己设置开启多端口
|
||||
recordAssistPort = 0; // 默认关闭
|
||||
|
||||
}
|
||||
|
||||
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 boolean isAutoConfig() {
|
||||
return autoConfig;
|
||||
}
|
||||
|
||||
public void setAutoConfig(boolean autoConfig) {
|
||||
this.autoConfig = autoConfig;
|
||||
}
|
||||
|
||||
public String getSecret() {
|
||||
return secret;
|
||||
}
|
||||
|
||||
public void setSecret(String secret) {
|
||||
this.secret = secret;
|
||||
}
|
||||
|
||||
public String getStreamNoneReaderDelayMS() {
|
||||
return streamNoneReaderDelayMS;
|
||||
}
|
||||
|
||||
public void setStreamNoneReaderDelayMS(String streamNoneReaderDelayMS) {
|
||||
this.streamNoneReaderDelayMS = streamNoneReaderDelayMS;
|
||||
}
|
||||
|
||||
public boolean isRtpEnable() {
|
||||
return rtpEnable;
|
||||
}
|
||||
|
||||
public void setRtpEnable(boolean rtpEnable) {
|
||||
this.rtpEnable = rtpEnable;
|
||||
}
|
||||
|
||||
public String getRtpPortRange() {
|
||||
return rtpPortRange;
|
||||
}
|
||||
|
||||
public void setRtpPortRange(String rtpPortRange) {
|
||||
this.rtpPortRange = rtpPortRange;
|
||||
}
|
||||
|
||||
public int getRecordAssistPort() {
|
||||
return recordAssistPort;
|
||||
}
|
||||
|
||||
public void setRecordAssistPort(int recordAssistPort) {
|
||||
this.recordAssistPort = recordAssistPort;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDocker() {
|
||||
return docker;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDocker(boolean docker) {
|
||||
this.docker = docker;
|
||||
}
|
||||
|
||||
public String getCreateTime() {
|
||||
return createTime;
|
||||
}
|
||||
|
||||
public void setCreateTime(String createTime) {
|
||||
this.createTime = createTime;
|
||||
}
|
||||
|
||||
public String getUpdateTime() {
|
||||
return updateTime;
|
||||
}
|
||||
|
||||
public void setUpdateTime(String updateTime) {
|
||||
this.updateTime = updateTime;
|
||||
}
|
||||
|
||||
public int getCount() {
|
||||
return count;
|
||||
}
|
||||
|
||||
public void setCount(int count) {
|
||||
this.count = count;
|
||||
}
|
||||
}
|
@ -7,6 +7,7 @@ public class StreamProxyItem extends GbStream {
|
||||
private String type;
|
||||
private String app;
|
||||
private String stream;
|
||||
private String mediaServerId;
|
||||
private String url;
|
||||
private String src_url;
|
||||
private String dst_url;
|
||||
@ -17,6 +18,7 @@ public class StreamProxyItem extends GbStream {
|
||||
private boolean enable_hls;
|
||||
private boolean enable_mp4;
|
||||
private String platformGbId;
|
||||
private String createTime;
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
@ -42,6 +44,16 @@ public class StreamProxyItem extends GbStream {
|
||||
this.stream = stream;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMediaServerId() {
|
||||
return mediaServerId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMediaServerId(String mediaServerId) {
|
||||
this.mediaServerId = mediaServerId;
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
@ -122,4 +134,12 @@ public class StreamProxyItem extends GbStream {
|
||||
public void setPlatformGbId(String platformGbId) {
|
||||
this.platformGbId = platformGbId;
|
||||
}
|
||||
|
||||
public String getCreateTime() {
|
||||
return createTime;
|
||||
}
|
||||
|
||||
public void setCreateTime(String createTime) {
|
||||
this.createTime = createTime;
|
||||
}
|
||||
}
|
||||
|
@ -76,6 +76,11 @@ public class StreamPushItem extends GbStream implements Comparable<StreamPushIte
|
||||
*/
|
||||
private String vhost;
|
||||
|
||||
/**
|
||||
* 使用的流媒体ID
|
||||
*/
|
||||
private String mediaServerId;
|
||||
|
||||
public String getVhost() {
|
||||
return vhost;
|
||||
}
|
||||
@ -202,5 +207,14 @@ public class StreamPushItem extends GbStream implements Comparable<StreamPushIte
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getMediaServerId() {
|
||||
return mediaServerId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMediaServerId(String mediaServerId) {
|
||||
this.mediaServerId = mediaServerId;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,33 @@
|
||||
package com.genersoft.iot.vmp.media.zlm.dto;
|
||||
|
||||
/**
|
||||
* 记录zlm运行中一些参数
|
||||
*/
|
||||
public class ZLMRunInfo {
|
||||
|
||||
/**
|
||||
* zlm当前流数量
|
||||
*/
|
||||
private int mediaCount;
|
||||
|
||||
/**
|
||||
* 在线状态
|
||||
*/
|
||||
private boolean online;
|
||||
|
||||
public int getMediaCount() {
|
||||
return mediaCount;
|
||||
}
|
||||
|
||||
public void setMediaCount(int mediaCount) {
|
||||
this.mediaCount = mediaCount;
|
||||
}
|
||||
|
||||
public boolean isOnline() {
|
||||
return online;
|
||||
}
|
||||
|
||||
public void setOnline(boolean online) {
|
||||
this.online = online;
|
||||
}
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
package com.genersoft.iot.vmp.service;
|
||||
|
||||
import com.genersoft.iot.vmp.conf.MediaConfig;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.Device;
|
||||
import com.genersoft.iot.vmp.media.zlm.ZLMServerConfig;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 媒体服务节点
|
||||
*/
|
||||
public interface IMediaServerService {
|
||||
|
||||
List<IMediaServerItem> getAll();
|
||||
|
||||
IMediaServerItem getOne(String generalMediaServerId);
|
||||
|
||||
IMediaServerItem getOneByHostAndPort(String host, int port);
|
||||
|
||||
/**
|
||||
* 新的节点加入
|
||||
* @param zlmServerConfig
|
||||
* @return
|
||||
*/
|
||||
void handLeZLMServerConfig(ZLMServerConfig zlmServerConfig);
|
||||
|
||||
void updateServerCatch(IMediaServerItem mediaServerItem, Integer count, Boolean b);
|
||||
|
||||
IMediaServerItem getMediaServerForMinimumLoad();
|
||||
|
||||
void setZLMConfig(IMediaServerItem mediaServerItem);
|
||||
|
||||
void init();
|
||||
|
||||
void closeRTPServer(Device device, String channelId);
|
||||
|
||||
void update(MediaConfig mediaConfig);
|
||||
|
||||
void addCount(String mediaServerId);
|
||||
|
||||
void removeCount(String mediaServerId);
|
||||
}
|
@ -2,6 +2,8 @@ package com.genersoft.iot.vmp.service;
|
||||
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.genersoft.iot.vmp.common.StreamInfo;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
||||
|
||||
/**
|
||||
* 媒体信息业务
|
||||
@ -14,23 +16,8 @@ public interface IMediaService {
|
||||
* @param stream
|
||||
* @return
|
||||
*/
|
||||
StreamInfo getStreamInfoByAppAndStreamWithCheck(String app, String stream);
|
||||
StreamInfo getStreamInfoByAppAndStreamWithCheck(String app, String stream, String mediaServerId,String addr);
|
||||
|
||||
/**
|
||||
* 根据应用名和流ID获取播放地址, 只是地址拼接
|
||||
* @param app
|
||||
* @param stream
|
||||
* @return
|
||||
*/
|
||||
StreamInfo getStreamInfoByAppAndStream(String app, String stream, JSONArray tracks);
|
||||
|
||||
/**
|
||||
* 根据应用名和流ID获取播放地址, 只是地址拼接,返回的ip使用远程访问ip,适用与zlm与wvp在一台主机的情况
|
||||
* @param app
|
||||
* @param stream
|
||||
* @return
|
||||
*/
|
||||
StreamInfo getStreamInfoByAppAndStream(String app, String stream, JSONArray tracks, String addr);
|
||||
|
||||
/**
|
||||
* 根据应用名和流ID获取播放地址, 通过zlm接口检查是否存在, 返回的ip使用远程访问ip,适用与zlm与wvp在一台主机的情况
|
||||
@ -38,5 +25,21 @@ public interface IMediaService {
|
||||
* @param stream
|
||||
* @return
|
||||
*/
|
||||
StreamInfo getStreamInfoByAppAndStreamWithCheck(String app, String stream, String addr);
|
||||
StreamInfo getStreamInfoByAppAndStreamWithCheck(String app, String stream, String mediaServerId);
|
||||
|
||||
/**
|
||||
* 根据应用名和流ID获取播放地址, 只是地址拼接
|
||||
* @param app
|
||||
* @param stream
|
||||
* @return
|
||||
*/
|
||||
StreamInfo getStreamInfoByAppAndStream(IMediaServerItem mediaServerItem, String app, String stream, JSONArray tracks);
|
||||
|
||||
/**
|
||||
* 根据应用名和流ID获取播放地址, 只是地址拼接,返回的ip使用远程访问ip,适用与zlm与wvp在一台主机的情况
|
||||
* @param app
|
||||
* @param stream
|
||||
* @return
|
||||
*/
|
||||
StreamInfo getStreamInfoByAppAndStream(IMediaServerItem mediaInfo, String app, String stream, JSONArray tracks, String addr);
|
||||
}
|
||||
|
@ -1,8 +1,11 @@
|
||||
package com.genersoft.iot.vmp.service;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.Device;
|
||||
import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
|
||||
import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
||||
import com.genersoft.iot.vmp.vmanager.gb28181.play.bean.PlayResult;
|
||||
|
||||
/**
|
||||
@ -10,8 +13,10 @@ import com.genersoft.iot.vmp.vmanager.gb28181.play.bean.PlayResult;
|
||||
*/
|
||||
public interface IPlayService {
|
||||
|
||||
void onPublishHandlerForPlayBack(JSONObject resonse, String deviceId, String channelId, String uuid);
|
||||
void onPublishHandlerForPlay(JSONObject resonse, String deviceId, String channelId, String uuid);
|
||||
void onPublishHandlerForPlayBack(IMediaServerItem mediaServerItem,JSONObject resonse, String deviceId, String channelId, String uuid);
|
||||
void onPublishHandlerForPlay(IMediaServerItem mediaServerItem, JSONObject resonse, String deviceId, String channelId, String uuid);
|
||||
|
||||
PlayResult play(String deviceId, String channelId, ZLMHttpHookSubscribe.Event event, SipSubscribe.Event errorEvent);
|
||||
PlayResult play(IMediaServerItem mediaServerItem, String deviceId, String channelId, ZLMHttpHookSubscribe.Event event, SipSubscribe.Event errorEvent);
|
||||
|
||||
IMediaServerItem getNewMediaServerItem(Device device);
|
||||
}
|
||||
|
@ -1,6 +1,8 @@
|
||||
package com.genersoft.iot.vmp.service;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem;
|
||||
import com.github.pagehelper.PageInfo;
|
||||
|
||||
@ -61,5 +63,5 @@ public interface IStreamProxyService {
|
||||
* 获取ffmpeg.cmd模板
|
||||
* @return
|
||||
*/
|
||||
JSONObject getFFmpegCMDs();
|
||||
JSONObject getFFmpegCMDs(IMediaServerItem mediaServerItem);
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package com.genersoft.iot.vmp.service;
|
||||
|
||||
import com.genersoft.iot.vmp.gb28181.bean.GbStream;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem;
|
||||
import com.github.pagehelper.PageInfo;
|
||||
|
||||
@ -8,7 +9,7 @@ import java.util.List;
|
||||
|
||||
public interface IStreamPushService {
|
||||
|
||||
List<StreamPushItem> handleJSON(String json);
|
||||
List<StreamPushItem> handleJSON(String json, IMediaServerItem mediaServerItem);
|
||||
|
||||
/**
|
||||
* 将应用名和流ID加入国标关联
|
||||
|
@ -0,0 +1,340 @@
|
||||
package com.genersoft.iot.vmp.service.impl;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.genersoft.iot.vmp.common.StreamInfo;
|
||||
import com.genersoft.iot.vmp.conf.MediaConfig;
|
||||
import com.genersoft.iot.vmp.conf.ProxyServletConfig;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.Device;
|
||||
import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
|
||||
import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
|
||||
import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
|
||||
import com.genersoft.iot.vmp.media.zlm.ZLMServerConfig;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.ZLMRunInfo;
|
||||
import com.genersoft.iot.vmp.service.IMediaServerService;
|
||||
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
|
||||
import com.genersoft.iot.vmp.storager.dao.MediaServerMapper;
|
||||
import org.mitre.dsmiley.httpproxy.ProxyServlet;
|
||||
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 java.text.SimpleDateFormat;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* 媒体服务器节点管理
|
||||
*/
|
||||
@Service
|
||||
public class MediaServerServiceImpl implements IMediaServerService {
|
||||
|
||||
private final static Logger logger = LoggerFactory.getLogger(MediaServerServiceImpl.class);
|
||||
|
||||
private Map<String, IMediaServerItem> zlmServers = new HashMap<>(); // 所有数据库的zlm的缓存
|
||||
private Map<String, Integer> zlmServerStatus = new LinkedHashMap<>(); // 所有上线的zlm的缓存以及负载
|
||||
|
||||
@Value("${sip.ip}")
|
||||
private String sipIp;
|
||||
|
||||
@Value("${server.ssl.enabled:false}")
|
||||
private boolean sslEnabled;
|
||||
|
||||
@Value("${server.port}")
|
||||
private String serverPort;
|
||||
|
||||
@Autowired
|
||||
private MediaConfig mediaConfig;
|
||||
|
||||
@Autowired
|
||||
private ZLMRESTfulUtils zlmresTfulUtils;
|
||||
|
||||
@Autowired
|
||||
private MediaServerMapper mediaServerMapper;
|
||||
|
||||
|
||||
@Autowired
|
||||
private IRedisCatchStorage redisCatchStorage;
|
||||
|
||||
@Autowired
|
||||
private VideoStreamSessionManager streamSession;
|
||||
|
||||
@Autowired
|
||||
private ZLMRTPServerFactory zlmrtpServerFactory;
|
||||
|
||||
private SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
|
||||
/**
|
||||
* 初始化
|
||||
*/
|
||||
@Override
|
||||
public void init() {
|
||||
zlmServers.clear();
|
||||
zlmServerStatus.clear();
|
||||
List<MediaServerItem> mediaServerItemList = mediaServerMapper.queryAll();
|
||||
for (IMediaServerItem mediaServerItem : mediaServerItemList) {
|
||||
zlmServers.put(mediaServerItem.getId(), mediaServerItem);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closeRTPServer(Device device, String channelId) {
|
||||
StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(device.getDeviceId(), channelId);
|
||||
IMediaServerItem mediaServerItem = null;
|
||||
if (streamInfo != null) {
|
||||
mediaServerItem = this.getOne (streamInfo.getMediaServerId());
|
||||
}
|
||||
String streamId = String.format("gb_play_%s_%s", device.getDeviceId(), channelId);
|
||||
zlmrtpServerFactory.closeRTPServer(mediaServerItem, streamId);
|
||||
streamSession.remove(device.getDeviceId(), channelId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(MediaConfig mediaConfig) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<IMediaServerItem> getAll() {
|
||||
if (zlmServers.size() == 0) {
|
||||
init();
|
||||
}
|
||||
List<IMediaServerItem> result = new ArrayList<>();
|
||||
for (String id : zlmServers.keySet()) {
|
||||
IMediaServerItem mediaServerItem = zlmServers.get(id);
|
||||
mediaServerItem.setCount(zlmServerStatus.get(id) == null ? 0 : zlmServerStatus.get(id));
|
||||
result.add(mediaServerItem);
|
||||
}
|
||||
return result;
|
||||
|
||||
|
||||
// return mediaServerMapper.queryAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取单个zlm服务器
|
||||
* @param mediaServerId 服务id
|
||||
* @return MediaServerItem
|
||||
*/
|
||||
@Override
|
||||
public IMediaServerItem getOne(String mediaServerId) {
|
||||
if (mediaServerId ==null) return null;
|
||||
IMediaServerItem mediaServerItem = zlmServers.get(mediaServerId);
|
||||
if (mediaServerItem != null) {
|
||||
mediaServerItem.setCount(zlmServerStatus.get(mediaServerId) == null ? 0 : zlmServerStatus.get(mediaServerId));
|
||||
return mediaServerItem;
|
||||
}else {
|
||||
IMediaServerItem item = mediaServerMapper.queryOne(mediaServerId);
|
||||
if (item != null) {
|
||||
zlmServers.put(item.getId(), item);
|
||||
}
|
||||
return item;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public IMediaServerItem getOneByHostAndPort(String host, int port) {
|
||||
return mediaServerMapper.queryOneByHostAndPort(host, port);
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理zlm上线
|
||||
* @param zlmServerConfig zlm上线携带的参数
|
||||
*/
|
||||
@Override
|
||||
public void handLeZLMServerConfig(ZLMServerConfig zlmServerConfig) {
|
||||
logger.info("[ {} ]-[ {}:{} ]已连接",
|
||||
zlmServerConfig.getGeneralMediaServerId(), zlmServerConfig.getIp(), zlmServerConfig.getHttpPort());
|
||||
|
||||
IMediaServerItem serverItem = getOne(zlmServerConfig.getGeneralMediaServerId());
|
||||
String now = this.format.format(new Date(System.currentTimeMillis()));
|
||||
if (serverItem != null) {
|
||||
serverItem.setSecret(zlmServerConfig.getApiSecret());
|
||||
serverItem.setIp(zlmServerConfig.getIp());
|
||||
// 如果是配置文件中的zlm。 也就是默认zlm。 一切以配置文件内容为准
|
||||
// docker部署不会使用zlm配置的端口号;
|
||||
// 直接编译部署的使用配置文件的端口号,如果zlm修改配改了配置,wvp自动修改
|
||||
|
||||
if (serverItem.getId().equals(mediaConfig.getId())
|
||||
|| (serverItem.getIp().equals(mediaConfig.getIp()) && serverItem.getHttpPort() == mediaConfig.getHttpPort())) {
|
||||
// 配置文件的zlm
|
||||
mediaConfig.setId(zlmServerConfig.getGeneralMediaServerId());
|
||||
mediaConfig.setUpdateTime(now);
|
||||
if (mediaConfig.getHttpPort() == 0) mediaConfig.setHttpPort(zlmServerConfig.getHttpPort());
|
||||
if (mediaConfig.getHttpSSlPort() == 0) mediaConfig.setHttpSSlPort(zlmServerConfig.getHttpSSLport());
|
||||
if (mediaConfig.getRtmpPort() == 0) mediaConfig.setRtmpPort(zlmServerConfig.getRtmpPort());
|
||||
if (mediaConfig.getRtmpSSlPort() == 0) mediaConfig.setRtmpSSlPort(zlmServerConfig.getRtmpSslPort());
|
||||
if (mediaConfig.getRtspPort() == 0) mediaConfig.setRtspPort(zlmServerConfig.getRtspPort());
|
||||
if (mediaConfig.getRtspSSLPort() == 0) mediaConfig.setRtspSSLPort(zlmServerConfig.getRtspSSlport());
|
||||
if (mediaConfig.getRtpProxyPort() == 0) mediaConfig.setRtpProxyPort(zlmServerConfig.getRtpProxyPort());
|
||||
mediaServerMapper.update(mediaConfig);
|
||||
serverItem = mediaConfig.getMediaSerItem();
|
||||
setZLMConfig(mediaConfig);
|
||||
}else {
|
||||
if (!serverItem.isDocker()) {
|
||||
serverItem.setHttpPort(zlmServerConfig.getHttpPort());
|
||||
serverItem.setHttpSSlPort(zlmServerConfig.getHttpSSLport());
|
||||
serverItem.setRtmpPort(zlmServerConfig.getRtmpPort());
|
||||
serverItem.setRtmpSSlPort(zlmServerConfig.getRtmpSslPort());
|
||||
serverItem.setRtpProxyPort(zlmServerConfig.getRtpProxyPort());
|
||||
serverItem.setRtspPort(zlmServerConfig.getRtspPort());
|
||||
|
||||
}
|
||||
serverItem.setUpdateTime(now);
|
||||
mediaServerMapper.update(serverItem);
|
||||
setZLMConfig(serverItem);
|
||||
}
|
||||
}else {
|
||||
if (zlmServerConfig.getGeneralMediaServerId().equals(mediaConfig.getId())
|
||||
|| (zlmServerConfig.getIp().equals(mediaConfig.getIp()) && zlmServerConfig.getHttpPort() == mediaConfig.getHttpPort())) {
|
||||
mediaConfig.setId(zlmServerConfig.getGeneralMediaServerId());
|
||||
mediaConfig.setCreateTime(now);
|
||||
mediaConfig.setUpdateTime(now);
|
||||
serverItem = mediaConfig;
|
||||
mediaServerMapper.add(mediaConfig);
|
||||
}else {
|
||||
// 一个新的zlm接入wvp
|
||||
serverItem = new MediaServerItem(zlmServerConfig, sipIp);
|
||||
serverItem.setCreateTime(now);
|
||||
serverItem.setUpdateTime(now);
|
||||
mediaServerMapper.add(serverItem);
|
||||
}
|
||||
}
|
||||
// 更新缓存
|
||||
if (zlmServerStatus.get(serverItem.getId()) == null) {
|
||||
zlmServers.put(serverItem.getId(), serverItem);
|
||||
zlmServerStatus.put(serverItem.getId(),0);
|
||||
}
|
||||
// 查询服务流数量
|
||||
IMediaServerItem finalServerItem = serverItem;
|
||||
zlmresTfulUtils.getMediaList(serverItem, null, null, "rtmp",(mediaList ->{
|
||||
Integer code = mediaList.getInteger("code");
|
||||
if (code == 0) {
|
||||
JSONArray data = mediaList.getJSONArray("data");
|
||||
if (data != null) {
|
||||
zlmServerStatus.put(finalServerItem.getId(),data.size());
|
||||
}else {
|
||||
zlmServerStatus.put(finalServerItem.getId(),0);
|
||||
}
|
||||
|
||||
}
|
||||
}));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新缓存
|
||||
* @param mediaServerItem zlm服务
|
||||
* @param count 在线数
|
||||
* @param online 在线状态
|
||||
*/
|
||||
@Override
|
||||
public void updateServerCatch(IMediaServerItem mediaServerItem, Integer count, Boolean online) {
|
||||
if (mediaServerItem != null) {
|
||||
zlmServers.put(mediaServerItem.getId(), mediaServerItem);
|
||||
Collection<Integer> values = zlmServerStatus.values();
|
||||
if (online != null && count != null) {
|
||||
zlmServerStatus.put(mediaServerItem.getId(), count);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addCount(String mediaServerId) {
|
||||
if (zlmServerStatus.get(mediaServerId) != null) {
|
||||
zlmServerStatus.put(mediaServerId, zlmServerStatus.get(mediaServerId) + 1);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeCount(String mediaServerId) {
|
||||
if (zlmServerStatus.get(mediaServerId) != null) {
|
||||
zlmServerStatus.put(mediaServerId, zlmServerStatus.get(mediaServerId) - 1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取负载最低的节点
|
||||
* @return MediaServerItem
|
||||
*/
|
||||
@Override
|
||||
public IMediaServerItem getMediaServerForMinimumLoad() {
|
||||
int mediaCount = -1;
|
||||
String key = null;
|
||||
System.out.println(JSON.toJSONString(zlmServerStatus));
|
||||
if (zlmServerStatus.size() == 1) {
|
||||
Map.Entry entry = zlmServerStatus.entrySet().iterator().next();
|
||||
key= (String) entry.getKey();
|
||||
}else {
|
||||
for (String id : zlmServerStatus.keySet()) {
|
||||
if (key == null) {
|
||||
key = id;
|
||||
mediaCount = zlmServerStatus.get(id);
|
||||
}
|
||||
if (zlmServerStatus.get(id) == 0) {
|
||||
key = id;
|
||||
break;
|
||||
}else if (mediaCount >= zlmServerStatus.get(id)){
|
||||
mediaCount = zlmServerStatus.get(id);
|
||||
key = id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (key == null) {
|
||||
logger.info("获取负载最低的节点时无在线节点");
|
||||
return null;
|
||||
}else{
|
||||
return zlmServers.get(key);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 对zlm服务器进行基础配置
|
||||
* @param mediaServerItem 服务ID
|
||||
*/
|
||||
@Override
|
||||
public void setZLMConfig(IMediaServerItem mediaServerItem) {
|
||||
logger.info("[ {} ]-[ {}:{} ]设置zlm",
|
||||
mediaServerItem.getId(), mediaServerItem.getIp(), mediaServerItem.getHttpPort());
|
||||
String protocol = sslEnabled ? "https" : "http";
|
||||
String hookPrex = String.format("%s://%s:%s/index/hook", protocol, mediaServerItem.getHookIp(), serverPort);
|
||||
String recordHookPrex = null;
|
||||
if (mediaServerItem.getRecordAssistPort() != 0) {
|
||||
recordHookPrex = String.format("http://127.0.0.1:%s/api/record", mediaServerItem.getRecordAssistPort());
|
||||
}
|
||||
Map<String, Object> param = new HashMap<>();
|
||||
param.put("api.secret",mediaServerItem.getSecret()); // -profile:v Baseline
|
||||
param.put("ffmpeg.cmd","%s -fflags nobuffer -i %s -c:a aac -strict -2 -ar 44100 -ab 48k -c:v libx264 -f flv %s");
|
||||
param.put("hook.enable","1");
|
||||
param.put("hook.on_flow_report","");
|
||||
param.put("hook.on_play",String.format("%s/on_play", hookPrex));
|
||||
param.put("hook.on_http_access","");
|
||||
param.put("hook.on_publish", String.format("%s/on_publish", hookPrex));
|
||||
param.put("hook.on_record_mp4",recordHookPrex != null? String.format("%s/on_record_mp4", recordHookPrex): "");
|
||||
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", hookPrex));
|
||||
param.put("hook.on_shell_login",String.format("%s/on_shell_login", hookPrex));
|
||||
param.put("hook.on_stream_changed",String.format("%s/on_stream_changed", hookPrex));
|
||||
param.put("hook.on_stream_none_reader",String.format("%s/on_stream_none_reader", hookPrex));
|
||||
param.put("hook.on_stream_not_found",String.format("%s/on_stream_not_found", hookPrex));
|
||||
param.put("hook.timeoutSec","20");
|
||||
param.put("general.streamNoneReaderDelayMS",mediaServerItem.getStreamNoneReaderDelayMS());
|
||||
|
||||
JSONObject responseJSON = zlmresTfulUtils.setServerConfig(mediaServerItem, param);
|
||||
|
||||
if (responseJSON != null && responseJSON.getInteger("code") == 0) {
|
||||
logger.info("[ {} ]-[ {}:{} ]设置zlm成功",
|
||||
mediaServerItem.getId(), mediaServerItem.getIp(), mediaServerItem.getHttpPort());
|
||||
}else {
|
||||
logger.info("[ {} ]-[ {}:{} ]设置zlm失败" + responseJSON.getString("msg"),
|
||||
mediaServerItem.getId(), mediaServerItem.getIp(), mediaServerItem.getHttpPort());
|
||||
}
|
||||
}
|
||||
}
|
@ -6,6 +6,9 @@ import com.alibaba.fastjson.JSONObject;
|
||||
import com.genersoft.iot.vmp.common.StreamInfo;
|
||||
import com.genersoft.iot.vmp.media.zlm.ZLMServerConfig;
|
||||
import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
||||
import com.genersoft.iot.vmp.service.IMediaServerService;
|
||||
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
|
||||
import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
|
||||
import com.genersoft.iot.vmp.service.IMediaService;
|
||||
@ -21,30 +24,53 @@ public class MediaServiceImpl implements IMediaService {
|
||||
@Autowired
|
||||
private IVideoManagerStorager storager;
|
||||
|
||||
@Autowired
|
||||
private IMediaServerService mediaServerService;
|
||||
|
||||
@Autowired
|
||||
private ZLMRESTfulUtils zlmresTfulUtils;
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public StreamInfo getStreamInfoByAppAndStream(String app, String stream, JSONArray tracks) {
|
||||
return getStreamInfoByAppAndStream(app, stream, tracks, null);
|
||||
public StreamInfo getStreamInfoByAppAndStream(IMediaServerItem mediaInfo, String app, String stream, JSONArray tracks) {
|
||||
return getStreamInfoByAppAndStream(mediaInfo, app, stream, tracks, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public StreamInfo getStreamInfoByAppAndStreamWithCheck(String app, String stream) {
|
||||
return getStreamInfoByAppAndStreamWithCheck(app, stream, null);
|
||||
public StreamInfo getStreamInfoByAppAndStreamWithCheck(String app, String stream, String mediaServerId, String addr) {
|
||||
StreamInfo streamInfo = null;
|
||||
IMediaServerItem mediaInfo = mediaServerService.getOne(mediaServerId);
|
||||
if (mediaInfo == null) {
|
||||
return streamInfo;
|
||||
}
|
||||
JSONObject mediaList = zlmresTfulUtils.getMediaList(mediaInfo, app, stream);
|
||||
if (mediaList != null) {
|
||||
if (mediaList.getInteger("code") == 0) {
|
||||
JSONArray data = mediaList.getJSONArray("data");
|
||||
if (data == null) return null;
|
||||
JSONObject mediaJSON = JSON.parseObject(JSON.toJSONString(data.get(0)), JSONObject.class);
|
||||
JSONArray tracks = mediaJSON.getJSONArray("tracks");
|
||||
streamInfo = getStreamInfoByAppAndStream(mediaInfo, app, stream, tracks);
|
||||
}
|
||||
}
|
||||
return streamInfo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StreamInfo getStreamInfoByAppAndStream(String app, String stream, JSONArray tracks, String addr) {
|
||||
ZLMServerConfig mediaInfo = redisCatchStorage.getMediaInfo();
|
||||
public StreamInfo getStreamInfoByAppAndStreamWithCheck(String app, String stream, String mediaServerId) {
|
||||
return getStreamInfoByAppAndStreamWithCheck(app, stream, mediaServerId, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public StreamInfo getStreamInfoByAppAndStream(IMediaServerItem mediaInfo, String app, String stream, JSONArray tracks, String addr) {
|
||||
StreamInfo streamInfoResult = new StreamInfo();
|
||||
streamInfoResult.setStreamId(stream);
|
||||
streamInfoResult.setApp(app);
|
||||
if (addr == null) {
|
||||
addr = mediaInfo.getStreamIp();
|
||||
}
|
||||
streamInfoResult.setMediaServerId(mediaInfo.getId());
|
||||
streamInfoResult.setRtmp(String.format("rtmp://%s:%s/%s/%s", addr, mediaInfo.getRtmpPort(), app, stream));
|
||||
streamInfoResult.setRtsp(String.format("rtsp://%s:%s/%s/%s", addr, mediaInfo.getRtspPort(), app, stream));
|
||||
streamInfoResult.setFlv(String.format("http://%s:%s/%s/%s.flv", addr, mediaInfo.getHttpPort(), app, stream));
|
||||
@ -60,19 +86,4 @@ public class MediaServiceImpl implements IMediaService {
|
||||
return streamInfoResult;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StreamInfo getStreamInfoByAppAndStreamWithCheck(String app, String stream, String addr) {
|
||||
StreamInfo streamInfo = null;
|
||||
JSONObject mediaList = zlmresTfulUtils.getMediaList(app, stream);
|
||||
if (mediaList != null) {
|
||||
if (mediaList.getInteger("code") == 0) {
|
||||
JSONArray data = mediaList.getJSONArray("data");
|
||||
if (data == null) return null;
|
||||
JSONObject mediaJSON = JSON.parseObject(JSON.toJSONString(data.get(0)), JSONObject.class);
|
||||
JSONArray tracks = mediaJSON.getJSONArray("tracks");
|
||||
streamInfo = getStreamInfoByAppAndStream(app, stream, tracks, addr);
|
||||
}
|
||||
}
|
||||
return streamInfo;
|
||||
}
|
||||
}
|
||||
|
@ -14,6 +14,9 @@ import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
|
||||
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
|
||||
import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe;
|
||||
import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
||||
import com.genersoft.iot.vmp.service.IMediaServerService;
|
||||
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
|
||||
import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
|
||||
import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
|
||||
@ -59,6 +62,9 @@ public class PlayServiceImpl implements IPlayService {
|
||||
@Autowired
|
||||
private IMediaService mediaService;
|
||||
|
||||
@Autowired
|
||||
private IMediaServerService mediaServerService;
|
||||
|
||||
@Autowired
|
||||
private VideoStreamSessionManager streamSession;
|
||||
|
||||
@ -67,8 +73,18 @@ public class PlayServiceImpl implements IPlayService {
|
||||
|
||||
|
||||
@Override
|
||||
public PlayResult play(String deviceId, String channelId, ZLMHttpHookSubscribe.Event hookEvent, SipSubscribe.Event errorEvent) {
|
||||
public PlayResult play(IMediaServerItem mediaServerItem, String deviceId, String channelId, ZLMHttpHookSubscribe.Event hookEvent, SipSubscribe.Event errorEvent) {
|
||||
PlayResult playResult = new PlayResult();
|
||||
if (mediaServerItem == null) {
|
||||
RequestMessage msg = new RequestMessage();
|
||||
msg.setId(DeferredResultHolder.CALLBACK_CMD_PlAY + playResult.getUuid());
|
||||
WVPResult wvpResult = new WVPResult();
|
||||
wvpResult.setCode(-1);
|
||||
wvpResult.setMsg("未找到可用的zlm");
|
||||
msg.setData(wvpResult);
|
||||
resultHolder.invokeResult(msg);
|
||||
return playResult;
|
||||
}
|
||||
Device device = storager.queryVideoDevice(deviceId);
|
||||
StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(deviceId, channelId);
|
||||
playResult.setDevice(device);
|
||||
@ -82,7 +98,7 @@ public class PlayServiceImpl implements IPlayService {
|
||||
result.onTimeout(()->{
|
||||
logger.warn(String.format("设备点播超时,deviceId:%s ,channelId:%s", deviceId, channelId));
|
||||
// 释放rtpserver
|
||||
cmder.closeRTPServer(playResult.getDevice(), channelId);
|
||||
mediaServerService.closeRTPServer(playResult.getDevice(), channelId);
|
||||
RequestMessage msg = new RequestMessage();
|
||||
msg.setId(DeferredResultHolder.CALLBACK_CMD_PlAY + playResult.getUuid());
|
||||
WVPResult wvpResult = new WVPResult();
|
||||
@ -115,9 +131,10 @@ public class PlayServiceImpl implements IPlayService {
|
||||
WVPResult wvpResult = (WVPResult)responseEntity.getBody();
|
||||
if (wvpResult.getCode() == 0) {
|
||||
StreamInfo streamInfoForSuccess = (StreamInfo)wvpResult.getData();
|
||||
IMediaServerItem mediaInfo = mediaServerService.getOne(streamInfoForSuccess.getMediaServerId());
|
||||
String streamUrl = streamInfoForSuccess.getFmp4();
|
||||
// 请求截图
|
||||
zlmresTfulUtils.getSnap(streamUrl, 15, 1, path, fileName);
|
||||
zlmresTfulUtils.getSnap(mediaInfo, streamUrl, 15, 1, path, fileName);
|
||||
}
|
||||
}
|
||||
} catch (FileNotFoundException e) {
|
||||
@ -126,17 +143,17 @@ public class PlayServiceImpl implements IPlayService {
|
||||
});
|
||||
if (streamInfo == null) {
|
||||
// 发送点播消息
|
||||
cmder.playStreamCmd(device, channelId, (JSONObject response) -> {
|
||||
cmder.playStreamCmd(mediaServerItem, device, channelId, (IMediaServerItem mediaServerItemInUse, JSONObject response) -> {
|
||||
logger.info("收到订阅消息: " + response.toJSONString());
|
||||
onPublishHandlerForPlay(response, deviceId, channelId, uuid.toString());
|
||||
onPublishHandlerForPlay(mediaServerItemInUse, response, deviceId, channelId, uuid.toString());
|
||||
if (hookEvent != null) {
|
||||
hookEvent.response(response);
|
||||
hookEvent.response(mediaServerItem, response);
|
||||
}
|
||||
}, event -> {
|
||||
}, (event) -> {
|
||||
RequestMessage msg = new RequestMessage();
|
||||
msg.setId(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid);
|
||||
Response response = event.getResponse();
|
||||
cmder.closeRTPServer(playResult.getDevice(), channelId);
|
||||
mediaServerService.closeRTPServer(playResult.getDevice(), channelId);
|
||||
WVPResult wvpResult = new WVPResult();
|
||||
wvpResult.setCode(-1);
|
||||
wvpResult.setMsg(String.format("点播失败, 错误码: %s, %s", response.getStatusCode(), response.getReasonPhrase()));
|
||||
@ -158,7 +175,10 @@ public class PlayServiceImpl implements IPlayService {
|
||||
resultHolder.invokeResult(msg);
|
||||
return playResult;
|
||||
}
|
||||
JSONObject rtpInfo = zlmresTfulUtils.getRtpInfo(streamId);
|
||||
String mediaServerId = streamInfo.getMediaServerId();
|
||||
IMediaServerItem mediaInfo = mediaServerService.getOne(mediaServerId);
|
||||
|
||||
JSONObject rtpInfo = zlmresTfulUtils.getRtpInfo(mediaInfo, streamId);
|
||||
if (rtpInfo != null && rtpInfo.getBoolean("exist")) {
|
||||
RequestMessage msg = new RequestMessage();
|
||||
msg.setId(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid);
|
||||
@ -171,16 +191,16 @@ public class PlayServiceImpl implements IPlayService {
|
||||
|
||||
resultHolder.invokeResult(msg);
|
||||
if (hookEvent != null) {
|
||||
hookEvent.response(JSONObject.parseObject(JSON.toJSONString(streamInfo)));
|
||||
hookEvent.response(mediaServerItem, JSONObject.parseObject(JSON.toJSONString(streamInfo)));
|
||||
}
|
||||
} else {
|
||||
redisCatchStorage.stopPlay(streamInfo);
|
||||
storager.stopPlay(streamInfo.getDeviceID(), streamInfo.getChannelId());
|
||||
cmder.playStreamCmd(device, channelId, (JSONObject response) -> {
|
||||
cmder.playStreamCmd(mediaServerItem, device, channelId, (IMediaServerItem mediaServerItemInuse, JSONObject response) -> {
|
||||
logger.info("收到订阅消息: " + response.toJSONString());
|
||||
onPublishHandlerForPlay(response, deviceId, channelId, uuid.toString());
|
||||
}, event -> {
|
||||
cmder.closeRTPServer(playResult.getDevice(), channelId);
|
||||
onPublishHandlerForPlay(mediaServerItemInuse, response, deviceId, channelId, uuid.toString());
|
||||
}, (event) -> {
|
||||
mediaServerService.closeRTPServer(playResult.getDevice(), channelId);
|
||||
RequestMessage msg = new RequestMessage();
|
||||
msg.setId(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid);
|
||||
Response response = event.getResponse();
|
||||
@ -198,10 +218,10 @@ public class PlayServiceImpl implements IPlayService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPublishHandlerForPlay(JSONObject resonse, String deviceId, String channelId, String uuid) {
|
||||
public void onPublishHandlerForPlay(IMediaServerItem mediaServerItem, JSONObject resonse, String deviceId, String channelId, String uuid) {
|
||||
RequestMessage msg = new RequestMessage();
|
||||
msg.setId(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid);
|
||||
StreamInfo streamInfo = onPublishHandler(resonse, deviceId, channelId, uuid);
|
||||
StreamInfo streamInfo = onPublishHandler(mediaServerItem, resonse, deviceId, channelId, uuid);
|
||||
if (streamInfo != null) {
|
||||
DeviceChannel deviceChannel = storager.queryChannel(deviceId, channelId);
|
||||
if (deviceChannel != null) {
|
||||
@ -234,10 +254,26 @@ public class PlayServiceImpl implements IPlayService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPublishHandlerForPlayBack(JSONObject resonse, String deviceId, String channelId, String uuid) {
|
||||
public IMediaServerItem getNewMediaServerItem(Device device) {
|
||||
if (device == null) return null;
|
||||
String mediaServerId = device.getMediaServerId();
|
||||
IMediaServerItem mediaServerItem = null;
|
||||
if (mediaServerId == null) {
|
||||
mediaServerItem = mediaServerService.getMediaServerForMinimumLoad();
|
||||
}else {
|
||||
mediaServerItem = mediaServerService.getOne(mediaServerId);
|
||||
}
|
||||
if (mediaServerItem == null) {
|
||||
logger.warn("点播时未找到可使用的ZLM...");
|
||||
}
|
||||
return mediaServerItem;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPublishHandlerForPlayBack(IMediaServerItem mediaServerItem, JSONObject resonse, String deviceId, String channelId, String uuid) {
|
||||
RequestMessage msg = new RequestMessage();
|
||||
msg.setId(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid);
|
||||
StreamInfo streamInfo = onPublishHandler(resonse, deviceId, channelId, uuid);
|
||||
StreamInfo streamInfo = onPublishHandler(mediaServerItem, resonse, deviceId, channelId, uuid);
|
||||
if (streamInfo != null) {
|
||||
redisCatchStorage.startPlayback(streamInfo);
|
||||
msg.setData(JSON.toJSONString(streamInfo));
|
||||
@ -249,10 +285,10 @@ public class PlayServiceImpl implements IPlayService {
|
||||
}
|
||||
}
|
||||
|
||||
public StreamInfo onPublishHandler(JSONObject resonse, String deviceId, String channelId, String uuid) {
|
||||
public StreamInfo onPublishHandler(IMediaServerItem mediaServerItem, JSONObject resonse, String deviceId, String channelId, String uuid) {
|
||||
String streamId = resonse.getString("stream");
|
||||
JSONArray tracks = resonse.getJSONArray("tracks");
|
||||
StreamInfo streamInfo = mediaService.getStreamInfoByAppAndStream("rtp", streamId, tracks);
|
||||
StreamInfo streamInfo = mediaService.getStreamInfoByAppAndStream(mediaServerItem,"rtp", streamId, tracks);
|
||||
streamInfo.setDeviceID(deviceId);
|
||||
streamInfo.setChannelId(channelId);
|
||||
return streamInfo;
|
||||
|
@ -2,10 +2,12 @@ package com.genersoft.iot.vmp.service.impl;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.GbStream;
|
||||
import com.genersoft.iot.vmp.media.zlm.ZLMServerConfig;
|
||||
import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem;
|
||||
import com.genersoft.iot.vmp.service.IGbStreamService;
|
||||
import com.genersoft.iot.vmp.service.IMediaServerService;
|
||||
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
|
||||
import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
|
||||
import com.genersoft.iot.vmp.storager.dao.GbStreamMapper;
|
||||
@ -13,6 +15,8 @@ import com.genersoft.iot.vmp.storager.dao.PlatformGbStreamMapper;
|
||||
import com.genersoft.iot.vmp.storager.dao.StreamProxyMapper;
|
||||
import com.genersoft.iot.vmp.service.IStreamProxyService;
|
||||
import com.github.pagehelper.PageInfo;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@ -25,6 +29,8 @@ import java.util.List;
|
||||
@Service
|
||||
public class StreamProxyServiceImpl implements IStreamProxyService {
|
||||
|
||||
private final static Logger logger = LoggerFactory.getLogger(StreamProxyServiceImpl.class);
|
||||
|
||||
@Autowired
|
||||
private IVideoManagerStorager videoManagerStorager;
|
||||
|
||||
@ -32,7 +38,7 @@ public class StreamProxyServiceImpl implements IStreamProxyService {
|
||||
private IRedisCatchStorage redisCatchStorage;
|
||||
|
||||
@Autowired
|
||||
private ZLMRESTfulUtils zlmresTfulUtils;
|
||||
private ZLMRESTfulUtils zlmresTfulUtils;;
|
||||
|
||||
@Autowired
|
||||
private StreamProxyMapper streamProxyMapper;
|
||||
@ -46,15 +52,28 @@ public class StreamProxyServiceImpl implements IStreamProxyService {
|
||||
@Autowired
|
||||
private IGbStreamService gbStreamService;
|
||||
|
||||
@Autowired
|
||||
private IMediaServerService mediaServerService;
|
||||
|
||||
|
||||
@Override
|
||||
public String save(StreamProxyItem param) {
|
||||
ZLMServerConfig mediaInfo = redisCatchStorage.getMediaInfo();
|
||||
IMediaServerItem mediaInfo;
|
||||
if ("auto".equals(param.getMediaServerId())){
|
||||
mediaInfo = mediaServerService.getMediaServerForMinimumLoad();
|
||||
}else {
|
||||
mediaInfo = mediaServerService.getOne(param.getMediaServerId());
|
||||
}
|
||||
if (mediaInfo == null) {
|
||||
logger.warn("保存代理未找到在线的ZLM...");
|
||||
return "保存失败";
|
||||
}
|
||||
String dstUrl = String.format("rtmp://%s:%s/%s/%s", "127.0.0.1", mediaInfo.getRtmpPort(), param.getApp(),
|
||||
param.getStream() );
|
||||
param.setDst_url(dstUrl);
|
||||
StringBuffer result = new StringBuffer();
|
||||
boolean streamLive = false;
|
||||
param.setMediaServerId(mediaInfo.getId());
|
||||
// 更新
|
||||
if (videoManagerStorager.queryStreamProxy(param.getApp(), param.getStream()) != null) {
|
||||
if (videoManagerStorager.updateStreamProxy(param)) {
|
||||
@ -81,6 +100,8 @@ public class StreamProxyServiceImpl implements IStreamProxyService {
|
||||
videoManagerStorager.updateStreamProxy(param);
|
||||
}
|
||||
}
|
||||
}else {
|
||||
result.append("保存失败");
|
||||
}
|
||||
|
||||
}
|
||||
@ -99,11 +120,18 @@ public class StreamProxyServiceImpl implements IStreamProxyService {
|
||||
@Override
|
||||
public JSONObject addStreamProxyToZlm(StreamProxyItem param) {
|
||||
JSONObject result = null;
|
||||
IMediaServerItem mediaServerItem = null;
|
||||
if (param.getMediaServerId() == null) {
|
||||
logger.warn("添加代理时MediaServerId 为null");
|
||||
return null;
|
||||
}else {
|
||||
mediaServerItem = mediaServerService.getOne(param.getMediaServerId());
|
||||
}
|
||||
if ("default".equals(param.getType())){
|
||||
result = zlmresTfulUtils.addStreamProxy(param.getApp(), param.getStream(), param.getUrl(),
|
||||
result = zlmresTfulUtils.addStreamProxy(mediaServerItem, param.getApp(), param.getStream(), param.getUrl(),
|
||||
param.isEnable_hls(), param.isEnable_mp4(), param.getRtp_type());
|
||||
}else if ("ffmpeg".equals(param.getType())) {
|
||||
result = zlmresTfulUtils.addFFmpegSource(param.getSrc_url(), param.getDst_url(),
|
||||
result = zlmresTfulUtils.addFFmpegSource(mediaServerItem, param.getSrc_url(), param.getDst_url(),
|
||||
param.getTimeout_ms() + "", param.isEnable_hls(), param.isEnable_mp4(),
|
||||
param.getFfmpeg_cmd_key());
|
||||
}
|
||||
@ -112,8 +140,9 @@ public class StreamProxyServiceImpl implements IStreamProxyService {
|
||||
|
||||
@Override
|
||||
public JSONObject removeStreamProxyFromZlm(StreamProxyItem param) {
|
||||
JSONObject result = zlmresTfulUtils.closeStreams(param.getApp(), param.getStream());
|
||||
|
||||
if (param ==null) return null;
|
||||
IMediaServerItem mediaServerItem = mediaServerService.getOne(param.getMediaServerId());
|
||||
JSONObject result = zlmresTfulUtils.closeStreams(mediaServerItem, param.getApp(), param.getStream());
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -124,17 +153,18 @@ public class StreamProxyServiceImpl implements IStreamProxyService {
|
||||
|
||||
@Override
|
||||
public void del(String app, String stream) {
|
||||
StreamProxyItem streamProxyItem = new StreamProxyItem();
|
||||
streamProxyItem.setApp(app);
|
||||
streamProxyItem.setStream(stream);
|
||||
JSONObject jsonObject = removeStreamProxyFromZlm(streamProxyItem);
|
||||
if (jsonObject.getInteger("code") == 0) {
|
||||
StreamProxyItem streamProxyItem = videoManagerStorager.queryStreamProxy(app, stream);
|
||||
if (streamProxyItem != null) {
|
||||
videoManagerStorager.deleteStreamProxy(app, stream);
|
||||
// 如果关联了国标那么移除关联
|
||||
gbStreamMapper.del(app, stream);
|
||||
platformGbStreamMapper.delByAppAndStream(app, stream);
|
||||
// TODO 如果关联的推流, 那么状态设置为离线
|
||||
JSONObject jsonObject = removeStreamProxyFromZlm(streamProxyItem);
|
||||
if (jsonObject != null && jsonObject.getInteger("code") == 0) {
|
||||
// 如果关联了国标那么移除关联
|
||||
gbStreamMapper.del(app, stream);
|
||||
platformGbStreamMapper.delByAppAndStream(app, stream);
|
||||
// TODO 如果关联的推流, 那么状态设置为离线
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -168,9 +198,9 @@ public class StreamProxyServiceImpl implements IStreamProxyService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSONObject getFFmpegCMDs() {
|
||||
public JSONObject getFFmpegCMDs(IMediaServerItem mediaServerItem) {
|
||||
JSONObject result = new JSONObject();
|
||||
JSONObject mediaServerConfigResuly = zlmresTfulUtils.getMediaServerConfig();
|
||||
JSONObject mediaServerConfigResuly = zlmresTfulUtils.getMediaServerConfig(mediaServerItem);
|
||||
if (mediaServerConfigResuly != null && mediaServerConfigResuly.getInteger("code") == 0
|
||||
&& mediaServerConfigResuly.getJSONArray("data").size() > 0){
|
||||
JSONObject mediaServerConfig = mediaServerConfigResuly.getJSONArray("data").getJSONObject(0);
|
||||
|
@ -5,9 +5,13 @@ import com.alibaba.fastjson.JSONObject;
|
||||
import com.alibaba.fastjson.TypeReference;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.GbStream;
|
||||
import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaItem;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem;
|
||||
import com.genersoft.iot.vmp.service.IMediaServerService;
|
||||
import com.genersoft.iot.vmp.service.IStreamPushService;
|
||||
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
|
||||
import com.genersoft.iot.vmp.storager.dao.GbStreamMapper;
|
||||
import com.genersoft.iot.vmp.storager.dao.StreamPushMapper;
|
||||
import com.github.pagehelper.PageHelper;
|
||||
@ -32,8 +36,14 @@ public class StreamPushServiceImpl implements IStreamPushService {
|
||||
@Autowired
|
||||
private ZLMRESTfulUtils zlmresTfulUtils;
|
||||
|
||||
@Autowired
|
||||
private IRedisCatchStorage redisCatchStorage;
|
||||
|
||||
@Autowired
|
||||
private IMediaServerService mediaServerService;
|
||||
|
||||
@Override
|
||||
public List<StreamPushItem> handleJSON(String jsonData) {
|
||||
public List<StreamPushItem> handleJSON(String jsonData, IMediaServerItem mediaServerItem) {
|
||||
if (jsonData == null) return null;
|
||||
|
||||
Map<String, StreamPushItem> result = new HashMap<>();
|
||||
@ -50,6 +60,7 @@ public class StreamPushServiceImpl implements IStreamPushService {
|
||||
if (streamPushItem == null) {
|
||||
streamPushItem = new StreamPushItem();
|
||||
streamPushItem.setApp(item.getApp());
|
||||
streamPushItem.setMediaServerId(mediaServerItem.getId());
|
||||
streamPushItem.setStream(item.getStream());
|
||||
streamPushItem.setAliveSecond(item.getAliveSecond());
|
||||
streamPushItem.setCreateStamp(item.getCreateStamp());
|
||||
@ -87,7 +98,8 @@ public class StreamPushServiceImpl implements IStreamPushService {
|
||||
@Override
|
||||
public boolean removeFromGB(GbStream stream) {
|
||||
int del = gbStreamMapper.del(stream.getApp(), stream.getStream());
|
||||
JSONObject mediaList = zlmresTfulUtils.getMediaList(stream.getApp(), stream.getStream());
|
||||
IMediaServerItem mediaInfo = mediaServerService.getOne(stream.getMediaServerId());
|
||||
JSONObject mediaList = zlmresTfulUtils.getMediaList(mediaInfo, stream.getApp(), stream.getStream());
|
||||
if (mediaList == null) {
|
||||
streamPushMapper.del(stream.getApp(), stream.getStream());
|
||||
}
|
||||
|
@ -2,10 +2,11 @@ package com.genersoft.iot.vmp.storager;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.genersoft.iot.vmp.common.StreamInfo;
|
||||
import com.genersoft.iot.vmp.media.zlm.ZLMServerConfig;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatformCatch;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@ -40,19 +41,6 @@ public interface IRedisCatchStorage {
|
||||
|
||||
StreamInfo queryPlayByDevice(String deviceId, String channelId);
|
||||
|
||||
/**
|
||||
* 更新流媒体信息
|
||||
* @param ZLMServerConfig
|
||||
* @return
|
||||
*/
|
||||
boolean updateMediaInfo(ZLMServerConfig ZLMServerConfig);
|
||||
|
||||
/**
|
||||
* 获取流媒体信息
|
||||
* @return
|
||||
*/
|
||||
ZLMServerConfig getMediaInfo();
|
||||
|
||||
Map<String, StreamInfo> queryPlayByDeviceId(String deviceId);
|
||||
|
||||
boolean startPlayback(StreamInfo stream);
|
||||
@ -114,6 +102,13 @@ public interface IRedisCatchStorage {
|
||||
*/
|
||||
void clearCatchByDeviceId(String deviceId);
|
||||
|
||||
/**
|
||||
* 获取mediaServer节点
|
||||
* @param mediaServerId
|
||||
* @return
|
||||
*/
|
||||
// MediaServerItem getMediaInfo(String mediaServerId);
|
||||
|
||||
/**
|
||||
* 设置所有设备离线
|
||||
*/
|
||||
|
@ -3,6 +3,8 @@ package com.genersoft.iot.vmp.storager;
|
||||
import java.util.List;
|
||||
|
||||
import com.genersoft.iot.vmp.gb28181.bean.*;
|
||||
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.StreamProxyItem;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem;
|
||||
import com.genersoft.iot.vmp.vmanager.gb28181.platform.bean.ChannelReduce;
|
||||
@ -365,4 +367,12 @@ public interface IVideoManagerStorager {
|
||||
* @param online
|
||||
*/
|
||||
void updateParentPlatformStatus(String platformGbID, boolean online);
|
||||
|
||||
/**
|
||||
* 更新媒体节点
|
||||
* @param mediaServerItem
|
||||
*/
|
||||
void updateMediaServer(MediaServerItem mediaServerItem);
|
||||
|
||||
List<StreamProxyItem> getStreamProxyListForEnableInMediaServer(String id, boolean b);
|
||||
}
|
||||
|
@ -12,9 +12,10 @@ import java.util.List;
|
||||
public interface GbStreamMapper {
|
||||
|
||||
@Insert("INSERT INTO gb_stream (app, stream, gbId, name, " +
|
||||
"longitude, latitude, streamType, status) VALUES" +
|
||||
"longitude, latitude, streamType, mediaServerId, status) VALUES" +
|
||||
"('${app}', '${stream}', '${gbId}', '${name}', " +
|
||||
"'${longitude}', '${latitude}', '${streamType}', ${status})")
|
||||
"'${longitude}', '${latitude}', '${streamType}', " +
|
||||
"'${mediaServerId}', ${status})")
|
||||
int add(GbStream gbStream);
|
||||
|
||||
@Update("UPDATE gb_stream " +
|
||||
@ -25,6 +26,7 @@ public interface GbStreamMapper {
|
||||
"streamType=#{streamType}," +
|
||||
"longitude=#{longitude}, " +
|
||||
"latitude=#{latitude}," +
|
||||
"mediaServerId=#{mediaServerId}," +
|
||||
"status=${status} " +
|
||||
"WHERE app=#{app} AND stream=#{stream} AND gbId=#{gbId}")
|
||||
int update(GbStream gbStream);
|
||||
@ -52,4 +54,7 @@ public interface GbStreamMapper {
|
||||
"SET status=${status} " +
|
||||
"WHERE app=#{app} AND stream=#{stream}")
|
||||
void setStatus(String app, String stream, boolean status);
|
||||
|
||||
@Select("SELECT gs.*, pgs.platformId FROM gb_stream gs LEFT JOIN platform_gb_stream pgs ON gs.app = pgs.app AND gs.stream = pgs.stream WHERE mediaServerId=#{mediaServerId} ")
|
||||
List<GbStream> selectAllByMediaServerId(String mediaServerId);
|
||||
}
|
||||
|
@ -0,0 +1,99 @@
|
||||
package com.genersoft.iot.vmp.storager.dao;
|
||||
|
||||
import com.genersoft.iot.vmp.conf.MediaConfig;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
||||
import org.apache.ibatis.annotations.Insert;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Select;
|
||||
import org.apache.ibatis.annotations.Update;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
@Mapper
|
||||
@Repository
|
||||
public interface MediaServerMapper {
|
||||
|
||||
@Insert("INSERT INTO media_server (" +
|
||||
"id, " +
|
||||
"ip, " +
|
||||
"hookIp, " +
|
||||
"sdpIp, " +
|
||||
"streamIp, " +
|
||||
"httpPort, " +
|
||||
"httpSSlPort, " +
|
||||
"rtmpPort, " +
|
||||
"rtmpSSlPort, " +
|
||||
"rtpProxyPort, " +
|
||||
"rtspPort, " +
|
||||
"rtspSSLPort, " +
|
||||
"autoConfig, " +
|
||||
"secret, " +
|
||||
"streamNoneReaderDelayMS, " +
|
||||
"rtpEnable, " +
|
||||
"rtpPortRange, " +
|
||||
"recordAssistPort, " +
|
||||
"createTime, " +
|
||||
"updateTime" +
|
||||
") VALUES " +
|
||||
"(" +
|
||||
"'${id}', " +
|
||||
"'${ip}', " +
|
||||
"'${hookIp}', " +
|
||||
"'${sdpIp}', " +
|
||||
"'${streamIp}', " +
|
||||
"${httpPort}, " +
|
||||
"${httpSSlPort}, " +
|
||||
"${rtmpPort}, " +
|
||||
"${rtmpSSlPort}, " +
|
||||
"${rtpProxyPort}, " +
|
||||
"${rtspPort}, " +
|
||||
"${rtspSSLPort}, " +
|
||||
"${autoConfig}, " +
|
||||
"'${secret}', " +
|
||||
"${streamNoneReaderDelayMS}, " +
|
||||
"${rtpEnable}, " +
|
||||
"'${rtpPortRange}', " +
|
||||
"${recordAssistPort}, " +
|
||||
"'${createTime}', " +
|
||||
"'${updateTime}')")
|
||||
int add(IMediaServerItem mediaServerItem);
|
||||
|
||||
@Update(value = {" <script>" +
|
||||
"UPDATE media_server " +
|
||||
"SET updateTime='${updateTime}'" +
|
||||
"<if test=\"ip != null\">, ip='${ip}'</if>" +
|
||||
"<if test=\"hookIp != null\">, hookIp='${hookIp}'</if>" +
|
||||
"<if test=\"sdpIp != null\">, sdpIp='${sdpIp}'</if>" +
|
||||
"<if test=\"streamIp != null\">, streamIp='${streamIp}'</if>" +
|
||||
"<if test=\"httpPort != null\">, httpPort=${httpPort}</if>" +
|
||||
"<if test=\"httpSSlPort != null\">, httpSSlPort=${httpSSlPort}</if>" +
|
||||
"<if test=\"rtmpPort != null\">, rtmpPort=${rtmpPort}</if>" +
|
||||
"<if test=\"rtmpSSlPort != null\">, rtmpSSlPort=${rtmpSSlPort}</if>" +
|
||||
"<if test=\"rtpProxyPort != null\">, rtpProxyPort=${rtpProxyPort}</if>" +
|
||||
"<if test=\"rtspPort != null\">, rtspPort=${rtspPort}</if>" +
|
||||
"<if test=\"rtspSSLPort != null\">, rtspSSLPort=${rtspSSLPort}</if>" +
|
||||
"<if test=\"autoConfig != null\">, autoConfig=${autoConfig}</if>" +
|
||||
"<if test=\"streamNoneReaderDelayMS != null\">, streamNoneReaderDelayMS=${streamNoneReaderDelayMS}</if>" +
|
||||
"<if test=\"rtpEnable != null\">, rtpEnable=${rtpEnable}</if>" +
|
||||
"<if test=\"rtpPortRange != null\">, rtpPortRange='${rtpPortRange}'</if>" +
|
||||
"<if test=\"secret != null\">, secret='${secret}'</if>" +
|
||||
"<if test=\"recordAssistPort != null\">, recordAssistPort=${recordAssistPort}</if>" +
|
||||
"WHERE id='${id}'"+
|
||||
" </script>"})
|
||||
int update(IMediaServerItem mediaServerItem);
|
||||
|
||||
@Select("SELECT * FROM media_server WHERE id='${id}'")
|
||||
MediaServerItem queryOne(String id);
|
||||
|
||||
@Select("SELECT * FROM media_server")
|
||||
List<MediaServerItem> queryAll();
|
||||
|
||||
@Select("DELETE FROM media_server WHERE id='${id}'")
|
||||
int delOne(String secret);
|
||||
|
||||
@Select("SELECT * FROM media_server WHERE ip='${host}' and httpPort=${port}")
|
||||
MediaServerItem queryOneByHostAndPort(String host, int port);
|
||||
}
|
@ -10,10 +10,10 @@ import java.util.List;
|
||||
@Repository
|
||||
public interface StreamProxyMapper {
|
||||
|
||||
@Insert("INSERT INTO stream_proxy (type, app, stream, url, src_url, dst_url, " +
|
||||
"timeout_ms, ffmpeg_cmd_key, rtp_type, enable_hls, enable_mp4, enable) VALUES" +
|
||||
"('${type}','${app}', '${stream}', '${url}', '${src_url}', '${dst_url}', " +
|
||||
"'${timeout_ms}', '${ffmpeg_cmd_key}', '${rtp_type}', ${enable_hls}, ${enable_mp4}, ${enable} )")
|
||||
@Insert("INSERT INTO stream_proxy (type, app, stream,mediaServerId, url, src_url, dst_url, " +
|
||||
"timeout_ms, ffmpeg_cmd_key, rtp_type, enable_hls, enable_mp4, enable, createTime) VALUES" +
|
||||
"('${type}','${app}', '${stream}', '${mediaServerId}','${url}', '${src_url}', '${dst_url}', " +
|
||||
"'${timeout_ms}', '${ffmpeg_cmd_key}', '${rtp_type}', ${enable_hls}, ${enable_mp4}, ${enable}, '${createTime}' )")
|
||||
int add(StreamProxyItem streamProxyDto);
|
||||
|
||||
@Update("UPDATE stream_proxy " +
|
||||
@ -21,6 +21,7 @@ public interface StreamProxyMapper {
|
||||
"app=#{app}," +
|
||||
"stream=#{stream}," +
|
||||
"url=#{url}, " +
|
||||
"mediaServerId=#{mediaServerId}, " +
|
||||
"src_url=#{src_url}," +
|
||||
"dst_url=#{dst_url}, " +
|
||||
"timeout_ms=#{timeout_ms}, " +
|
||||
@ -35,12 +36,17 @@ public interface StreamProxyMapper {
|
||||
@Delete("DELETE FROM stream_proxy WHERE app=#{app} AND stream=#{stream}")
|
||||
int del(String app, String stream);
|
||||
|
||||
@Select("SELECT st.*, pgs.gbId, pgs.name, pgs.longitude, pgs.latitude FROM stream_proxy st LEFT JOIN gb_stream pgs on st.app = pgs.app AND st.stream = pgs.stream")
|
||||
@Select("SELECT st.*, pgs.gbId, pgs.name, pgs.longitude, pgs.latitude FROM stream_proxy st LEFT JOIN gb_stream pgs on st.app = pgs.app AND st.stream = pgs.stream order by st.createTime desc")
|
||||
List<StreamProxyItem> selectAll();
|
||||
|
||||
@Select("SELECT st.*, pgs.gbId, pgs.name, pgs.longitude, pgs.latitude FROM stream_proxy st LEFT JOIN gb_stream pgs on st.app = pgs.app AND st.stream = pgs.stream WHERE st.enable=${enable}")
|
||||
@Select("SELECT st.*, pgs.gbId, pgs.name, pgs.longitude, pgs.latitude FROM stream_proxy st LEFT JOIN gb_stream pgs on st.app = pgs.app AND st.stream = pgs.stream WHERE st.enable=${enable} order by st.createTime desc")
|
||||
List<StreamProxyItem> selectForEnable(boolean enable);
|
||||
|
||||
@Select("SELECT st.*, pgs.gbId, pgs.name, pgs.longitude, pgs.latitude FROM stream_proxy st LEFT JOIN gb_stream pgs on st.app = pgs.app AND st.stream = pgs.stream WHERE st.app=#{app} AND st.stream=#{stream}")
|
||||
@Select("SELECT st.*, pgs.gbId, pgs.name, pgs.longitude, pgs.latitude FROM stream_proxy st LEFT JOIN gb_stream pgs on st.app = pgs.app AND st.stream = pgs.stream WHERE st.app=#{app} AND st.stream=#{stream} order by st.createTime desc")
|
||||
StreamProxyItem selectOne(String app, String stream);
|
||||
|
||||
@Select("SELECT st.*, pgs.gbId, pgs.name, pgs.longitude, pgs.latitude FROM stream_proxy st " +
|
||||
"LEFT JOIN gb_stream pgs on st.app = pgs.app AND st.stream = pgs.stream " +
|
||||
"WHERE st.enable=${enable} and st.mediaServerId = '${id}' order by st.createTime desc")
|
||||
List<StreamProxyItem> selectForEnableInMediaServer(String id, boolean enable);
|
||||
}
|
||||
|
@ -11,14 +11,15 @@ import java.util.List;
|
||||
public interface StreamPushMapper {
|
||||
|
||||
@Insert("INSERT INTO stream_push (app, stream, totalReaderCount, originType, originTypeStr, " +
|
||||
"createStamp, aliveSecond) VALUES" +
|
||||
"createStamp, aliveSecond, mediaServerId) VALUES" +
|
||||
"('${app}', '${stream}', '${totalReaderCount}', '${originType}', '${originTypeStr}', " +
|
||||
"'${createStamp}', '${aliveSecond}' )")
|
||||
"'${createStamp}', '${aliveSecond}', '${mediaServerId}' )")
|
||||
int add(StreamPushItem streamPushItem);
|
||||
|
||||
@Update("UPDATE stream_push " +
|
||||
"SET app=#{app}," +
|
||||
"stream=#{stream}," +
|
||||
"mediaServerId=#{mediaServerId}," +
|
||||
"totalReaderCount=#{totalReaderCount}, " +
|
||||
"originType=#{originType}," +
|
||||
"originTypeStr=#{originTypeStr}, " +
|
||||
@ -41,10 +42,10 @@ public interface StreamPushMapper {
|
||||
|
||||
@Insert("<script>" +
|
||||
"INSERT INTO stream_push (app, stream, totalReaderCount, originType, originTypeStr, " +
|
||||
"createStamp, aliveSecond) " +
|
||||
"createStamp, aliveSecond, mediaServerId) " +
|
||||
"VALUES <foreach collection='streamPushItems' item='item' index='index' >" +
|
||||
"( '${item.app}', '${item.stream}', '${item.totalReaderCount}', '${item.originType}', " +
|
||||
"'${item.originTypeStr}','${item.createStamp}', '${item.aliveSecond}' )" +
|
||||
"'${item.originTypeStr}','${item.createStamp}', '${item.aliveSecond}', '${item.mediaServerId}' )" +
|
||||
" </foreach>" +
|
||||
"</script>")
|
||||
void addAll(List<StreamPushItem> streamPushItems);
|
||||
|
@ -5,6 +5,8 @@ import com.genersoft.iot.vmp.common.StreamInfo;
|
||||
import com.genersoft.iot.vmp.common.VideoManagerConstants;
|
||||
import com.genersoft.iot.vmp.media.zlm.ZLMServerConfig;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.*;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
||||
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
|
||||
import com.genersoft.iot.vmp.storager.dao.DeviceChannelMapper;
|
||||
import com.genersoft.iot.vmp.utils.redis.RedisUtil;
|
||||
@ -87,26 +89,6 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage {
|
||||
return (StreamInfo)redis.get(playLeys.get(0).toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新流媒体信息
|
||||
* @param ZLMServerConfig
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public boolean updateMediaInfo(ZLMServerConfig ZLMServerConfig) {
|
||||
ZLMServerConfig.setUpdateTime(format.format(new Date(System.currentTimeMillis())));
|
||||
return redis.set(VideoManagerConstants.MEDIA_SERVER_PREFIX, ZLMServerConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取流媒体信息
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public ZLMServerConfig getMediaInfo() {
|
||||
return (ZLMServerConfig)redis.get(VideoManagerConstants.MEDIA_SERVER_PREFIX);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, StreamInfo> queryPlayByDeviceId(String deviceId) {
|
||||
Map<String, StreamInfo> streamInfos = new HashMap<>();
|
||||
@ -297,7 +279,7 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage {
|
||||
|
||||
@Override
|
||||
public void outlineForAll() {
|
||||
List<Object> onlineDevices = redis.scan(String.format("%S*", VideoManagerConstants.KEEPLIVEKEY_PREFIX));
|
||||
List<Object> onlineDevices = redis.scan(VideoManagerConstants.KEEPLIVEKEY_PREFIX + "*" );
|
||||
for (int i = 0; i < onlineDevices.size(); i++) {
|
||||
String key = (String) onlineDevices.get(i);
|
||||
redis.del(key);
|
||||
@ -308,4 +290,5 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage {
|
||||
public void updateWVPInfo(JSONObject jsonObject) {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ import java.util.*;
|
||||
|
||||
import com.genersoft.iot.vmp.gb28181.bean.*;
|
||||
import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem;
|
||||
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
|
||||
@ -70,6 +71,9 @@ public class VideoManagerStoragerImpl implements IVideoManagerStorager {
|
||||
@Autowired
|
||||
private VideoStreamSessionManager streamSession;
|
||||
|
||||
@Autowired
|
||||
private MediaServerMapper mediaServerMapper;
|
||||
|
||||
private SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
|
||||
|
||||
@ -459,6 +463,8 @@ public class VideoManagerStoragerImpl implements IVideoManagerStorager {
|
||||
boolean result = false;
|
||||
streamProxyItem.setStreamType("proxy");
|
||||
streamProxyItem.setStatus(true);
|
||||
String now = this.format.format(new Date(System.currentTimeMillis()));
|
||||
streamProxyItem.setCreateTime(now);
|
||||
try {
|
||||
if (gbStreamMapper.add(streamProxyItem)<0 || streamProxyMapper.add(streamProxyItem) < 0) {
|
||||
//事务回滚
|
||||
@ -467,6 +473,7 @@ public class VideoManagerStoragerImpl implements IVideoManagerStorager {
|
||||
result = true;
|
||||
dataSourceTransactionManager.commit(transactionStatus); //手动提交
|
||||
}catch (Exception e) {
|
||||
logger.error("向数据库添加流代理失败:", e);
|
||||
dataSourceTransactionManager.rollback(transactionStatus);
|
||||
}
|
||||
return result;
|
||||
@ -599,4 +606,21 @@ public class VideoManagerStoragerImpl implements IVideoManagerStorager {
|
||||
public void updateParentPlatformStatus(String platformGbID, boolean online) {
|
||||
platformMapper.updateParentPlatformStatus(platformGbID, online);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateMediaServer(MediaServerItem mediaServerItem) {
|
||||
String now = this.format.format(new Date(System.currentTimeMillis()));
|
||||
mediaServerItem.setUpdateTime(now);
|
||||
if (mediaServerMapper.queryOne(mediaServerItem.getId()) != null) {
|
||||
mediaServerMapper.update(mediaServerItem);
|
||||
}else {
|
||||
mediaServerItem.setCreateTime(now);
|
||||
mediaServerMapper.add(mediaServerItem);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<StreamProxyItem> getStreamProxyListForEnableInMediaServer(String id, boolean enable) {
|
||||
return streamProxyMapper.selectForEnableInMediaServer(id, enable);
|
||||
}
|
||||
}
|
||||
|
@ -25,6 +25,7 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.context.request.async.DeferredResult;
|
||||
|
||||
@ -78,7 +79,7 @@ public class DeviceConfig {
|
||||
cmder.deviceBasicConfigCmd(device, channelId, name, expiration, heartBeatInterval, heartBeatCount, event -> {
|
||||
Response response = event.getResponse();
|
||||
RequestMessage msg = new RequestMessage();
|
||||
msg.setId(DeferredResultHolder.CALLBACK_CMD_DEVICECONFIG + (XmlUtil.isEmpty(channelId) ? deviceId : channelId));
|
||||
msg.setId(DeferredResultHolder.CALLBACK_CMD_DEVICECONFIG + (StringUtils.isEmpty(channelId) ? deviceId : channelId));
|
||||
msg.setData(String.format("设备配置操作失败,错误码: %s, %s", response.getStatusCode(), response.getReasonPhrase()));
|
||||
resultHolder.invokeResult(msg);
|
||||
});
|
||||
@ -87,7 +88,7 @@ public class DeviceConfig {
|
||||
logger.warn(String.format("设备配置操作超时, 设备未返回应答指令"));
|
||||
// 释放rtpserver
|
||||
RequestMessage msg = new RequestMessage();
|
||||
msg.setId(DeferredResultHolder.CALLBACK_CMD_DEVICECONFIG + (XmlUtil.isEmpty(channelId) ? deviceId : channelId));
|
||||
msg.setId(DeferredResultHolder.CALLBACK_CMD_DEVICECONFIG + (StringUtils.isEmpty(channelId) ? deviceId : channelId));
|
||||
JSONObject json = new JSONObject();
|
||||
json.put("DeviceID", deviceId);
|
||||
json.put("Status", "Timeout");
|
||||
@ -95,7 +96,7 @@ public class DeviceConfig {
|
||||
msg.setData(json); //("看守位控制操作超时, 设备未返回应答指令");
|
||||
resultHolder.invokeResult(msg);
|
||||
});
|
||||
resultHolder.put(DeferredResultHolder.CALLBACK_CMD_DEVICECONFIG + (XmlUtil.isEmpty(channelId) ? deviceId : channelId), result);
|
||||
resultHolder.put(DeferredResultHolder.CALLBACK_CMD_DEVICECONFIG + (StringUtils.isEmpty(channelId) ? deviceId : channelId), result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -123,7 +124,7 @@ public class DeviceConfig {
|
||||
cmder.deviceConfigQuery(device, channelId, configType, event -> {
|
||||
Response response = event.getResponse();
|
||||
RequestMessage msg = new RequestMessage();
|
||||
msg.setId(DeferredResultHolder.CALLBACK_CMD_CONFIGDOWNLOAD + (XmlUtil.isEmpty(channelId) ? deviceId : channelId));
|
||||
msg.setId(DeferredResultHolder.CALLBACK_CMD_CONFIGDOWNLOAD + (StringUtils.isEmpty(channelId) ? deviceId : channelId));
|
||||
msg.setData(String.format("获取设备配置失败,错误码: %s, %s", response.getStatusCode(), response.getReasonPhrase()));
|
||||
resultHolder.invokeResult(msg);
|
||||
});
|
||||
@ -132,11 +133,11 @@ public class DeviceConfig {
|
||||
logger.warn(String.format("获取设备配置超时"));
|
||||
// 释放rtpserver
|
||||
RequestMessage msg = new RequestMessage();
|
||||
msg.setId(DeferredResultHolder.CALLBACK_CMD_CONFIGDOWNLOAD + (XmlUtil.isEmpty(channelId) ? deviceId : channelId));
|
||||
msg.setId(DeferredResultHolder.CALLBACK_CMD_CONFIGDOWNLOAD + (StringUtils.isEmpty(channelId) ? deviceId : channelId));
|
||||
msg.setData("Timeout. Device did not response to this command.");
|
||||
resultHolder.invokeResult(msg);
|
||||
});
|
||||
resultHolder.put(DeferredResultHolder.CALLBACK_CMD_CONFIGDOWNLOAD + (XmlUtil.isEmpty(channelId) ? deviceId : channelId), result);
|
||||
resultHolder.put(DeferredResultHolder.CALLBACK_CMD_CONFIGDOWNLOAD + (StringUtils.isEmpty(channelId) ? deviceId : channelId), result);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -26,6 +26,7 @@ import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.context.request.async.DeferredResult;
|
||||
|
||||
@ -97,7 +98,7 @@ public class DeviceControl {
|
||||
cmder.recordCmd(device, channelId, recordCmdStr, event -> {
|
||||
Response response = event.getResponse();
|
||||
RequestMessage msg = new RequestMessage();
|
||||
msg.setId(DeferredResultHolder.CALLBACK_CMD_DEVICECONTROL + (XmlUtil.isEmpty(channelId) ? deviceId : channelId));
|
||||
msg.setId(DeferredResultHolder.CALLBACK_CMD_DEVICECONTROL + (StringUtils.isEmpty(channelId) ? deviceId : channelId));
|
||||
msg.setData(String.format("开始/停止录像操作失败,错误码: %s, %s", response.getStatusCode(), response.getReasonPhrase()));
|
||||
resultHolder.invokeResult(msg);
|
||||
});
|
||||
@ -106,11 +107,11 @@ public class DeviceControl {
|
||||
logger.warn(String.format("开始/停止录像操作超时, 设备未返回应答指令"));
|
||||
// 释放rtpserver
|
||||
RequestMessage msg = new RequestMessage();
|
||||
msg.setId(DeferredResultHolder.CALLBACK_CMD_DEVICECONTROL + (XmlUtil.isEmpty(channelId) ? deviceId : channelId));
|
||||
msg.setId(DeferredResultHolder.CALLBACK_CMD_DEVICECONTROL + (StringUtils.isEmpty(channelId) ? deviceId : channelId));
|
||||
msg.setData("Timeout. Device did not response to this command.");
|
||||
resultHolder.invokeResult(msg);
|
||||
});
|
||||
resultHolder.put(DeferredResultHolder.CALLBACK_CMD_DEVICECONTROL + (XmlUtil.isEmpty(channelId) ? deviceId : channelId), result);
|
||||
resultHolder.put(DeferredResultHolder.CALLBACK_CMD_DEVICECONTROL + (StringUtils.isEmpty(channelId) ? deviceId : channelId), result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -254,7 +255,7 @@ public class DeviceControl {
|
||||
cmder.homePositionCmd(device, channelId, enabled, resetTime, presetIndex, event -> {
|
||||
Response response = event.getResponse();
|
||||
RequestMessage msg = new RequestMessage();
|
||||
msg.setId(DeferredResultHolder.CALLBACK_CMD_DEVICECONTROL + (XmlUtil.isEmpty(channelId) ? deviceId : channelId));
|
||||
msg.setId(DeferredResultHolder.CALLBACK_CMD_DEVICECONTROL + (StringUtils.isEmpty(channelId) ? deviceId : channelId));
|
||||
msg.setData(String.format("看守位控制操作失败,错误码: %s, %s", response.getStatusCode(), response.getReasonPhrase()));
|
||||
resultHolder.invokeResult(msg);
|
||||
});
|
||||
@ -263,7 +264,7 @@ public class DeviceControl {
|
||||
logger.warn(String.format("看守位控制操作超时, 设备未返回应答指令"));
|
||||
// 释放rtpserver
|
||||
RequestMessage msg = new RequestMessage();
|
||||
msg.setId(DeferredResultHolder.CALLBACK_CMD_DEVICECONTROL + (XmlUtil.isEmpty(channelId) ? deviceId : channelId));
|
||||
msg.setId(DeferredResultHolder.CALLBACK_CMD_DEVICECONTROL + (StringUtils.isEmpty(channelId) ? deviceId : channelId));
|
||||
JSONObject json = new JSONObject();
|
||||
json.put("DeviceID", deviceId);
|
||||
json.put("Status", "Timeout");
|
||||
@ -271,7 +272,7 @@ public class DeviceControl {
|
||||
msg.setData(json); //("看守位控制操作超时, 设备未返回应答指令");
|
||||
resultHolder.invokeResult(msg);
|
||||
});
|
||||
resultHolder.put(DeferredResultHolder.CALLBACK_CMD_DEVICECONTROL + (XmlUtil.isEmpty(channelId) ? deviceId : channelId), result);
|
||||
resultHolder.put(DeferredResultHolder.CALLBACK_CMD_DEVICECONTROL + (StringUtils.isEmpty(channelId) ? deviceId : channelId), result);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
@ -43,11 +43,13 @@ public class MediaController {
|
||||
@ApiImplicitParams({
|
||||
@ApiImplicitParam(name = "app", value = "应用名", dataTypeClass = String.class),
|
||||
@ApiImplicitParam(name = "stream", value = "流id", dataTypeClass = String.class),
|
||||
@ApiImplicitParam(name = "mediaServerId", value = "媒体服务器id", dataTypeClass = String.class),
|
||||
})
|
||||
@GetMapping(value = "/stream_info_by_app_and_stream")
|
||||
@ResponseBody
|
||||
public StreamInfo getStreamInfoByAppAndStream(String app, String stream){
|
||||
return mediaService.getStreamInfoByAppAndStreamWithCheck(app, stream);
|
||||
public StreamInfo getStreamInfoByAppAndStream(@RequestParam String app, @RequestParam String stream, @RequestParam String mediaServerId){
|
||||
|
||||
return mediaService.getStreamInfoByAppAndStreamWithCheck(app, stream,mediaServerId);
|
||||
}
|
||||
|
||||
|
||||
|
@ -8,6 +8,9 @@ import com.genersoft.iot.vmp.gb28181.bean.Device;
|
||||
import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
|
||||
import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
|
||||
import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
||||
import com.genersoft.iot.vmp.service.IMediaServerService;
|
||||
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
|
||||
import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
|
||||
import com.genersoft.iot.vmp.vmanager.gb28181.play.bean.PlayResult;
|
||||
@ -72,6 +75,9 @@ public class PlayController {
|
||||
@Autowired
|
||||
private IMediaService mediaService;
|
||||
|
||||
@Autowired
|
||||
private IMediaServerService mediaServerService;
|
||||
|
||||
@ApiOperation("开始点播")
|
||||
@ApiImplicitParams({
|
||||
@ApiImplicitParam(name = "deviceId", value = "设备ID", dataTypeClass = String.class),
|
||||
@ -81,8 +87,10 @@ public class PlayController {
|
||||
public DeferredResult<ResponseEntity<String>> play(@PathVariable String deviceId,
|
||||
@PathVariable String channelId) {
|
||||
|
||||
PlayResult playResult = playService.play(deviceId, channelId, null, null);
|
||||
|
||||
// 获取可用的zlm
|
||||
Device device = storager.queryVideoDevice(deviceId);
|
||||
IMediaServerItem newMediaServerItem = playService.getNewMediaServerItem(device);
|
||||
PlayResult playResult = playService.play(newMediaServerItem, deviceId, channelId, null, null);
|
||||
|
||||
return playResult.getResult();
|
||||
}
|
||||
@ -102,8 +110,8 @@ public class PlayController {
|
||||
|
||||
// 录像查询以channelId作为deviceId查询
|
||||
resultHolder.put(DeferredResultHolder.CALLBACK_CMD_STOP + uuid, result);
|
||||
|
||||
cmder.streamByeCmd(deviceId, channelId, event -> {
|
||||
Device device = storager.queryVideoDevice(deviceId);
|
||||
cmder.streamByeCmd(deviceId, channelId, (event) -> {
|
||||
StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(deviceId, channelId);
|
||||
if (streamInfo == null) {
|
||||
RequestMessage msg = new RequestMessage();
|
||||
@ -120,6 +128,7 @@ public class PlayController {
|
||||
msg.setData(String.format("success"));
|
||||
resultHolder.invokeResult(msg);
|
||||
}
|
||||
mediaServerService.closeRTPServer(device, channelId);
|
||||
});
|
||||
|
||||
if (deviceId != null || channelId != null) {
|
||||
@ -165,16 +174,16 @@ public class PlayController {
|
||||
logger.warn("视频转码API调用失败!, 视频流已经停止!");
|
||||
return new ResponseEntity<String>("未找到视频流信息, 视频流可能已经停止", HttpStatus.OK);
|
||||
}
|
||||
JSONObject rtpInfo = zlmresTfulUtils.getRtpInfo(streamId);
|
||||
IMediaServerItem mediaInfo = mediaServerService.getOne(streamInfo.getMediaServerId());
|
||||
JSONObject rtpInfo = zlmresTfulUtils.getRtpInfo(mediaInfo, streamId);
|
||||
if (!rtpInfo.getBoolean("exist")) {
|
||||
logger.warn("视频转码API调用失败!, 视频流已停止推流!");
|
||||
return new ResponseEntity<String>("推流信息在流媒体中不存在, 视频流可能已停止推流", HttpStatus.OK);
|
||||
} else {
|
||||
ZLMServerConfig mediaInfo = redisCatchStorage.getMediaInfo();
|
||||
String dstUrl = String.format("rtmp://%s:%s/convert/%s", "127.0.0.1", mediaInfo.getRtmpPort(),
|
||||
streamId );
|
||||
String srcUrl = String.format("rtsp://%s:%s/rtp/%s", "127.0.0.1", mediaInfo.getRtspPort(), streamId);
|
||||
JSONObject jsonObject = zlmresTfulUtils.addFFmpegSource(srcUrl, dstUrl, "1000000", true, false, null);
|
||||
JSONObject jsonObject = zlmresTfulUtils.addFFmpegSource(mediaInfo, srcUrl, dstUrl, "1000000", true, false, null);
|
||||
logger.info(jsonObject.toJSONString());
|
||||
JSONObject result = new JSONObject();
|
||||
if (jsonObject != null && jsonObject.getInteger("code") == 0) {
|
||||
@ -182,7 +191,7 @@ public class PlayController {
|
||||
JSONObject data = jsonObject.getJSONObject("data");
|
||||
if (data != null) {
|
||||
result.put("key", data.getString("key"));
|
||||
StreamInfo streamInfoResult = mediaService.getStreamInfoByAppAndStreamWithCheck("convert", streamId);
|
||||
StreamInfo streamInfoResult = mediaService.getStreamInfoByAppAndStreamWithCheck("convert", streamId, mediaInfo.getId());
|
||||
result.put("data", streamInfoResult);
|
||||
}
|
||||
}else {
|
||||
@ -203,25 +212,38 @@ public class PlayController {
|
||||
@ApiImplicitParam(name = "key", value = "视频流key", dataTypeClass = String.class),
|
||||
})
|
||||
@PostMapping("/convertStop/{key}")
|
||||
public ResponseEntity<String> playConvertStop(@PathVariable String key) {
|
||||
|
||||
JSONObject jsonObject = zlmresTfulUtils.delFFmpegSource(key);
|
||||
logger.info(jsonObject.toJSONString());
|
||||
public ResponseEntity<String> playConvertStop(@PathVariable String key, String mediaServerId) {
|
||||
JSONObject result = new JSONObject();
|
||||
if (jsonObject != null && jsonObject.getInteger("code") == 0) {
|
||||
result.put("code", 0);
|
||||
JSONObject data = jsonObject.getJSONObject("data");
|
||||
if (data != null && data.getBoolean("flag")) {
|
||||
result.put("code", "0");
|
||||
result.put("msg", "success");
|
||||
}else {
|
||||
|
||||
}
|
||||
}else {
|
||||
result.put("code", 1);
|
||||
result.put("msg", "delFFmpegSource fail");
|
||||
if (mediaServerId == null) {
|
||||
result.put("code", 400);
|
||||
result.put("msg", "mediaServerId is null");
|
||||
return new ResponseEntity<String>( result.toJSONString(), HttpStatus.BAD_REQUEST);
|
||||
}
|
||||
return new ResponseEntity<String>( result.toJSONString(), HttpStatus.OK);
|
||||
IMediaServerItem mediaInfo = mediaServerService.getOne(mediaServerId);
|
||||
if (mediaInfo == null) {
|
||||
result.put("code", 0);
|
||||
result.put("msg", "使用的流媒体已经停止运行");
|
||||
return new ResponseEntity<String>( result.toJSONString(), HttpStatus.OK);
|
||||
}else {
|
||||
JSONObject jsonObject = zlmresTfulUtils.delFFmpegSource(mediaInfo, key);
|
||||
logger.info(jsonObject.toJSONString());
|
||||
if (jsonObject != null && jsonObject.getInteger("code") == 0) {
|
||||
result.put("code", 0);
|
||||
JSONObject data = jsonObject.getJSONObject("data");
|
||||
if (data != null && data.getBoolean("flag")) {
|
||||
result.put("code", "0");
|
||||
result.put("msg", "success");
|
||||
}else {
|
||||
|
||||
}
|
||||
}else {
|
||||
result.put("code", 1);
|
||||
result.put("msg", "delFFmpegSource fail");
|
||||
}
|
||||
return new ResponseEntity<String>( result.toJSONString(), HttpStatus.OK);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ApiOperation("语音广播命令")
|
||||
@ -249,7 +271,7 @@ public class PlayController {
|
||||
resultHolder.invokeResult(msg);
|
||||
return result;
|
||||
}
|
||||
cmder.audioBroadcastCmd(device, event -> {
|
||||
cmder.audioBroadcastCmd(device, (event) -> {
|
||||
Response response = event.getResponse();
|
||||
RequestMessage msg = new RequestMessage();
|
||||
msg.setId(DeferredResultHolder.CALLBACK_CMD_BROADCAST + deviceId);
|
||||
|
@ -4,6 +4,8 @@ import com.genersoft.iot.vmp.common.StreamInfo;
|
||||
import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
|
||||
import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
|
||||
//import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
||||
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
|
||||
import com.genersoft.iot.vmp.service.IPlayService;
|
||||
import io.swagger.annotations.Api;
|
||||
@ -87,9 +89,18 @@ public class PlaybackController {
|
||||
cmder.streamByeCmd(deviceId, channelId);
|
||||
}
|
||||
resultHolder.put(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid, result);
|
||||
cmder.playbackStreamCmd(device, channelId, startTime, endTime, (JSONObject response) -> {
|
||||
IMediaServerItem newMediaServerItem = playService.getNewMediaServerItem(device);
|
||||
if (newMediaServerItem == null) {
|
||||
logger.warn(String.format("设备回放超时,deviceId:%s ,channelId:%s", deviceId, channelId));
|
||||
RequestMessage msg = new RequestMessage();
|
||||
msg.setId(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid);
|
||||
msg.setData("Timeout");
|
||||
resultHolder.invokeResult(msg);
|
||||
return result;
|
||||
}
|
||||
cmder.playbackStreamCmd(newMediaServerItem, device, channelId, startTime, endTime, (IMediaServerItem mediaServerItem, JSONObject response) -> {
|
||||
logger.info("收到订阅消息: " + response.toJSONString());
|
||||
playService.onPublishHandlerForPlayBack(response, deviceId, channelId, uuid.toString());
|
||||
playService.onPublishHandlerForPlayBack(mediaServerItem, response, deviceId, channelId, uuid.toString());
|
||||
}, event -> {
|
||||
Response response = event.getResponse();
|
||||
RequestMessage msg = new RequestMessage();
|
||||
|
@ -9,6 +9,7 @@ import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.context.request.async.DeferredResult;
|
||||
|
||||
@ -104,7 +105,7 @@ public class PtzController {
|
||||
cmder.presetQuery(device, channelId, event -> {
|
||||
Response response = event.getResponse();
|
||||
RequestMessage msg = new RequestMessage();
|
||||
msg.setId(DeferredResultHolder.CALLBACK_CMD_PRESETQUERY + (XmlUtil.isEmpty(channelId) ? deviceId : channelId));
|
||||
msg.setId(DeferredResultHolder.CALLBACK_CMD_PRESETQUERY + (StringUtils.isEmpty(channelId) ? deviceId : channelId));
|
||||
msg.setData(String.format("获取设备预置位失败,错误码: %s, %s", response.getStatusCode(), response.getReasonPhrase()));
|
||||
resultHolder.invokeResult(msg);
|
||||
});
|
||||
@ -113,11 +114,11 @@ public class PtzController {
|
||||
logger.warn(String.format("获取设备预置位超时"));
|
||||
// 释放rtpserver
|
||||
RequestMessage msg = new RequestMessage();
|
||||
msg.setId(DeferredResultHolder.CALLBACK_CMD_PRESETQUERY + (XmlUtil.isEmpty(channelId) ? deviceId : channelId));
|
||||
msg.setId(DeferredResultHolder.CALLBACK_CMD_PRESETQUERY + (StringUtils.isEmpty(channelId) ? deviceId : channelId));
|
||||
msg.setData("获取设备预置位超时");
|
||||
resultHolder.invokeResult(msg);
|
||||
});
|
||||
resultHolder.put(DeferredResultHolder.CALLBACK_CMD_PRESETQUERY + (XmlUtil.isEmpty(channelId) ? deviceId : channelId), result);
|
||||
resultHolder.put(DeferredResultHolder.CALLBACK_CMD_PRESETQUERY + (StringUtils.isEmpty(channelId) ? deviceId : channelId), result);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,9 @@ package com.genersoft.iot.vmp.vmanager.record;
|
||||
|
||||
import com.genersoft.iot.vmp.conf.MediaConfig;
|
||||
import com.genersoft.iot.vmp.media.zlm.ZLMServerConfig;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
||||
import com.genersoft.iot.vmp.service.IMediaServerService;
|
||||
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpStatus;
|
||||
@ -27,6 +30,8 @@ public class RecoderProxyController {
|
||||
|
||||
@Autowired
|
||||
private IRedisCatchStorage redisCatchStorage;
|
||||
@Autowired
|
||||
private IMediaServerService mediaServerService;
|
||||
|
||||
@Autowired
|
||||
private MediaConfig mediaConfig;
|
||||
@ -48,7 +53,11 @@ public class RecoderProxyController {
|
||||
return null;
|
||||
}
|
||||
// 后续改为根据Id获取对应的ZLM
|
||||
ZLMServerConfig mediaInfo = redisCatchStorage.getMediaInfo();
|
||||
IMediaServerItem mediaInfo = mediaServerService.getOne(mediaId);
|
||||
if (mediaInfo == null) {
|
||||
response.setStatus(HttpStatus.NOT_FOUND.value());
|
||||
return null;
|
||||
}
|
||||
String requestURI = String.format("http://%s:%s%s?%s",
|
||||
mediaInfo.getSdpIp(),
|
||||
mediaConfig.getRecordAssistPort(),
|
||||
|
@ -2,8 +2,11 @@ package com.genersoft.iot.vmp.vmanager.server;
|
||||
|
||||
import com.genersoft.iot.vmp.VManageBootstrap;
|
||||
import com.genersoft.iot.vmp.media.zlm.ZLMServerConfig;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
|
||||
import com.genersoft.iot.vmp.service.IMediaServerService;
|
||||
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
|
||||
import com.genersoft.iot.vmp.utils.SpringBeanFactory;
|
||||
import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
|
||||
import gov.nist.javax.sip.SipStackImpl;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
@ -16,6 +19,7 @@ import javax.sip.ObjectInUseException;
|
||||
import javax.sip.SipProvider;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Api(tags = "服务控制")
|
||||
@ -28,17 +32,28 @@ public class ServerController {
|
||||
private ConfigurableApplicationContext context;
|
||||
|
||||
@Autowired
|
||||
private IRedisCatchStorage redisCatchStorage;
|
||||
private IMediaServerService mediaServerService;
|
||||
|
||||
|
||||
@ApiOperation("流媒体服务列表")
|
||||
@GetMapping(value = "/media_server/list")
|
||||
@ResponseBody
|
||||
public Object getMediaServerList(){
|
||||
// TODO 为后续多个zlm支持准备
|
||||
ZLMServerConfig mediaInfo = redisCatchStorage.getMediaInfo();
|
||||
ArrayList<ZLMServerConfig> result = new ArrayList<>();
|
||||
result.add(mediaInfo);
|
||||
public WVPResult<List<IMediaServerItem>> getMediaServerList(){
|
||||
WVPResult<List<IMediaServerItem>> result = new WVPResult<>();
|
||||
result.setCode(0);
|
||||
result.setMsg("success");
|
||||
result.setData(mediaServerService.getAll());
|
||||
return result;
|
||||
}
|
||||
|
||||
@ApiOperation("获取流媒体服务")
|
||||
@GetMapping(value = "/media_server/one/{id}")
|
||||
@ResponseBody
|
||||
public WVPResult<IMediaServerItem> getMediaServer(@PathVariable String id){
|
||||
WVPResult<IMediaServerItem> result = new WVPResult<>();
|
||||
result.setCode(0);
|
||||
result.setMsg("success");
|
||||
result.setData(mediaServerService.getOne(id));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -1,11 +1,15 @@
|
||||
package com.genersoft.iot.vmp.vmanager.streamProxy;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
|
||||
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 com.genersoft.iot.vmp.storager.IRedisCatchStorage;
|
||||
import com.genersoft.iot.vmp.service.IStreamProxyService;
|
||||
import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
|
||||
import com.github.pagehelper.PageInfo;
|
||||
import io.netty.util.internal.StringUtil;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiImplicitParam;
|
||||
import io.swagger.annotations.ApiImplicitParams;
|
||||
@ -14,6 +18,7 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
@ -31,6 +36,10 @@ public class StreamProxyController {
|
||||
@Autowired
|
||||
private IRedisCatchStorage redisCatchStorage;
|
||||
|
||||
|
||||
@Autowired
|
||||
private IMediaServerService mediaServerService;
|
||||
|
||||
@Autowired
|
||||
private IStreamProxyService streamProxyService;
|
||||
|
||||
@ -60,6 +69,7 @@ public class StreamProxyController {
|
||||
@ResponseBody
|
||||
public WVPResult save(@RequestBody StreamProxyItem param){
|
||||
logger.info("添加代理: " + JSONObject.toJSONString(param));
|
||||
if (StringUtils.isEmpty(param.getMediaServerId())) param.setMediaServerId("auto");
|
||||
String msg = streamProxyService.save(param);
|
||||
WVPResult<Object> result = new WVPResult<>();
|
||||
result.setCode(0);
|
||||
@ -69,10 +79,15 @@ public class StreamProxyController {
|
||||
|
||||
@ApiOperation("获取ffmpeg.cmd模板")
|
||||
@GetMapping(value = "/ffmpeg_cmd/list")
|
||||
@ApiImplicitParams({
|
||||
@ApiImplicitParam(name = "mediaServerId", value = "流媒体ID", dataTypeClass = String.class),
|
||||
})
|
||||
@ResponseBody
|
||||
public WVPResult getFFmpegCMDs(){
|
||||
logger.debug("获取ffmpeg.cmd模板:" );
|
||||
JSONObject data = streamProxyService.getFFmpegCMDs();
|
||||
public WVPResult getFFmpegCMDs(@RequestParam String mediaServerId){
|
||||
logger.debug("获取节点[ {} ]ffmpeg.cmd模板", mediaServerId );
|
||||
|
||||
IMediaServerItem mediaServerItem = mediaServerService.getOne(mediaServerId);
|
||||
JSONObject data = streamProxyService.getFFmpegCMDs(mediaServerItem);
|
||||
WVPResult<JSONObject> result = new WVPResult<>();
|
||||
result.setCode(0);
|
||||
result.setMsg("success");
|
||||
@ -82,12 +97,12 @@ public class StreamProxyController {
|
||||
|
||||
@ApiOperation("移除代理")
|
||||
@ApiImplicitParams({
|
||||
@ApiImplicitParam(name = "app", value = "应用名", dataTypeClass = String.class),
|
||||
@ApiImplicitParam(name = "stream", value = "流ID", dataTypeClass = String.class),
|
||||
@ApiImplicitParam(name = "app", value = "应用名", required = true, dataTypeClass = String.class),
|
||||
@ApiImplicitParam(name = "stream", value = "流ID", required = true, dataTypeClass = String.class),
|
||||
})
|
||||
@DeleteMapping(value = "/del")
|
||||
@ResponseBody
|
||||
public WVPResult del(String app, String stream){
|
||||
public WVPResult del(@RequestParam String app, @RequestParam String stream){
|
||||
logger.info("移除代理: " + app + "/" + stream);
|
||||
WVPResult<Object> result = new WVPResult<>();
|
||||
if (app == null || stream == null) {
|
||||
|
@ -10,7 +10,7 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
/**
|
||||
* 兼容LiveGBS的API:设备控制
|
||||
* API兼容:设备控制
|
||||
*/
|
||||
@CrossOrigin
|
||||
@RestController
|
||||
|
@ -11,7 +11,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
/**
|
||||
* 兼容LiveGBS的API:系统接口
|
||||
* API兼容:系统接口
|
||||
*/
|
||||
@Controller
|
||||
@CrossOrigin
|
||||
|
@ -14,7 +14,7 @@ import org.springframework.web.bind.annotation.*;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 兼容LiveGBS的API:设备信息
|
||||
* API兼容:设备信息
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@CrossOrigin
|
||||
|
@ -17,7 +17,7 @@ import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.context.request.async.DeferredResult;
|
||||
|
||||
/**
|
||||
* 兼容LiveGBS的API:实时直播
|
||||
* API兼容:实时直播
|
||||
*/
|
||||
@SuppressWarnings(value = {"rawtypes", "unchecked"})
|
||||
@CrossOrigin
|
||||
|
@ -70,9 +70,13 @@ sip:
|
||||
keepalive-timeout: 180
|
||||
# [可选] 国标级联注册失败,再次发起注册的时间间隔。 默认60秒
|
||||
register-time-interval: 60
|
||||
# TODO [可选] 收到心跳后自动上线, 重启服务后会将所有设备置为离线,默认false,等待注册后上线。设置为true则收到心跳设置为上线。
|
||||
# keepalliveToOnline: false
|
||||
|
||||
#zlm 默认服务器配置
|
||||
media:
|
||||
# [可选] zlm服务器唯一id,用于触发hook时区别是哪台服务器,general.mediaServerId
|
||||
id:
|
||||
# [必须修改] zlm服务器的内网IP
|
||||
ip: 192.168.0.100
|
||||
# [可选] 返回流地址时的ip,置空使用 media.ip
|
||||
|
Binary file not shown.
@ -7,22 +7,23 @@
|
||||
<el-main>
|
||||
<div style="background-color: #FFFFFF; margin-bottom: 1rem; position: relative; padding: 0.5rem; text-align: left;">
|
||||
<span style="font-size: 1rem; font-weight: bold;">云端录像</span>
|
||||
<div style="position: absolute; right: 5rem; top: 0.3rem;">
|
||||
节点选择: <el-select size="mini" @change="chooseMediaChange" style="width: 16rem; margin-right: 1rem;" v-model="mediaServer" placeholder="请选择" default-first-option>
|
||||
<el-option
|
||||
v-for="item in mediaServerList"
|
||||
:key="item.id"
|
||||
:label="item.id + '( ' + item.streamIp + ' )'"
|
||||
:value="item">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</div>
|
||||
<div style="position: absolute; right: 1rem; top: 0.3rem;">
|
||||
<el-button v-if="!recordDetail" icon="el-icon-refresh-right" circle size="mini" :loading="loading" @click="getRecordList()"></el-button>
|
||||
<el-button v-if="recordDetail" icon="el-icon-arrow-left" circle size="mini" @click="backToList()"></el-button>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="!recordDetail">
|
||||
<div style="background-color: #FFFFFF; margin-bottom: 1rem; position: relative; padding: 0.5rem; text-align: left;font-size: 14px;">
|
||||
节点选择: <el-select size="mini" @change="chooseMediaChange" style="width: 16rem; margin-right: 1rem;" v-model="mediaServer" placeholder="请选择" default-first-option>
|
||||
<el-option
|
||||
v-for="item in mediaServerList"
|
||||
:key="item.generalMediaServerId"
|
||||
:label="item.generalMediaServerId + '( ' + item.wanIp + ' )'"
|
||||
:value="item">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</div>
|
||||
|
||||
<!--设备列表-->
|
||||
<el-table :data="recordList" border style="width: 100%" :height="winHeight">
|
||||
<el-table-column prop="app" label="应用名" align="center">
|
||||
@ -60,6 +61,7 @@
|
||||
<script>
|
||||
import uiHeader from './UiHeader.vue'
|
||||
import cloudRecordDetail from './CloudRecordDetail.vue'
|
||||
import MediaServer from './service/MediaServer'
|
||||
export default {
|
||||
name: 'app',
|
||||
components: {
|
||||
@ -78,6 +80,7 @@
|
||||
count:15,
|
||||
total:0,
|
||||
loading: false,
|
||||
mediaServerObj : new MediaServer(),
|
||||
recordDetail: false
|
||||
|
||||
};
|
||||
@ -107,20 +110,13 @@
|
||||
},
|
||||
getMediaServerList: function (){
|
||||
let that = this;
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url:`/api/server/media_server/list`,
|
||||
}).then(function (res) {
|
||||
console.log(res)
|
||||
that.mediaServerList = res.data;
|
||||
that.mediaServerObj.getMediaServerList((data)=>{
|
||||
that.mediaServerList = data;
|
||||
if (that.mediaServerList.length > 0) {
|
||||
that.mediaServer = that.mediaServerList[0]
|
||||
that.getRecordList();
|
||||
}
|
||||
|
||||
}).catch(function (error) {
|
||||
console.log(error);
|
||||
});
|
||||
})
|
||||
},
|
||||
getRecordList: function (){
|
||||
let that = this;
|
||||
|
@ -17,6 +17,8 @@
|
||||
</el-table-column>
|
||||
<el-table-column prop="gbId" label="国标编码" width="150" align="center">
|
||||
</el-table-column>
|
||||
<el-table-column prop="mediaServerId" label="流媒体" width="150" align="center">
|
||||
</el-table-column>
|
||||
<el-table-column label="开始时间" align="center" >
|
||||
<template slot-scope="scope">
|
||||
<el-button-group>
|
||||
@ -134,7 +136,8 @@
|
||||
url:`/api/media/stream_info_by_app_and_stream`,
|
||||
params: {
|
||||
app: row.app,
|
||||
stream: row.stream
|
||||
stream: row.stream,
|
||||
mediaServerId: row.mediaServerId
|
||||
}
|
||||
}).then(function (res) {
|
||||
that.getListLoading = false;
|
||||
|
@ -32,6 +32,15 @@
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="mediaServerId" label="流媒体" width="150" align="center"></el-table-column>
|
||||
<el-table-column label="类型" width="100" align="center">
|
||||
<template slot-scope="scope">
|
||||
<div slot="reference" class="name-wrapper">
|
||||
<el-tag size="medium">{{scope.row.type}}</el-tag>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column prop="gbId" label="国标编码" width="180" align="center" show-overflow-tooltip/>
|
||||
<el-table-column label="启用" width="120" align="center">
|
||||
<template slot-scope="scope">
|
||||
@ -147,8 +156,6 @@
|
||||
count: that.count
|
||||
}
|
||||
}).then(function (res) {
|
||||
console.log(res);
|
||||
console.log(res.data.list);
|
||||
that.total = res.data.total;
|
||||
that.streamProxyList = res.data.list;
|
||||
that.getListLoading = false;
|
||||
@ -170,7 +177,6 @@
|
||||
this.getListLoading = false;
|
||||
if (res.data.code == 0 ){
|
||||
if (res.data.data.length > 0) {
|
||||
console.log(res.data.data)
|
||||
this.$refs.onvifEdit.openDialog(res.data.data, (url)=>{
|
||||
if (url != null) {
|
||||
this.$refs.onvifEdit.close();
|
||||
@ -200,7 +206,8 @@
|
||||
url:`/api/media/stream_info_by_app_and_stream`,
|
||||
params: {
|
||||
app: row.app,
|
||||
stream: row.stream
|
||||
stream: row.stream,
|
||||
mediaServerId: row.mediaServerId
|
||||
}
|
||||
}).then(function (res) {
|
||||
that.getListLoading = false;
|
||||
|
@ -7,6 +7,17 @@
|
||||
<el-main>
|
||||
<div style="background-color: #FFFFFF; margin-bottom: 1rem; position: relative; padding: 0.5rem; text-align: left;">
|
||||
<span style="font-size: 1rem; font-weight: bold;">控制台</span>
|
||||
<div style="position: absolute; right: 17rem; top: 0.3rem;">
|
||||
节点选择: <el-select size="mini" @change="chooseMediaChange" style="width: 16rem; margin-right: 1rem;" v-model="mediaServerChoose" placeholder="请选择" default-first-option>
|
||||
<el-option
|
||||
v-for="item in mediaServerList"
|
||||
:key="item.id"
|
||||
:label="item.id + '( ' + item.streamIp + ' )'"
|
||||
:value="item.id">
|
||||
</el-option>
|
||||
</el-select>
|
||||
<span >{{loadCount}}</span>
|
||||
</div>
|
||||
<div style="position: absolute; right: 1rem; top: 0.3rem;">
|
||||
<el-popover placement="bottom" width="750" height="300" trigger="click">
|
||||
<div style="height: 600px;overflow:auto;">
|
||||
@ -53,6 +64,7 @@
|
||||
|
||||
<script>
|
||||
import uiHeader from './UiHeader.vue'
|
||||
import MediaServer from './service/MediaServer'
|
||||
|
||||
import echarts from 'echarts';
|
||||
export default {
|
||||
@ -87,68 +99,101 @@ export default {
|
||||
chartInterval: 0, //更新图表统计图定时任务标识
|
||||
allSessionData: [],
|
||||
visible: false,
|
||||
serverConfig: {}
|
||||
serverConfig: {},
|
||||
mediaServer : new MediaServer(),
|
||||
mediaServerChoose : null,
|
||||
loadCount : 0,
|
||||
mediaServerList : []
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
this.getAllSession();
|
||||
|
||||
this.initTable();
|
||||
this.updateData();
|
||||
this.chartInterval = setInterval(this.updateData, 3000);
|
||||
this.mediaServer.getMediaServerList((data)=>{
|
||||
this.mediaServerList = data.data;
|
||||
if (this.mediaServerList && this.mediaServerList.length > 0) {
|
||||
this.mediaServerChoose = this.mediaServerList[0].id
|
||||
this.loadCount = this.mediaServerList[0].count;
|
||||
this.getThreadsLoad();
|
||||
this.getAllSession();
|
||||
}
|
||||
})
|
||||
},
|
||||
destroyed() {
|
||||
clearInterval(this.chartInterval); //释放定时任务
|
||||
},
|
||||
methods: {
|
||||
chooseMediaChange: function (val) {
|
||||
this.loadCount = 0
|
||||
this.initTable()
|
||||
this.updateData();
|
||||
},
|
||||
updateData: function () {
|
||||
this.getThreadsLoad();
|
||||
this.getLoadCount();
|
||||
this.getAllSession();
|
||||
},
|
||||
/**
|
||||
* 获取线程状态
|
||||
*/
|
||||
getThreadsLoad: function () {
|
||||
let that = this;
|
||||
this.$axios({
|
||||
if (that.mediaServerChoose != null) {
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url: '/zlm/index/api/getThreadsLoad'
|
||||
}).then(function (res) {
|
||||
url: '/zlm/' + that.mediaServerChoose +'/index/api/getThreadsLoad'
|
||||
}).then(function (res) {
|
||||
if (res.data.code == 0) {
|
||||
that.tableOption.xAxis.data.push(new Date().toLocaleTimeString('chinese', {
|
||||
hour12: false
|
||||
}));
|
||||
that.table1Option.xAxis.data.push(new Date().toLocaleTimeString('chinese', {
|
||||
hour12: false
|
||||
}));
|
||||
that.tableOption.xAxis.data.push(new Date().toLocaleTimeString('chinese', {
|
||||
hour12: false
|
||||
}));
|
||||
that.table1Option.xAxis.data.push(new Date().toLocaleTimeString('chinese', {
|
||||
hour12: false
|
||||
}));
|
||||
|
||||
for (var i = 0; i < res.data.data.length; i++) {
|
||||
if (that.tableOption.series[i] === undefined) {
|
||||
let data = {
|
||||
data: [],
|
||||
type: 'line'
|
||||
};
|
||||
let data1 = {
|
||||
data: [],
|
||||
type: 'line'
|
||||
};
|
||||
data.data.push(res.data.data[i].delay);
|
||||
data1.data.push(res.data.data[i].load);
|
||||
that.tableOption.series.push(data);
|
||||
that.table1Option.series.push(data1);
|
||||
} else {
|
||||
that.tableOption.series[i].data.push(res.data.data[i].delay);
|
||||
that.table1Option.series[i].data.push(res.data.data[i].load);
|
||||
}
|
||||
for (var i = 0; i < res.data.data.length; i++) {
|
||||
if (that.tableOption.series[i] === undefined) {
|
||||
let data = {
|
||||
data: [],
|
||||
type: 'line'
|
||||
};
|
||||
let data1 = {
|
||||
data: [],
|
||||
type: 'line'
|
||||
};
|
||||
data.data.push(res.data.data[i].delay);
|
||||
data1.data.push(res.data.data[i].load);
|
||||
that.tableOption.series.push(data);
|
||||
that.table1Option.series.push(data1);
|
||||
} else {
|
||||
that.tableOption.series[i].data.push(res.data.data[i].delay);
|
||||
that.table1Option.series[i].data.push(res.data.data[i].load);
|
||||
}
|
||||
that.tableOption.dataZoom[0].start = that.charZoomStart;
|
||||
that.tableOption.dataZoom[0].end = that.charZoomEnd;
|
||||
that.table1Option.dataZoom[0].start = that.charZoomStart;
|
||||
that.table1Option.dataZoom[0].end = that.charZoomEnd;
|
||||
//that.myChart = echarts.init(document.getElementById('ThreadsLoad'));
|
||||
that.myChart.setOption(that.tableOption, true);
|
||||
// that.myChart1 = echarts.init(document.getElementById('WorkThreadsLoad'));
|
||||
that.myChart1.setOption(that.table1Option, true);
|
||||
}
|
||||
that.tableOption.dataZoom[0].start = that.charZoomStart;
|
||||
that.tableOption.dataZoom[0].end = that.charZoomEnd;
|
||||
that.table1Option.dataZoom[0].start = that.charZoomStart;
|
||||
that.table1Option.dataZoom[0].end = that.charZoomEnd;
|
||||
//that.myChart = echarts.init(document.getElementById('ThreadsLoad'));
|
||||
that.myChart.setOption(that.tableOption, true);
|
||||
// that.myChart1 = echarts.init(document.getElementById('WorkThreadsLoad'));
|
||||
that.myChart1.setOption(that.table1Option, true);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
},
|
||||
getLoadCount: function (){
|
||||
let that = this;
|
||||
if (that.mediaServerChoose != null) {
|
||||
that.mediaServer.getMediaServer(that.mediaServerChoose, (data)=>{
|
||||
if (data.code == 0) {
|
||||
that.loadCount = data.data.count
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
initTable: function () {
|
||||
let that = this;
|
||||
@ -242,10 +287,9 @@ export default {
|
||||
getAllSession: function () {
|
||||
let that = this;
|
||||
that.allSessionData = [];
|
||||
console.log("地址:" + '/zlm/index/api/getAllSession');
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url: '/zlm/index/api/getAllSession'
|
||||
url: '/zlm/' + that.mediaServerChoose +'/index/api/getAllSession'
|
||||
}).then(function (res) {
|
||||
res.data.data.forEach(item => {
|
||||
let data = {
|
||||
|
@ -39,6 +39,22 @@
|
||||
<el-form-item label="超时时间:毫秒" prop="timeout_ms" v-if="proxyParam.type=='ffmpeg'">
|
||||
<el-input v-model="proxyParam.timeout_ms" clearable></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="节点选择" prop="rtp_type">
|
||||
<el-select
|
||||
v-model="proxyParam.mediaServerId"
|
||||
@change="mediaServerIdChange"
|
||||
style="width: 100%"
|
||||
placeholder="请选择拉流节点"
|
||||
>
|
||||
<el-option label="自动选择" value="auto"></el-option>
|
||||
<el-option
|
||||
v-for="item in mediaServerList"
|
||||
:key="item.id"
|
||||
:label="item.id"
|
||||
:value="item.id">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="FFmpeg命令模板" prop="ffmpeg_cmd_key" v-if="proxyParam.type=='ffmpeg'">
|
||||
<!-- <el-input v-model="proxyParam.ffmpeg_cmd_key" clearable></el-input>-->
|
||||
<el-select
|
||||
@ -68,6 +84,7 @@
|
||||
<el-option label="组播" value="2"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="国标平台">
|
||||
<el-select
|
||||
v-model="proxyParam.platformGbId"
|
||||
@ -106,6 +123,8 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import MediaServer from './../service/MediaServer'
|
||||
|
||||
export default {
|
||||
name: "streamProxyEdit",
|
||||
props: {},
|
||||
@ -134,27 +153,8 @@ export default {
|
||||
isLoging: false,
|
||||
dialogLoading: false,
|
||||
onSubmit_text: "立即创建",
|
||||
platformList: [{
|
||||
id: 1,
|
||||
enable: true,
|
||||
name: "141",
|
||||
serverGBId: "34020000002000000001",
|
||||
serverGBDomain: "3402000000",
|
||||
serverIP: "192.168.1.141",
|
||||
serverPort: 15060,
|
||||
deviceGBId: "34020000002000000001",
|
||||
deviceIp: "192.168.1.20",
|
||||
devicePort: "5060",
|
||||
username: "34020000002000000001",
|
||||
password: "12345678",
|
||||
expires: "300",
|
||||
keepTimeout: "60",
|
||||
transport: "UDP",
|
||||
characterSet: "GB2312",
|
||||
ptz: false,
|
||||
rtcp: false,
|
||||
status: true,
|
||||
}],
|
||||
platformList: [],
|
||||
mediaServer: new MediaServer(),
|
||||
proxyParam: {
|
||||
name: null,
|
||||
type: "default",
|
||||
@ -170,7 +170,9 @@ export default {
|
||||
enable_hls: true,
|
||||
enable_mp4: false,
|
||||
platformGbId: null,
|
||||
mediaServerId: "auto",
|
||||
},
|
||||
mediaServerList:{},
|
||||
ffmpegCmdList:{},
|
||||
|
||||
rules: {
|
||||
@ -193,7 +195,6 @@ export default {
|
||||
}
|
||||
|
||||
let that = this;
|
||||
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url:`/api/platform/query/10000/0`
|
||||
@ -202,17 +203,28 @@ export default {
|
||||
}).catch(function (error) {
|
||||
console.log(error);
|
||||
});
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url:`/api/proxy/ffmpeg_cmd/list`
|
||||
}).then(function (res) {
|
||||
that.ffmpegCmdList = res.data.data;
|
||||
}).catch(function (error) {
|
||||
console.log(error);
|
||||
});
|
||||
this.mediaServer.getMediaServerList((data)=>{
|
||||
this.mediaServerList = data;
|
||||
})
|
||||
},
|
||||
mediaServerIdChange:function (){
|
||||
let that = this;
|
||||
if (that.proxyParam.mediaServerId !== "auto"){
|
||||
that.$axios({
|
||||
method: 'get',
|
||||
url:`/api/proxy/ffmpeg_cmd/list`,
|
||||
params: {
|
||||
mediaServerId: that.proxyParam.mediaServerId
|
||||
}
|
||||
}).then(function (res) {
|
||||
that.ffmpegCmdList = res.data.data;
|
||||
}).catch(function (error) {
|
||||
console.log(error);
|
||||
});
|
||||
}
|
||||
|
||||
},
|
||||
onSubmit: function () {
|
||||
console.log("onSubmit");
|
||||
this.dialogLoading = true;
|
||||
var that = this;
|
||||
that.$axios({
|
||||
@ -239,7 +251,6 @@ export default {
|
||||
});
|
||||
},
|
||||
close: function () {
|
||||
console.log("关闭添加视频平台");
|
||||
this.showDialog = false;
|
||||
this.dialogLoading = false;
|
||||
this.$refs.streamProxy.resetFields();
|
||||
|
@ -181,6 +181,7 @@ export default {
|
||||
showVideoDialog: false,
|
||||
streamId: '',
|
||||
app : '',
|
||||
mediaServerId : '',
|
||||
convertKey: '',
|
||||
deviceId: '',
|
||||
channelId: '',
|
||||
@ -218,7 +219,7 @@ export default {
|
||||
if (tab.name == "codec") {
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url: '/zlm/index/api/getMediaInfo?vhost=__defaultVhost__&schema=rtmp&app='+ this.app +'&stream='+ this.streamId
|
||||
url: '/zlm/' +this.mediaServerId+ '/index/api/getMediaInfo?vhost=__defaultVhost__&schema=rtmp&app='+ this.app +'&stream='+ this.streamId
|
||||
}).then(function (res) {
|
||||
that.tracksLoading = false;
|
||||
if (res.data.code == 0 && res.data.online) {
|
||||
@ -235,12 +236,11 @@ export default {
|
||||
}
|
||||
},
|
||||
openDialog: function (tab, deviceId, channelId, param) {
|
||||
console.log("openDialog")
|
||||
console.log(param)
|
||||
this.tabActiveName = tab;
|
||||
this.channelId = channelId;
|
||||
this.deviceId = deviceId;
|
||||
this.streamId = "";
|
||||
this.mediaServerId = "";
|
||||
this.app = "";
|
||||
this.videoUrl = ""
|
||||
if (!!this.$refs.videoPlayer) {
|
||||
@ -257,8 +257,8 @@ export default {
|
||||
break;
|
||||
case "streamPlay":
|
||||
this.tabActiveName = "media";
|
||||
this.showRrecord = false,
|
||||
this.showPtz = false,
|
||||
this.showRrecord = false;
|
||||
this.showPtz = false;
|
||||
this.play(param.streamInfo, param.hasAudio)
|
||||
break;
|
||||
case "control":
|
||||
@ -269,19 +269,17 @@ export default {
|
||||
console.log(val)
|
||||
},
|
||||
play: function (streamInfo, hasAudio) {
|
||||
|
||||
this.hasAudio = hasAudio;
|
||||
this.isLoging = false;
|
||||
// this.videoUrl = streamInfo.rtc;
|
||||
this.videoUrl = this.getUrlByStreamInfo(streamInfo);
|
||||
this.streamId = streamInfo.streamId;
|
||||
this.app = streamInfo.app;
|
||||
this.mediaServerId = streamInfo.mediaServerId;
|
||||
this.playFromStreamInfo(false, streamInfo)
|
||||
},
|
||||
getUrlByStreamInfo(streamInfo){
|
||||
let baseZlmApi = process.env.NODE_ENV === 'development'?`${location.host}/debug/zlm`:`${location.host}/zlm`
|
||||
console.log(12121212)
|
||||
console.log(baseZlmApi)
|
||||
// return `${baseZlmApi}/${streamInfo.app}/${streamInfo.streamId}.flv`;
|
||||
// return `http://${baseZlmApi}/${streamInfo.app}/${streamInfo.streamId}.flv`;
|
||||
return streamInfo.ws_flv;
|
||||
@ -430,6 +428,7 @@ export default {
|
||||
var streamInfo = res.data;
|
||||
that.app = streamInfo.app;
|
||||
that.streamId = streamInfo.streamId;
|
||||
that.mediaServerId = streamInfo.mediaServerId;
|
||||
that.videoUrl = that.getUrlByStreamInfo(streamInfo);
|
||||
that.recordPlay = true;
|
||||
});
|
||||
|
32
web_src/src/components/service/MediaServer.js
Normal file
32
web_src/src/components/service/MediaServer.js
Normal file
@ -0,0 +1,32 @@
|
||||
import axios from 'axios';
|
||||
|
||||
class MediaServer{
|
||||
|
||||
constructor() {
|
||||
this.$axios = axios;
|
||||
}
|
||||
|
||||
getMediaServerList(callback){
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url:`/api/server/media_server/list`,
|
||||
}).then(function (res) {
|
||||
if (typeof (callback) == "function") callback(res.data)
|
||||
}).catch(function (error) {
|
||||
console.log(error);
|
||||
});
|
||||
}
|
||||
|
||||
getMediaServer(id, callback){
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url:`/api/server/media_server/one/` + id,
|
||||
}).then(function (res) {
|
||||
if (typeof (callback) == "function") callback(res.data)
|
||||
}).catch(function (error) {
|
||||
console.log(error);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default MediaServer;
|
Loading…
Reference in New Issue
Block a user