Browse Source

添加发送媒体流, 添加媒体服务器节点管理ui,修复修改密码

pull/174/head
648540858 3 years ago
parent
commit
720231d33f
  1. 1
      sql/mysql.sql
  2. 3
      src/main/java/com/genersoft/iot/vmp/conf/ApiAccessFilter.java
  3. 13
      src/main/java/com/genersoft/iot/vmp/conf/MediaConfig.java
  4. 7
      src/main/java/com/genersoft/iot/vmp/conf/ProxyServletConfig.java
  5. 22
      src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRTPServerFactory.java
  6. 6
      src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRunner.java
  7. 29
      src/main/java/com/genersoft/iot/vmp/media/zlm/dto/MediaServerItem.java
  8. 7
      src/main/java/com/genersoft/iot/vmp/service/IMediaServerService.java
  9. 166
      src/main/java/com/genersoft/iot/vmp/service/impl/MediaServerServiceImpl.java
  10. 3
      src/main/java/com/genersoft/iot/vmp/storager/dao/MediaServerMapper.java
  11. 60
      src/main/java/com/genersoft/iot/vmp/vmanager/server/ServerController.java
  12. 2
      src/main/resources/all-application.yml
  13. 2
      src/main/resources/application-dev.yml
  14. BIN
      src/main/resources/wvp.sqlite
  15. 1
      web_src/build/webpack.base.conf.js
  16. BIN
      web_src/src/assets/zlm-log.png
  17. 2
      web_src/src/components/CloudRecord.vue
  18. 2
      web_src/src/components/DeviceList.vue
  19. 159
      web_src/src/components/MediaServerManger.vue
  20. 1
      web_src/src/components/UiHeader.vue
  21. 2
      web_src/src/components/control.vue
  22. 368
      web_src/src/components/dialog/MediaServerEdit.vue
  23. 2
      web_src/src/components/dialog/StreamProxyEdit.vue
  24. 2
      web_src/src/components/dialog/changePassword.vue
  25. 2
      web_src/src/components/dialog/deviceEdit.vue
  26. 55
      web_src/src/components/service/MediaServer.js
  27. 6
      web_src/src/router/index.js
  28. 10
      web_src/static/css/iconfont.css
  29. BIN
      web_src/static/css/iconfont.woff2
  30. BIN
      web_src/static/images/zlm-logo.png

1
sql/mysql.sql

@ -140,6 +140,7 @@ create table media_server
streamNoneReaderDelayMS int not null, streamNoneReaderDelayMS int not null,
rtpEnable int not null, rtpEnable int not null,
rtpPortRange varchar(50) not null, rtpPortRange varchar(50) not null,
sendRtpPortRange varchar(50) not null,
recordAssistPort int not null, recordAssistPort int not null,
defaultServer int not null, defaultServer int not null,
createTime varchar(50) not null, createTime varchar(50) not null,

3
src/main/java/com/genersoft/iot/vmp/conf/ApiAccessFilter.java

@ -18,6 +18,9 @@ import javax.servlet.http.HttpServletResponse;
import java.io.IOException; import java.io.IOException;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
/**
* @author lin
*/
@WebFilter(filterName = "ApiAccessFilter", urlPatterns = "/api/*", asyncSupported=true) @WebFilter(filterName = "ApiAccessFilter", urlPatterns = "/api/*", asyncSupported=true)
public class ApiAccessFilter extends OncePerRequestFilter { public class ApiAccessFilter extends OncePerRequestFilter {

13
src/main/java/com/genersoft/iot/vmp/conf/MediaConfig.java

@ -68,6 +68,10 @@ public class MediaConfig{
@Value("${media.rtp.port-range}") @Value("${media.rtp.port-range}")
private String rtpPortRange; private String rtpPortRange;
@Value("${media.rtp.send-port-range}")
private String sendRtpPortRange;
@Value("${media.record-assist-port:0}") @Value("${media.record-assist-port:0}")
private Integer recordAssistPort = 0; private Integer recordAssistPort = 0;
@ -165,6 +169,14 @@ public class MediaConfig{
} }
} }
public String getSipDomain() {
return sipDomain;
}
public String getSendRtpPortRange() {
return sendRtpPortRange;
}
public MediaServerItem getMediaSerItem(){ public MediaServerItem getMediaSerItem(){
MediaServerItem mediaServerItem = new MediaServerItem(); MediaServerItem mediaServerItem = new MediaServerItem();
mediaServerItem.setId(id); mediaServerItem.setId(id);
@ -185,6 +197,7 @@ public class MediaConfig{
mediaServerItem.setStreamNoneReaderDelayMS(streamNoneReaderDelayMS); mediaServerItem.setStreamNoneReaderDelayMS(streamNoneReaderDelayMS);
mediaServerItem.setRtpEnable(rtpEnable); mediaServerItem.setRtpEnable(rtpEnable);
mediaServerItem.setRtpPortRange(rtpPortRange); mediaServerItem.setRtpPortRange(rtpPortRange);
mediaServerItem.setSendRtpPortRange(sendRtpPortRange);
mediaServerItem.setRecordAssistPort(recordAssistPort); mediaServerItem.setRecordAssistPort(recordAssistPort);
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

7
src/main/java/com/genersoft/iot/vmp/conf/ProxyServletConfig.java

@ -21,6 +21,9 @@ import javax.servlet.http.HttpServletRequest;
import java.io.IOException; import java.io.IOException;
import java.net.ConnectException; import java.net.ConnectException;
/**
* @author lin
*/
@SuppressWarnings(value = {"rawtypes", "unchecked"}) @SuppressWarnings(value = {"rawtypes", "unchecked"})
@Configuration @Configuration
public class ProxyServletConfig { public class ProxyServletConfig {
@ -35,7 +38,7 @@ public class ProxyServletConfig {
@Bean @Bean
public ServletRegistrationBean zlmServletRegistrationBean(){ public ServletRegistrationBean zlmServletRegistrationBean(){
ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new ZLMProxySerlet(),"/zlm/*"); ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new ZlmProxyServlet(),"/zlm/*");
servletRegistrationBean.setName("zlm_Proxy"); servletRegistrationBean.setName("zlm_Proxy");
servletRegistrationBean.addInitParameter("targetUri", "http://127.0.0.1:6080"); servletRegistrationBean.addInitParameter("targetUri", "http://127.0.0.1:6080");
servletRegistrationBean.addUrlMappings(); servletRegistrationBean.addUrlMappings();
@ -45,7 +48,7 @@ public class ProxyServletConfig {
return servletRegistrationBean; return servletRegistrationBean;
} }
class ZLMProxySerlet extends ProxyServlet{ class ZlmProxyServlet extends ProxyServlet{
@Override @Override
protected String rewriteQueryStringFromRequest(HttpServletRequest servletRequest, String queryString) { protected String rewriteQueryStringFromRequest(HttpServletRequest servletRequest, String queryString) {
String queryStr = super.rewriteQueryStringFromRequest(servletRequest, queryString); String queryStr = super.rewriteQueryStringFromRequest(servletRequest, queryString);

22
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRTPServerFactory.java

@ -8,6 +8,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
@ -44,8 +45,15 @@ public class ZLMRTPServerFactory {
Map<String, Object> param = new HashMap<>(); Map<String, Object> param = new HashMap<>();
int result = -1; int result = -1;
/**
* 不设置推流端口端则使用随机端口
*/
if (StringUtils.isEmpty(mediaServerItem.getSendRtpPortRange())){
param.put("port", 0);
}else {
int newPort = getPortFromportRange(mediaServerItem); int newPort = getPortFromportRange(mediaServerItem);
param.put("port", newPort); param.put("port", newPort);
}
param.put("enable_tcp", 1); param.put("enable_tcp", 1);
param.put("stream_id", streamId); param.put("stream_id", streamId);
JSONObject openRtpServerResultJson = zlmresTfulUtils.openRtpServer(mediaServerItem, param); JSONObject openRtpServerResultJson = zlmresTfulUtils.openRtpServer(mediaServerItem, param);
@ -53,24 +61,24 @@ public class ZLMRTPServerFactory {
if (openRtpServerResultJson != null) { if (openRtpServerResultJson != null) {
switch (openRtpServerResultJson.getInteger("code")){ switch (openRtpServerResultJson.getInteger("code")){
case 0: case 0:
result= newPort; result= openRtpServerResultJson.getInteger("port");
break; break;
case -300: // id已经存在, 可能已经在其他端口推流 case -300: // id已经存在, 可能已经在其他端口推流
Map<String, Object> closeRtpServerParam = new HashMap<>(); Map<String, Object> closeRtpServerParam = new HashMap<>();
closeRtpServerParam.put("stream_id", streamId); closeRtpServerParam.put("stream_id", streamId);
zlmresTfulUtils.closeRtpServer(mediaServerItem, closeRtpServerParam); zlmresTfulUtils.closeRtpServer(mediaServerItem, closeRtpServerParam);
result = newPort; result = createRTPServer(mediaServerItem, streamId);;
break; break;
case -400: // 端口占用 case -400: // 端口占用
result= createRTPServer(mediaServerItem, streamId); result= createRTPServer(mediaServerItem, streamId);
break; break;
default: default:
logger.error("创建RTP Server 失败 {}: " + openRtpServerResultJson.getString("msg"), newPort); logger.error("创建RTP Server 失败 {}: " + openRtpServerResultJson.getString("msg"), param.get("port"));
break; break;
} }
}else { }else {
// 检查ZLM状态 // 检查ZLM状态
logger.error("创建RTP Server 失败 {}: 请检查ZLM服务", newPort); logger.error("创建RTP Server 失败 {}: 请检查ZLM服务", param.get("port"));
} }
return result; return result;
} }
@ -98,7 +106,7 @@ public class ZLMRTPServerFactory {
private int getPortFromportRange(MediaServerItem mediaServerItem) { private int getPortFromportRange(MediaServerItem mediaServerItem) {
int currentPort = mediaServerItem.getCurrentPort(); int currentPort = mediaServerItem.getCurrentPort();
if (currentPort == 0) { if (currentPort == 0) {
String[] portRangeStrArray = mediaServerItem.getRtpPortRange().split(","); String[] portRangeStrArray = mediaServerItem.getSendRtpPortRange().split(",");
portRangeArray[0] = Integer.parseInt(portRangeStrArray[0]); portRangeArray[0] = Integer.parseInt(portRangeStrArray[0]);
portRangeArray[1] = Integer.parseInt(portRangeStrArray[1]); portRangeArray[1] = Integer.parseInt(portRangeStrArray[1]);
} }
@ -229,7 +237,9 @@ public class ZLMRTPServerFactory {
*/ */
public int totalReaderCount(MediaServerItem mediaServerItem, String app, String streamId) { public int totalReaderCount(MediaServerItem mediaServerItem, String app, String streamId) {
JSONObject mediaInfo = zlmresTfulUtils.getMediaInfo(mediaServerItem, app, "rtmp", streamId); JSONObject mediaInfo = zlmresTfulUtils.getMediaInfo(mediaServerItem, app, "rtmp", streamId);
if (mediaInfo == null) return 0; if (mediaInfo == null) {
return 0;
}
return mediaInfo.getInteger("totalReaderCount"); return mediaInfo.getInteger("totalReaderCount");
} }

6
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRunner.java

@ -108,8 +108,10 @@ public class ZLMRunner implements CommandLineRunner {
} }
public ZLMServerConfig getMediaServerConfig(MediaServerItem mediaServerItem) { public ZLMServerConfig getMediaServerConfig(MediaServerItem mediaServerItem) {
if (startGetMedia == null) return null; if (startGetMedia == null) { return null;}
if ( startGetMedia.get(mediaServerItem.getId()) == null || !startGetMedia.get(mediaServerItem.getId())) return null; if ( startGetMedia.get(mediaServerItem.getId()) == null || !startGetMedia.get(mediaServerItem.getId())) {
return null;
}
JSONObject responseJSON = zlmresTfulUtils.getMediaServerConfig(mediaServerItem); JSONObject responseJSON = zlmresTfulUtils.getMediaServerConfig(mediaServerItem);
ZLMServerConfig ZLMServerConfig = null; ZLMServerConfig ZLMServerConfig = null;
if (responseJSON != null) { if (responseJSON != null) {

29
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/MediaServerItem.java

@ -41,14 +41,20 @@ public class MediaServerItem{
private boolean rtpEnable; private boolean rtpEnable;
private boolean status;
private String rtpPortRange; private String rtpPortRange;
private String sendRtpPortRange;
private int recordAssistPort; private int recordAssistPort;
private String createTime; private String createTime;
private String updateTime; private String updateTime;
private String lastKeepaliveTime;
private boolean defaultServer; private boolean defaultServer;
private SsrcConfig ssrcConfig; private SsrcConfig ssrcConfig;
@ -82,6 +88,7 @@ public class MediaServerItem{
secret = zlmServerConfig.getApiSecret(); secret = zlmServerConfig.getApiSecret();
streamNoneReaderDelayMS = zlmServerConfig.getGeneralStreamNoneReaderDelayMS(); streamNoneReaderDelayMS = zlmServerConfig.getGeneralStreamNoneReaderDelayMS();
rtpEnable = false; // 默认使用单端口;直到用户自己设置开启多端口 rtpEnable = false; // 默认使用单端口;直到用户自己设置开启多端口
rtpPortRange = "30000,30500"; // 默认使用30000,30500作为级联时发送流的端口号
recordAssistPort = 0; // 默认关闭 recordAssistPort = 0; // 默认关闭
} }
@ -278,5 +285,27 @@ public class MediaServerItem{
this.currentPort = currentPort; this.currentPort = currentPort;
} }
public boolean isStatus() {
return status;
}
public void setStatus(boolean status) {
this.status = status;
}
public String getLastKeepaliveTime() {
return lastKeepaliveTime;
}
public void setLastKeepaliveTime(String lastKeepaliveTime) {
this.lastKeepaliveTime = lastKeepaliveTime;
}
public String getSendRtpPortRange() {
return sendRtpPortRange;
}
public void setSendRtpPortRange(String sendRtpPortRange) {
this.sendRtpPortRange = sendRtpPortRange;
}
} }

7
src/main/java/com/genersoft/iot/vmp/service/IMediaServerService.java

@ -4,6 +4,7 @@ import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.media.zlm.ZLMServerConfig; 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.MediaServerItem;
import com.genersoft.iot.vmp.service.bean.SSRCInfo; import com.genersoft.iot.vmp.service.bean.SSRCInfo;
import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
import java.util.List; import java.util.List;
@ -49,7 +50,11 @@ public interface IMediaServerService {
void clearMediaServerForOnline(); void clearMediaServerForOnline();
void add(MediaServerItem mediaSerItem); WVPResult<String> add(MediaServerItem mediaSerItem);
void resetOnlineServerItem(MediaServerItem serverItem); void resetOnlineServerItem(MediaServerItem serverItem);
WVPResult<MediaServerItem> checkMediaServer(String ip, int port, String secret);
boolean checkMediaRecordServer(String ip, int port);
} }

166
src/main/java/com/genersoft/iot/vmp/service/impl/MediaServerServiceImpl.java

@ -1,5 +1,6 @@
package com.genersoft.iot.vmp.service.impl; package com.genersoft.iot.vmp.service.impl;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import com.genersoft.iot.vmp.common.VideoManagerConstants; import com.genersoft.iot.vmp.common.VideoManagerConstants;
@ -14,10 +15,11 @@ 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.MediaServerItem;
import com.genersoft.iot.vmp.service.IMediaServerService; import com.genersoft.iot.vmp.service.IMediaServerService;
import com.genersoft.iot.vmp.service.bean.SSRCInfo; import com.genersoft.iot.vmp.service.bean.SSRCInfo;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import com.genersoft.iot.vmp.storager.dao.MediaServerMapper; import com.genersoft.iot.vmp.storager.dao.MediaServerMapper;
import com.genersoft.iot.vmp.utils.redis.JedisUtil; import com.genersoft.iot.vmp.utils.redis.JedisUtil;
import com.genersoft.iot.vmp.utils.redis.RedisUtil; import com.genersoft.iot.vmp.utils.redis.RedisUtil;
import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
import okhttp3.*;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@ -56,9 +58,6 @@ public class MediaServerServiceImpl implements IMediaServerService, CommandLineR
@Autowired @Autowired
private MediaServerMapper mediaServerMapper; private MediaServerMapper mediaServerMapper;
@Autowired
private IRedisCatchStorage redisCatchStorage;
@Autowired @Autowired
private VideoStreamSessionManager streamSession; private VideoStreamSessionManager streamSession;
@ -97,7 +96,9 @@ public class MediaServerServiceImpl implements IMediaServerService, CommandLineR
@Override @Override
public SSRCInfo openRTPServer(MediaServerItem mediaServerItem, String streamId) { public SSRCInfo openRTPServer(MediaServerItem mediaServerItem, String streamId) {
if (mediaServerItem == null || mediaServerItem.getId() == null) return null; if (mediaServerItem == null || mediaServerItem.getId() == null) {
return null;
}
// 获取mediaServer可用的ssrc // 获取mediaServer可用的ssrc
String key = VideoManagerConstants.MEDIA_SERVER_PREFIX + mediaServerItem.getId(); String key = VideoManagerConstants.MEDIA_SERVER_PREFIX + mediaServerItem.getId();
@ -107,7 +108,9 @@ public class MediaServerServiceImpl implements IMediaServerService, CommandLineR
return null; return null;
}else { }else {
String ssrc = ssrcConfig.getPlaySsrc(); String ssrc = ssrcConfig.getPlaySsrc();
if (streamId == null) streamId = String.format("%08x", Integer.parseInt(ssrc)).toUpperCase(); if (streamId == null) {
streamId = String.format("%08x", Integer.parseInt(ssrc)).toUpperCase();
}
int rtpServerPort = mediaServerItem.getRtpProxyPort(); int rtpServerPort = mediaServerItem.getRtpProxyPort();
if (mediaServerItem.isRtpEnable()) { if (mediaServerItem.isRtpEnable()) {
rtpServerPort = zlmrtpServerFactory.createRTPServer(mediaServerItem, streamId); rtpServerPort = zlmrtpServerFactory.createRTPServer(mediaServerItem, streamId);
@ -131,7 +134,9 @@ public class MediaServerServiceImpl implements IMediaServerService, CommandLineR
@Override @Override
public void releaseSsrc(MediaServerItem mediaServerItem, String ssrc) { public void releaseSsrc(MediaServerItem mediaServerItem, String ssrc) {
if (mediaServerItem == null || ssrc == null) return; if (mediaServerItem == null || ssrc == null) {
return;
}
SsrcConfig ssrcConfig = mediaServerItem.getSsrcConfig(); SsrcConfig ssrcConfig = mediaServerItem.getSsrcConfig();
ssrcConfig.releaseSsrc(ssrc); ssrcConfig.releaseSsrc(ssrc);
mediaServerItem.setSsrcConfig(ssrcConfig); mediaServerItem.setSsrcConfig(ssrcConfig);
@ -141,7 +146,6 @@ public class MediaServerServiceImpl implements IMediaServerService, CommandLineR
/** /**
* zlm 重启后重置他的推流信息 TODO 给正在使用的设备发送停止命令 * zlm 重启后重置他的推流信息 TODO 给正在使用的设备发送停止命令
* @param mediaServerItem
*/ */
@Override @Override
public void clearRTPServer(MediaServerItem mediaServerItem) { public void clearRTPServer(MediaServerItem mediaServerItem) {
@ -174,9 +178,15 @@ public class MediaServerServiceImpl implements IMediaServerService, CommandLineR
public List<MediaServerItem> getAll() { public List<MediaServerItem> getAll() {
List<MediaServerItem> result = new ArrayList<>(); List<MediaServerItem> result = new ArrayList<>();
List<Object> mediaServerKeys = redisUtil.scan(String.format("%S*", VideoManagerConstants.MEDIA_SERVER_PREFIX)); List<Object> mediaServerKeys = redisUtil.scan(String.format("%S*", VideoManagerConstants.MEDIA_SERVER_PREFIX));
for (int i = 0; i < mediaServerKeys.size(); i++) { String onlineKey = VideoManagerConstants.MEDIA_SERVERS_ONLINE_PREFIX;
String key = (String) mediaServerKeys.get(i); for (Object mediaServerKey : mediaServerKeys) {
result.add((MediaServerItem)redisUtil.get(key)); String key = (String) mediaServerKey;
MediaServerItem mediaServerItem = (MediaServerItem) redisUtil.get(key);
// 检查状态
if (redisUtil.zScore(onlineKey, mediaServerItem.getId()) != null) {
mediaServerItem.setStatus(true);
}
result.add(mediaServerItem);
} }
return result; return result;
} }
@ -208,7 +218,9 @@ public class MediaServerServiceImpl implements IMediaServerService, CommandLineR
*/ */
@Override @Override
public MediaServerItem getOne(String mediaServerId) { public MediaServerItem getOne(String mediaServerId) {
if (mediaServerId == null) return null; if (mediaServerId == null) {
return null;
}
String key = VideoManagerConstants.MEDIA_SERVER_PREFIX + mediaServerId; String key = VideoManagerConstants.MEDIA_SERVER_PREFIX + mediaServerId;
return (MediaServerItem)redisUtil.get(key); return (MediaServerItem)redisUtil.get(key);
} }
@ -225,8 +237,34 @@ public class MediaServerServiceImpl implements IMediaServerService, CommandLineR
} }
@Override @Override
public void add(MediaServerItem mediaSerItem) { public WVPResult<String> add(MediaServerItem mediaServerItem) {
mediaServerMapper.add(mediaSerItem); WVPResult<String> result = new WVPResult<>();
mediaServerItem.setCreateTime(this.format.format(System.currentTimeMillis()));
mediaServerItem.setUpdateTime(this.format.format(System.currentTimeMillis()));
JSONObject responseJSON = zlmresTfulUtils.getMediaServerConfig(mediaServerItem);
if (responseJSON != null) {
JSONArray data = responseJSON.getJSONArray("data");
if (data != null && data.size() > 0) {
ZLMServerConfig zlmServerConfig= JSON.parseObject(JSON.toJSONString(data.get(0)), ZLMServerConfig.class);
if (mediaServerMapper.queryOne(zlmServerConfig.getGeneralMediaServerId()) != null) {
result.setCode(-1);
result.setMsg("保存失败,媒体服务ID [ " + zlmServerConfig.getGeneralMediaServerId() + " ] 已存在,请修改媒体服务器配置");
return result;
}
zlmServerConfig.setIp(mediaServerItem.getIp());
handLeZLMServerConfig(zlmServerConfig);
result.setCode(0);
result.setMsg("success");
}else {
result.setCode(-1);
result.setMsg("连接失败");
}
}else {
result.setCode(-1);
result.setMsg("连接失败");
}
return result;
} }
/** /**
@ -249,13 +287,27 @@ public class MediaServerServiceImpl implements IMediaServerService, CommandLineR
// docker部署不会使用zlm配置的端口号不是默认的则不做更新, 配置修改需要自行修改server配置; // docker部署不会使用zlm配置的端口号不是默认的则不做更新, 配置修改需要自行修改server配置;
MediaServerItem serverItemFromConfig = mediaConfig.getMediaSerItem(); MediaServerItem serverItemFromConfig = mediaConfig.getMediaSerItem();
serverItemFromConfig.setId(zlmServerConfig.getGeneralMediaServerId()); serverItemFromConfig.setId(zlmServerConfig.getGeneralMediaServerId());
if (mediaConfig.getHttpPort() == 0) serverItemFromConfig.setHttpPort(zlmServerConfig.getHttpPort()); if (mediaConfig.getHttpPort() == 0) {
if (mediaConfig.getHttpSSlPort() == 0) serverItemFromConfig.setHttpSSlPort(zlmServerConfig.getHttpSSLport()); serverItemFromConfig.setHttpPort(zlmServerConfig.getHttpPort());
if (mediaConfig.getRtmpPort() == 0) serverItemFromConfig.setRtmpPort(zlmServerConfig.getRtmpPort()); }
if (mediaConfig.getRtmpSSlPort() == 0) serverItemFromConfig.setRtmpSSlPort(zlmServerConfig.getRtmpSslPort()); if (mediaConfig.getHttpSSlPort() == 0) {
if (mediaConfig.getRtspPort() == 0) serverItemFromConfig.setRtspPort(zlmServerConfig.getRtspPort()); serverItemFromConfig.setHttpSSlPort(zlmServerConfig.getHttpSSLport());
if (mediaConfig.getRtspSSLPort() == 0) serverItemFromConfig.setRtspSSLPort(zlmServerConfig.getRtspSSlport()); }
if (mediaConfig.getRtpProxyPort() == 0) serverItemFromConfig.setRtpProxyPort(zlmServerConfig.getRtpProxyPort()); if (mediaConfig.getRtmpPort() == 0) {
serverItemFromConfig.setRtmpPort(zlmServerConfig.getRtmpPort());
}
if (mediaConfig.getRtmpSSlPort() == 0) {
serverItemFromConfig.setRtmpSSlPort(zlmServerConfig.getRtmpSslPort());
}
if (mediaConfig.getRtspPort() == 0) {
serverItemFromConfig.setRtspPort(zlmServerConfig.getRtspPort());
}
if (mediaConfig.getRtspSSLPort() == 0) {
serverItemFromConfig.setRtspSSLPort(zlmServerConfig.getRtspSSlport());
}
if (mediaConfig.getRtpProxyPort() == 0) {
serverItemFromConfig.setRtpProxyPort(zlmServerConfig.getRtpProxyPort());
}
if (serverItem != null){ if (serverItem != null){
mediaServerMapper.delDefault(); mediaServerMapper.delDefault();
mediaServerMapper.add(serverItemFromConfig); mediaServerMapper.add(serverItemFromConfig);
@ -319,9 +371,10 @@ public class MediaServerServiceImpl implements IMediaServerService, CommandLineR
@Override @Override
public void addCount(String mediaServerId) { public void addCount(String mediaServerId) {
if (mediaServerId == null) return; if (mediaServerId == null) {
return;
}
String key = VideoManagerConstants.MEDIA_SERVERS_ONLINE_PREFIX; String key = VideoManagerConstants.MEDIA_SERVERS_ONLINE_PREFIX;
Double aDouble = redisUtil.zScore(key, mediaServerId);
redisUtil.zIncrScore(key, mediaServerId, 1); redisUtil.zIncrScore(key, mediaServerId, 1);
} }
@ -399,4 +452,71 @@ public class MediaServerServiceImpl implements IMediaServerService, CommandLineR
} }
@Override
public WVPResult<MediaServerItem> checkMediaServer(String ip, int port, String secret) {
WVPResult<MediaServerItem> result = new WVPResult<>();
if (mediaServerMapper.queryOneByHostAndPort(ip, port) != null) {
result.setCode(-1);
result.setMsg("此连接已存在");
return result;
}
MediaServerItem mediaServerItem = new MediaServerItem();
mediaServerItem.setIp(ip);
mediaServerItem.setHttpPort(port);
mediaServerItem.setSecret(secret);
JSONObject responseJSON = zlmresTfulUtils.getMediaServerConfig(mediaServerItem);
if (responseJSON == null) {
result.setCode(-1);
result.setMsg("连接失败");
return result;
}
JSONArray data = responseJSON.getJSONArray("data");
ZLMServerConfig zlmServerConfig = JSON.parseObject(JSON.toJSONString(data.get(0)), ZLMServerConfig.class);
if (zlmServerConfig == null) {
result.setCode(-1);
result.setMsg("读取配置失败");
return result;
}
if (mediaServerMapper.queryOne(zlmServerConfig.getGeneralMediaServerId()) != null) {
result.setCode(-1);
result.setMsg("媒体服务ID [" + zlmServerConfig.getGeneralMediaServerId() + " ] 已存在,请修改媒体服务器配置");
return result;
}
mediaServerItem.setHttpSSlPort(zlmServerConfig.getHttpPort());
mediaServerItem.setRtmpPort(zlmServerConfig.getRtmpPort());
mediaServerItem.setRtmpSSlPort(zlmServerConfig.getRtmpSslPort());
mediaServerItem.setRtspPort(zlmServerConfig.getRtspPort());
mediaServerItem.setRtspSSLPort(zlmServerConfig.getRtspSSlport());
mediaServerItem.setRtpProxyPort(zlmServerConfig.getRtpProxyPort());
mediaServerItem.setStreamIp(ip);
mediaServerItem.setHookIp(sipConfig.getIp());
mediaServerItem.setSdpIp(ip);
mediaServerItem.setStreamNoneReaderDelayMS(zlmServerConfig.getGeneralStreamNoneReaderDelayMS());
result.setCode(0);
result.setMsg("成功");
result.setData(mediaServerItem);
return result;
}
@Override
public boolean checkMediaRecordServer(String ip, int port) {
boolean result = false;
OkHttpClient client = new OkHttpClient();
String url = String.format("http://%s:%s/index/api/record", ip, port);
FormBody.Builder builder = new FormBody.Builder();
Request request = new Request.Builder()
.get()
.url(url)
.build();
try {
Response response = client.newCall(request).execute();
if (response != null) {
result = true;
}
} catch (Exception e) {}
return result;
}
} }

3
src/main/java/com/genersoft/iot/vmp/storager/dao/MediaServerMapper.java

@ -32,6 +32,7 @@ public interface MediaServerMapper {
"streamNoneReaderDelayMS, " + "streamNoneReaderDelayMS, " +
"rtpEnable, " + "rtpEnable, " +
"rtpPortRange, " + "rtpPortRange, " +
"sendRtpPortRange, " +
"recordAssistPort, " + "recordAssistPort, " +
"defaultServer, " + "defaultServer, " +
"createTime, " + "createTime, " +
@ -55,6 +56,7 @@ public interface MediaServerMapper {
"${streamNoneReaderDelayMS}, " + "${streamNoneReaderDelayMS}, " +
"${rtpEnable}, " + "${rtpEnable}, " +
"'${rtpPortRange}', " + "'${rtpPortRange}', " +
"'${sendRtpPortRange}', " +
"${recordAssistPort}, " + "${recordAssistPort}, " +
"${defaultServer}, " + "${defaultServer}, " +
"'${createTime}', " + "'${createTime}', " +
@ -79,6 +81,7 @@ public interface MediaServerMapper {
"<if test=\"streamNoneReaderDelayMS != null\">, streamNoneReaderDelayMS=${streamNoneReaderDelayMS}</if>" + "<if test=\"streamNoneReaderDelayMS != null\">, streamNoneReaderDelayMS=${streamNoneReaderDelayMS}</if>" +
"<if test=\"rtpEnable != null\">, rtpEnable=${rtpEnable}</if>" + "<if test=\"rtpEnable != null\">, rtpEnable=${rtpEnable}</if>" +
"<if test=\"rtpPortRange != null\">, rtpPortRange='${rtpPortRange}'</if>" + "<if test=\"rtpPortRange != null\">, rtpPortRange='${rtpPortRange}'</if>" +
"<if test=\"sendRtpPortRange != null\">, sendRtpPortRange='${sendRtpPortRange}'</if>" +
"<if test=\"secret != null\">, secret='${secret}'</if>" + "<if test=\"secret != null\">, secret='${secret}'</if>" +
"<if test=\"recordAssistPort != null\">, recordAssistPort=${recordAssistPort}</if>" + "<if test=\"recordAssistPort != null\">, recordAssistPort=${recordAssistPort}</if>" +
"WHERE id='${id}'"+ "WHERE id='${id}'"+

60
src/main/java/com/genersoft/iot/vmp/vmanager/server/ServerController.java

@ -57,7 +57,9 @@ public class ServerController {
@ApiOperation("流媒体服务列表") @ApiOperation("流媒体服务列表")
@GetMapping(value = "/media_server/list") @GetMapping(value = "/media_server/list")
@ResponseBody @ResponseBody
public WVPResult<List<MediaServerItem>> getMediaServerList(){ public WVPResult<List<MediaServerItem>> getMediaServerList(boolean detail){
List<MediaServerItem> all = mediaServerService.getAll();
WVPResult<List<MediaServerItem>> result = new WVPResult<>(); WVPResult<List<MediaServerItem>> result = new WVPResult<>();
result.setCode(0); result.setCode(0);
result.setMsg("success"); result.setMsg("success");
@ -87,6 +89,60 @@ public class ServerController {
return result; return result;
} }
@ApiOperation("测试流媒体服务")
@ApiImplicitParams({
@ApiImplicitParam(name="ip", value = "流媒体服务IP", dataTypeClass = String.class),
@ApiImplicitParam(name="port", value = "流媒体服务HTT端口", dataTypeClass = Integer.class),
@ApiImplicitParam(name="secret", value = "流媒体服务secret", dataTypeClass = String.class),
})
@GetMapping(value = "/media_server/check")
@ResponseBody
public WVPResult<MediaServerItem> checkMediaServer(@RequestParam String ip, @RequestParam int port, @RequestParam String secret){
return mediaServerService.checkMediaServer(ip, port, secret);
}
@ApiOperation("测试流媒体录像管理服务")
@ApiImplicitParams({
@ApiImplicitParam(name="ip", value = "流媒体服务IP", dataTypeClass = String.class),
@ApiImplicitParam(name="port", value = "流媒体服务HTT端口", dataTypeClass = Integer.class),
@ApiImplicitParam(name="secret", value = "流媒体服务secret", dataTypeClass = String.class),
})
@GetMapping(value = "/media_server/record/check")
@ResponseBody
public WVPResult<String> checkMediaRecordServer(@RequestParam String ip, @RequestParam int port){
boolean checkResult = mediaServerService.checkMediaRecordServer(ip, port);
WVPResult<String> result = new WVPResult<>();
if (checkResult) {
result.setCode(0);
result.setMsg("success");
}else {
result.setCode(-1);
result.setMsg("连接失败");
}
return result;
}
@ApiOperation("保存流媒体服务")
@ApiImplicitParams({
@ApiImplicitParam(name="mediaServerItem", value = "流媒体信息", dataTypeClass = MediaServerItem.class)
})
@PostMapping(value = "/media_server/save")
@ResponseBody
public WVPResult<String> checkMediaServer(@RequestBody MediaServerItem mediaServerItem){
if (mediaServerService.getOne(mediaServerItem.getId()) != null) {
mediaServerService.update(mediaServerItem);
}else {
return mediaServerService.add(mediaServerItem);
}
WVPResult<String> result = new WVPResult<>();
result.setCode(0);
result.setMsg("success");
return result;
}
@ApiOperation("重启服务") @ApiOperation("重启服务")
@GetMapping(value = "/restart") @GetMapping(value = "/restart")
@ResponseBody @ResponseBody
@ -155,6 +211,8 @@ public class ServerController {
case "base": case "base":
jsonObject.put("base", userSetup); jsonObject.put("base", userSetup);
break; break;
default:
break;
} }
} }
result.setData(jsonObject); result.setData(jsonObject);

2
src/main/resources/all-application.yml

@ -119,6 +119,8 @@ media:
enable: true enable: true
# [可选] 在此范围内选择端口用于媒体流传输, # [可选] 在此范围内选择端口用于媒体流传输,
port-range: 30000,30500 # 端口范围 port-range: 30000,30500 # 端口范围
# [可选] 国标级联在此范围内选择端口发送媒体流,
send-port-range: 30000,30500 # 端口范围
# 录像辅助服务, 部署此服务可以实现zlm录像的管理与下载, 0 表示不使用 # 录像辅助服务, 部署此服务可以实现zlm录像的管理与下载, 0 表示不使用
record-assist-port: 0 record-assist-port: 0

2
src/main/resources/application-dev.yml

@ -63,6 +63,8 @@ media:
enable: true enable: true
# [可选] 在此范围内选择端口用于媒体流传输, # [可选] 在此范围内选择端口用于媒体流传输,
port-range: 30000,30500 # 端口范围 port-range: 30000,30500 # 端口范围
# [可选] 国标级联在此范围内选择端口发送媒体流,
send-port-range: 30000,30500 # 端口范围
# 录像辅助服务, 部署此服务可以实现zlm录像的管理与下载, 0 表示不使用 # 录像辅助服务, 部署此服务可以实现zlm录像的管理与下载, 0 表示不使用
record-assist-port: 0 record-assist-port: 0

BIN
src/main/resources/wvp.sqlite

Binary file not shown.

1
web_src/build/webpack.base.conf.js

@ -27,6 +27,7 @@ module.exports = {
alias: { alias: {
'vue$': 'vue/dist/vue.esm.js', 'vue$': 'vue/dist/vue.esm.js',
'@': resolve('src'), '@': resolve('src'),
'@static': resolve('static'),
} }
}, },
module: { module: {

BIN
web_src/src/assets/zlm-log.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

2
web_src/src/components/CloudRecord.vue

@ -111,7 +111,7 @@
}, },
getMediaServerList: function (){ getMediaServerList: function (){
let that = this; let that = this;
that.mediaServerObj.getMediaServerList((data)=>{ that.mediaServerObj.getOnlineMediaServerList((data)=>{
that.mediaServerList = data.data; that.mediaServerList = data.data;
if (that.mediaServerList.length > 0) { if (that.mediaServerList.length > 0) {
that.mediaServerId = that.mediaServerList[0].id that.mediaServerId = that.mediaServerList[0].id

2
web_src/src/components/DeviceList.vue

@ -60,7 +60,7 @@
<el-button-group> <el-button-group>
<el-button size="mini" icon="el-icon-video-camera-solid" v-bind:disabled="scope.row.online==0" type="primary" @click="showChannelList(scope.row)">通道</el-button> <el-button size="mini" icon="el-icon-video-camera-solid" v-bind:disabled="scope.row.online==0" type="primary" @click="showChannelList(scope.row)">通道</el-button>
<el-button size="mini" icon="el-icon-location" v-bind:disabled="scope.row.online==0" type="primary" @click="showDevicePosition(scope.row)">定位</el-button> <el-button size="mini" icon="el-icon-location" v-bind:disabled="scope.row.online==0" type="primary" @click="showDevicePosition(scope.row)">定位</el-button>
<el-button size="mini" icon="el-icon-delete" type="primary" @click="edit(scope.row)">编辑</el-button> <el-button size="mini" icon="el-icon-edit" type="primary" @click="edit(scope.row)">编辑</el-button>
<el-button size="mini" icon="el-icon-delete" type="danger" v-if="scope.row.online==0" @click="deleteDevice(scope.row)">删除</el-button> <el-button size="mini" icon="el-icon-delete" type="danger" v-if="scope.row.online==0" @click="deleteDevice(scope.row)">删除</el-button>
</el-button-group> </el-button-group>
</template> </template>

159
web_src/src/components/MediaServerManger.vue

@ -0,0 +1,159 @@
<template>
<div id="mediaServerManger">
<el-container>
<el-header>
<uiHeader></uiHeader>
</el-header>
<el-main id="msMain">
<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>
<div style="background-color: #FFFFFF; margin-bottom: 1rem; position: relative; padding: 0.5rem; text-align: left;font-size: 14px;">
<el-button icon="el-icon-plus" size="mini" style="margin-right: 1rem;" type="primary" @click="add">添加节点</el-button>
</div>
<el-row :gutter="12">
<el-col :span="num" v-for="item in mediaServerList" :key="item.id">
<el-card shadow="hover" :body-style="{ padding: '0px'}" class="server-card">
<div class="card-img-zlm"></div>
<div style="padding: 14px;text-align: left">
<span style="font-size: 16px">{{item.id}}</span>
<div style="margin-top: 13px; line-height: 12px; ">
<span style="font-size: 14px; color: #999; margin-top: 5px">创建时间 {{item.createTime}}</span>
<el-button icon="el-icon-edit" style="padding: 0;float: right;" type="text" @click="edit(item)">编辑</el-button>
</div>
</div>
<i v-if="item.status" class="iconfont icon-online server-card-status-online" title="在线"></i>
<i v-if="!item.status" class="iconfont icon-online server-card-status-offline" title="离线"></i>
</el-card>
</el-col>
</el-row>
<mediaServerEdit ref="mediaServerEdit" ></mediaServerEdit>
</el-main>
</el-container>
</div>
</template>
<script>
import uiHeader from './UiHeader.vue'
import MediaServer from './service/MediaServer'
import mediaServerEdit from './dialog/MediaServerEdit'
export default {
name: 'mediaServerManger',
components: {
uiHeader,mediaServerEdit
},
data() {
return {
mediaServerObj : new MediaServer(),
mediaServerList: [], //
winHeight: window.innerHeight - 200,
updateLooper: false,
currentPage:1,
count:15,
num: this.getNumberByWidth(),
total:0,
};
},
computed: {
},
mounted() {
this.initData();
this.updateLooper = setInterval(this.initData, 2000);
},
destroyed() {
clearTimeout(this.updateLooper);
},
methods: {
initData: function() {
this.getServerList()
},
currentChange: function(val){
this.currentPage = val;
this.getServerList();
},
handleSizeChange: function(val){
this.count = val;
this.getServerList();
},
getServerList: function(){
this.mediaServerObj.getMediaServerList((data)=>{
this.mediaServerList = data.data;
})
},
add: function (){
this.$refs.mediaServerEdit.openDialog(null, this.initData)
},
edit: function (row){
this.$refs.mediaServerEdit.openDialog(row, this.initData)
},
getNumberByWidth(){
let candidateNums = [1, 2, 3, 4, 6, 8, 12, 24]
let clientWidth = window.innerWidth - 30;
let interval = 20;
let itemWidth = 360;
let num = (clientWidth + interval)/(itemWidth + interval)
let result = Math.ceil(24/num);
let resultVal = 24;
for (let i = 0; i < candidateNums.length; i++) {
let value = candidateNums[i]
if (i + 1 >= candidateNums.length) {
return 24;
}
if (value <= result && candidateNums[i + 1] > result ) {
return value;
}
}
console.log("aadada: "+ resultVal)
return resultVal;
},
dateFormat: function(/** timestamp=0 **/) {
var ts = arguments[0] || 0;
var t,y,m,d,h,i,s;
t = ts ? new Date(ts*1000) : new Date();
y = t.getFullYear();
m = t.getMonth()+1;
d = t.getDate();
h = t.getHours();
i = t.getMinutes();
s = t.getSeconds();
//
return y+'-'+(m<10?'0'+m:m)+'-'+(d<10?'0'+d:d)+' '+(h<10?'0'+h:h)+':'+(i<10?'0'+i:i)+':'+(s<10?'0'+s:s);
}
}
};
</script>
<style>
.server-card{
position: relative;
margin-bottom: 20px;
}
.card-img-zlm{
width: 200px; height: 200px;
background: url('~@static/images/zlm-logo.png') no-repeat center;
background-position: center;
background-size: contain;
margin: 0 auto;
}
.server-card-status-online{
position: absolute;
right: 20px;
top: 20px;
color: #3caf36;
font-size: 18px;
}
.server-card-status-offline{
position: absolute;
right: 20px;
top: 20px;
color: #808080;
font-size: 18px;
}
.server-card:hover {
border: 1px solid #adadad;
}
</style>

1
web_src/src/components/UiHeader.vue

@ -6,6 +6,7 @@
<el-menu-item index="/pushVideoList">推流列表</el-menu-item> <el-menu-item index="/pushVideoList">推流列表</el-menu-item>
<el-menu-item index="/streamProxyList">拉流代理</el-menu-item> <el-menu-item index="/streamProxyList">拉流代理</el-menu-item>
<el-menu-item index="/cloudRecord">云端录像</el-menu-item> <el-menu-item index="/cloudRecord">云端录像</el-menu-item>
<el-menu-item index="/mediaServerManger">节点管理</el-menu-item>
<el-menu-item index="/parentPlatformList/15/1">国标级联</el-menu-item> <el-menu-item index="/parentPlatformList/15/1">国标级联</el-menu-item>
<el-menu-item @click="openDoc">在线文档</el-menu-item> <el-menu-item @click="openDoc">在线文档</el-menu-item>
<!-- <el-submenu index="/setting">--> <!-- <el-submenu index="/setting">-->

2
web_src/src/components/control.vue

@ -139,7 +139,7 @@ export default {
this.initTable(); this.initTable();
this.updateData(); this.updateData();
this.chartInterval = setInterval(this.updateData, 3000); this.chartInterval = setInterval(this.updateData, 3000);
this.mediaServer.getMediaServerList((data)=>{ this.mediaServer.getOnlineMediaServerList((data)=>{
this.mediaServerList = data.data; this.mediaServerList = data.data;
if (this.mediaServerList && this.mediaServerList.length > 0) { if (this.mediaServerList && this.mediaServerList.length > 0) {
this.mediaServerChoose = this.mediaServerList[0].id this.mediaServerChoose = this.mediaServerList[0].id

368
web_src/src/components/dialog/MediaServerEdit.vue

@ -0,0 +1,368 @@
<template>
<div id="mediaServerEdit" v-loading="isLoging">
<el-dialog
title="媒体节点"
:width="dialogWidth"
top="2rem"
:close-on-click-modal="false"
:visible.sync="showDialog"
:destroy-on-close="true"
@close="close()"
>
<div id="formStep" style="margin-top: 1rem; margin-right: 20px;">
<el-form v-if="currentStep == 1" ref="mediaServerForm" :rules="rules" :model="mediaServerForm" label-width="140px" >
<el-form-item label="IP" prop="ip">
<el-input v-model="mediaServerForm.ip" placeholder="媒体服务IP" clearable></el-input>
</el-form-item>
<el-form-item label="HTTP端口" prop="port">
<el-input v-model="mediaServerForm.httpPort" placeholder="媒体服务HTTP端口" clearable></el-input>
</el-form-item>
<el-form-item label="SECRET" prop="secret">
<el-input v-model="mediaServerForm.secret" placeholder="媒体服务SECRET" clearable></el-input>
</el-form-item>
<el-form-item>
<div style="float: right;">
<el-button type="primary" v-if="currentStep === 1 && serverCheck === 1" @click="next" >下一步</el-button>
<el-button @click="close">取消</el-button>
<el-button type="primary" @click="checkServer" >测试</el-button>
<i v-if="serverCheck === 1" class="el-icon-success" style="color: #3caf36"></i>
<i v-if="serverCheck === -1" class="el-icon-error" style="color: #c80000"></i>
</div>
</el-form-item>
</el-form>
<el-row :gutter="24">
<el-col :span="12">
<el-form v-if="currentStep === 2 || currentStep === 3" ref="mediaServerForm1" :rules="rules" :model="mediaServerForm" label-width="140px" >
<el-form-item label="IP" prop="ip">
<el-input v-if="currentStep === 2" v-model="mediaServerForm.ip" disabled></el-input>
<el-input v-if="currentStep === 3" v-model="mediaServerForm.ip"></el-input>
</el-form-item>
<el-form-item label="HTTP端口" prop="port">
<el-input v-if="currentStep === 2" v-model="mediaServerForm.httpPort" disabled></el-input>
<el-input v-if="currentStep === 3" v-model="mediaServerForm.httpPort"></el-input>
</el-form-item>
<el-form-item label="SECRET" prop="secret">
<el-input v-if="currentStep === 2" v-model="mediaServerForm.secret" disabled></el-input>
<el-input v-if="currentStep === 3" v-model="mediaServerForm.secret"></el-input>
</el-form-item>
<el-form-item label="HOOK IP" prop="ip">
<el-input v-model="mediaServerForm.hookIp" placeholder="媒体服务HOOK_IP" clearable></el-input>
</el-form-item>
<el-form-item label="SDP IP" prop="ip">
<el-input v-model="mediaServerForm.sdpIp" placeholder="媒体服务SDP_IP" clearable></el-input>
</el-form-item>
<el-form-item label="流IP" prop="ip">
<el-input v-model="mediaServerForm.streamIp" placeholder="媒体服务流IP" clearable></el-input>
</el-form-item>
<el-form-item label="HTTPS PORT" prop="port">
<el-input v-model="mediaServerForm.httpSSlPort" placeholder="媒体服务HTTPS_PORT" clearable></el-input>
</el-form-item>
<el-form-item label="RTSP PORT" prop="port">
<el-input v-model="mediaServerForm.rtspPort" placeholder="媒体服务RTSP_PORT" clearable></el-input>
</el-form-item>
<el-form-item label="RTSPS PORT" prop="port">
<el-input v-model="mediaServerForm.rtspSSLPort" placeholder="媒体服务RTSPS_PORT" clearable></el-input>
</el-form-item>
</el-form>
</el-col>
<el-col :span="12">
<el-form v-if="currentStep === 2 || currentStep === 3" ref="mediaServerForm2" :rules="rules" :model="mediaServerForm" label-width="180px" >
<el-form-item label="RTMP PORT" prop="port">
<el-input v-model="mediaServerForm.rtmpPort" placeholder="媒体服务RTMP_PORT" clearable></el-input>
</el-form-item>
<el-form-item label="RTMPS PORT" prop="port">
<el-input v-model="mediaServerForm.rtmpSSlPort" placeholder="媒体服务RTMPS_PORT" clearable></el-input>
</el-form-item>
<el-form-item label="自动配置媒体服务" >
<el-switch v-model="mediaServerForm.autoConfig"></el-switch>
</el-form-item>
<el-form-item label="收流端口模式" >
<el-switch active-text="多端口" inactive-text="单端口" v-model="mediaServerForm.rtpEnable"></el-switch>
</el-form-item>
<el-form-item v-if="!mediaServerForm.rtpEnable" label="收流端口" prop="port">
<el-input v-model.number="mediaServerForm.rtpProxyPort" clearable></el-input>
</el-form-item>
<el-form-item v-if="mediaServerForm.rtpEnable" label="收流端口" prop="port">
<el-input v-model="mediaServerForm.rtpPortRange1" placeholder="起始" clearable style="width: 100px" prop="port"></el-input>
-
<el-input v-model="mediaServerForm.rtpPortRange2" placeholder="终止" clearable style="width: 100px" prop="port"></el-input>
</el-form-item>
<el-form-item label="推流端口" prop="port">
<el-input v-model="mediaServerForm.sendRtpPortRange1" placeholder="起始" clearable style="width: 100px" prop="port"></el-input>
-
<el-input v-model="mediaServerForm.sendRtpPortRange2" placeholder="终止" clearable style="width: 100px" prop="port"></el-input>
</el-form-item>
<el-form-item label="无人观看多久后停止拉流" >
<el-input v-model.number="mediaServerForm.streamNoneReaderDelayMS" clearable></el-input>
</el-form-item>
<el-form-item label="录像管理服务端口" prop="port">
<el-input v-model.number="mediaServerForm.recordAssistPort">
<!-- <el-button v-if="mediaServerForm.recordAssistPort > 0" slot="append" type="primary" @click="checkRecordServer">测试</el-button>-->
<el-button v-if="mediaServerForm.recordAssistPort > 0" class="el-icon-check" slot="append" type="primary" @click="checkRecordServer"></el-button>
</el-input>
<i v-if="recordServerCheck == 1" class="el-icon-success" style="color: #3caf36; position: absolute;top: 14px;"></i>
<i v-if="recordServerCheck == 2" class="el-icon-loading" style="color: #3caf36; position: absolute;top: 14px;"></i>
<i v-if="recordServerCheck === -1" class="el-icon-error" style="color: #c80000; position: absolute;top: 14px;"></i>
</el-form-item>
<el-form-item>
<div style="float: right;">
<el-button type="primary" @click="onSubmit" >提交</el-button>
<el-button @click="close">取消</el-button>
</div>
</el-form-item>
</el-form>
</el-col>
</el-row>
</div>
</el-dialog>
</div>
</template>
<script>
import MediaServer from './../service/MediaServer'
export default {
name: "streamProxyEdit",
props: {},
computed: {},
created() {
this.setDialogWidth()
},
data() {
const isValidIp = (rule, value, callback) => { // IP
var reg = /^(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])$/
console.log(this.mediaServerForm.ip)
if (!reg.test(this.mediaServerForm.ip)) {
return callback(new Error('请输入有效的IP地址'))
} else {
callback()
}
return true
}
const isValidPort = (rule, value, callback) => { // IP
var reg = /^(([0-9]|[1-9]\d{1,3}|[1-5]\d{4}|6[0-5]{2}[0-3][0-5]))$/
if (!reg.test(this.mediaServerForm.httpPort)) {
return callback(new Error('请输入有效的端口号'))
} else {
callback()
}
return true
}
return {
dialogWidth: 0,
defaultWidth: 1000,
listChangeCallback: null,
showDialog: false,
isLoging: false,
dialogLoading: false,
currentStep: 1,
platformList: [],
mediaServer: new MediaServer(),
serverCheck: 0,
recordServerCheck: 0,
mediaServerForm: {
id: "",
ip: "",
autoConfig: true,
hookIp: "",
sdpIp: "",
streamIp: "",
streamNoneReaderDelayMS: "",
secret: "035c73f7-bb6b-4889-a715-d9eb2d1925cc",
httpPort: "",
httpSSlPort: "",
recordAssistPort: "",
rtmpPort: "",
rtmpSSlPort: "",
rtpEnable: false,
rtpPortRange: "",
sendRtpPortRange: "",
rtpPortRange1: "",
rtpPortRange2: "",
sendRtpPortRange1: "",
sendRtpPortRange2: "",
rtpProxyPort: "",
rtspPort: "",
rtspSSLPort: "",
},
rules: {
ip: [{ required: true, validator: isValidIp, message: '请输入有效的IP地址', trigger: 'blur' }],
port: [{ required: true, validator: isValidPort, message: '请输入有效的端口号', trigger: 'blur' }],
secret: [{ required: true, message: "请输入secret", trigger: "blur" }],
timeout_ms: [{ required: true, message: "请输入FFmpeg推流成功超时时间", trigger: "blur" }],
ffmpeg_cmd_key: [{ required: false, message: "请输入FFmpeg命令参数模板(可选)", trigger: "blur" }],
},
};
},
methods: {
setDialogWidth() {
let val = document.body.clientWidth
if (val < this.defaultWidth) {
this.dialogWidth = '100%'
} else {
this.dialogWidth = this.defaultWidth + 'px'
}
},
openDialog: function (param, callback) {
this.showDialog = true;
this.listChangeCallback = callback;
if (param != null) {
this.mediaServerForm = param;
this.currentStep = 3;
if (param.rtpPortRange) {
let rtpPortRange = this.mediaServerForm.rtpPortRange.split(",");
if (rtpPortRange.length > 0) {
this.mediaServerForm["rtpPortRange1"] = rtpPortRange[0]
this.mediaServerForm["rtpPortRange2"] = rtpPortRange[1]
}
}
let sendRtpPortRange = this.mediaServerForm.sendRtpPortRange.split(",");
this.mediaServerForm["sendRtpPortRange1"] = sendRtpPortRange[0]
this.mediaServerForm["sendRtpPortRange2"] = sendRtpPortRange[1]
}
},
checkServer: function() {
let that = this;
that.serverCheck = 0;
that.mediaServer.checkServer(that.mediaServerForm, data =>{
if (data.code === 0) {
if (parseInt(that.mediaServerForm.httpPort) !== parseInt(data.data.httpPort)) {
that.$message({
showClose: true,
message: '如果你正在使用docker部署你的媒体服务,请注意的端口映射。',
type: 'warning',
duration: 0
});
}
let httpPort = that.mediaServerForm.httpPort;
that.mediaServerForm = data.data;
that.mediaServerForm.httpPort = httpPort;
that.mediaServerForm.autoConfig = true;
that.mediaServerForm.sendRtpPortRange1 = 30000
that.mediaServerForm.sendRtpPortRange2 = 30500
that.mediaServerForm.rtpPortRange1 = 30000
that.mediaServerForm.rtpPortRange2 = 30500
that.serverCheck = 1;
}else {
that.serverCheck = -1;
that.$message({
showClose: true,
message: data.msg,
type: "error",
});
}
})
},
next: function (){
this.currentStep = 2;
this.defaultWidth = 900;
this.setDialogWidth();
},
checkRecordServer: function (){
let that = this;
that.recordServerCheck = 2;
if (that.mediaServerForm.recordAssistPort <= 0 || that.mediaServerForm.recordAssistPort > 65535 ) {
that.recordServerCheck = -1;
that.$message({
showClose: true,
message: "端口号应该在-65535之间",
type: "error",
});
return;
}
that.mediaServer.checkRecordServer(that.mediaServerForm, data =>{
if (data.code === 0) {
that.recordServerCheck = 1;
}else {
that.recordServerCheck = -1;
that.$message({
showClose: true,
message: data.msg,
type: "error",
});
}
})
},
onSubmit: function () {
this.dialogLoading = true;
let that = this;
if (this.mediaServerForm.rtpEnable) {
this.mediaServerForm.rtpPortRange = this.mediaServerForm.rtpPortRange1 + "," + this.mediaServerForm.rtpPortRange2;
}
this.mediaServerForm.sendRtpPortRange = this.mediaServerForm.sendRtpPortRange1 + "," + this.mediaServerForm.sendRtpPortRange2;
that.mediaServer.addServer(this.mediaServerForm, data => {
if (data.code === 0) {
that.$message({
showClose: true,
message: "保存成功",
type: "success",
});
if (this.listChangeCallback) this.listChangeCallback();
that.close()
}else {
that.$message({
showClose: true,
message: data.msg,
type: "error",
});
}
})
},
close: function () {
this.showDialog = false;
this.dialogLoading = false;
this.mediaServerForm = {
id: "",
ip: "",
autoConfig: true,
hookIp: "",
sdpIp: "",
streamIp: "",
streamNoneReaderDelayMS: "",
secret: "035c73f7-bb6b-4889-a715-d9eb2d1925cc",
httpPort: "",
httpSSlPort: "",
recordAssistPort: "",
rtmpPort: "",
rtmpSSlPort: "",
rtpEnable: false,
rtpPortRange: "",
sendRtpPortRange: "",
rtpPortRange1: "",
rtpPortRange2: "",
sendRtpPortRange1: "",
sendRtpPortRange2: "",
rtpProxyPort: "",
rtspPort: "",
rtspSSLPort: "",
};
this.listChangeCallback = null
this.currentStep = 1;
},
deviceGBIdExit: async function (deviceGbId) {
var result = false;
var that = this;
await that.$axios({
method: 'post',
url:`/api/platform/exit/${deviceGbId}`
}).then(function (res) {
result = res.data;
}).catch(function (error) {
console.log(error);
});
return result;
},
checkExpires: function() {
if (this.platform.enable && this.platform.expires == "0") {
this.platform.expires = "300";
}
}
},
};
</script>

2
web_src/src/components/dialog/StreamProxyEdit.vue

@ -203,7 +203,7 @@ export default {
}).catch(function (error) { }).catch(function (error) {
console.log(error); console.log(error);
}); });
this.mediaServer.getMediaServerList((data)=>{ this.mediaServer.getOnlineMediaServerList((data)=>{
this.mediaServerList = data; this.mediaServerList = data;
}) })
}, },

2
web_src/src/components/dialog/changePassword.vue

@ -89,7 +89,7 @@ export default {
method: 'post', method: 'post',
url:"/api/user/changePassword", url:"/api/user/changePassword",
params: { params: {
oldpassword: crypto.createHash('md5').update(this.oldPassword, "utf8").digest('hex'), oldPassword: crypto.createHash('md5').update(this.oldPassword, "utf8").digest('hex'),
password: this.newPassword password: this.newPassword
} }
}).then((res)=> { }).then((res)=> {

2
web_src/src/components/dialog/deviceEdit.vue

@ -82,7 +82,7 @@ export default {
}, },
getMediaServerList: function (){ getMediaServerList: function (){
let that = this; let that = this;
that.mediaServerObj.getMediaServerList((data)=>{ that.mediaServerObj.getOnlineMediaServerList((data)=>{
that.mediaServerList = data.data; that.mediaServerList = data.data;
}) })
}, },

55
web_src/src/components/service/MediaServer.js

@ -6,7 +6,7 @@ class MediaServer{
this.$axios = axios; this.$axios = axios;
} }
getMediaServerList(callback){ getOnlineMediaServerList(callback){
this.$axios({ this.$axios({
method: 'get', method: 'get',
url:`/api/server/media_server/online/list`, url:`/api/server/media_server/online/list`,
@ -16,6 +16,16 @@ class MediaServer{
console.log(error); console.log(error);
}); });
} }
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){ getMediaServer(id, callback){
this.$axios({ this.$axios({
@ -27,6 +37,49 @@ class MediaServer{
console.log(error); console.log(error);
}); });
} }
checkServer(param, callback){
this.$axios({
method: 'get',
url:`/api/server/media_server/check`,
params: {
ip: param.ip,
port: param.httpPort,
secret: param.secret
}
}).then(function (res) {
if (typeof (callback) == "function") callback(res.data)
}).catch(function (error) {
console.log(error);
});
}
checkRecordServer(param, callback){
this.$axios({
method: 'get',
url:`/api/server/media_server/record/check`,
params: {
ip: param.ip,
port: param.recordAssistPort
}
}).then(function (res) {
if (typeof (callback) == "function") callback(res.data)
}).catch(function (error) {
console.log(error);
});
}
addServer(param, callback){
this.$axios({
method: 'post',
url:`/api/server/media_server/save`,
data: param
}).then(function (res) {
if (typeof (callback) == "function") callback(res.data)
}).catch(function (error) {
console.log(error);
});
}
} }
export default MediaServer; export default MediaServer;

6
web_src/src/router/index.js

@ -10,6 +10,7 @@ import devicePosition from '../components/devicePosition.vue'
import login from '../components/Login.vue' import login from '../components/Login.vue'
import parentPlatformList from '../components/ParentPlatformList.vue' import parentPlatformList from '../components/ParentPlatformList.vue'
import cloudRecord from '../components/CloudRecord.vue' import cloudRecord from '../components/CloudRecord.vue'
import mediaServerManger from '../components/MediaServerManger.vue'
import test from '../components/test.vue' import test from '../components/test.vue'
import web from '../components/setting/Web.vue' import web from '../components/setting/Web.vue'
import sip from '../components/setting/Sip.vue' import sip from '../components/setting/Sip.vue'
@ -70,6 +71,11 @@ export default new VueRouter({
name: 'cloudRecord', name: 'cloudRecord',
component: cloudRecord, component: cloudRecord,
}, },
{
path: '/mediaServerManger',
name: 'mediaServerManger',
component: mediaServerManger,
},
{ {
path: '/setting/web', path: '/setting/web',
name: 'web', name: 'web',

10
web_src/static/css/iconfont.css

@ -1,8 +1,8 @@
@font-face { @font-face {
font-family: "iconfont"; /* Project id 1291092 */ font-family: "iconfont"; /* Project id 1291092 */
src: url('iconfont.woff2?t=1626163621710') format('woff2'), src: url('iconfont.woff2?t=1631767887536') format('woff2'),
url('iconfont.woff?t=1626163621710') format('woff'), url('iconfont.woff?t=1631767887536') format('woff'),
url('iconfont.ttf?t=1626163621710') format('truetype'); url('iconfont.ttf?t=1631767887536') format('truetype');
} }
.iconfont { .iconfont {
@ -13,6 +13,10 @@
-moz-osx-font-smoothing: grayscale; -moz-osx-font-smoothing: grayscale;
} }
.icon-online:before {
content: "\e600";
}
.icon-xiangqing2:before { .icon-xiangqing2:before {
content: "\e798"; content: "\e798";
} }

BIN
web_src/static/css/iconfont.woff2

Binary file not shown.

BIN
web_src/static/images/zlm-logo.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Loading…
Cancel
Save