Browse Source

增加对zlm使用docker容器的支持

pull/93/head
panlinlin 3 years ago
parent
commit
10ae1bba59
  1. 1
      pom.xml
  2. 42
      src/main/java/com/genersoft/iot/vmp/conf/ApplicationCheckRunner.java
  3. 177
      src/main/java/com/genersoft/iot/vmp/conf/MediaConfig.java
  4. 3
      src/main/java/com/genersoft/iot/vmp/conf/security/WebSecurityConfig.java
  5. 2
      src/main/java/com/genersoft/iot/vmp/gb28181/event/offline/KeepaliveTimeoutListenerForPlatform.java
  6. 26
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java
  7. 4
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java
  8. 6
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/InviteRequestProcessor.java
  9. 14
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/RegisterRequestProcessor.java
  10. 13
      src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHTTPProxyController.java
  11. 25
      src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java
  12. 4
      src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMMediaListManager.java
  13. 17
      src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRESTfulUtils.java
  14. 7
      src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRTPServerFactory.java
  15. 83
      src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRunner.java
  16. 15
      src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMServerConfig.java
  17. 45
      src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMServerManger.java
  18. 4
      src/main/java/com/genersoft/iot/vmp/service/impl/MediaServiceImpl.java
  19. 4
      src/main/java/com/genersoft/iot/vmp/service/impl/StreamProxyServiceImpl.java
  20. 8
      src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java
  21. 14
      src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java
  22. 4
      src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/play/PlayController.java
  23. 24
      src/main/resources/application-dev.yml

1
pom.xml

@ -45,6 +45,7 @@
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.build.timestamp.format>yyyyMMddHHmmss</maven.build.timestamp.format>
<maven-jar-plugin.version>3.1.1</maven-jar-plugin.version>
<!-- 依赖版本 -->
<pagehelper.version>5.2.0</pagehelper.version>

42
src/main/java/com/genersoft/iot/vmp/conf/ApplicationCheckRunner.java

@ -2,6 +2,7 @@ package com.genersoft.iot.vmp.conf;
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.CommandLineRunner;
import org.springframework.core.annotation.Order;
@ -17,46 +18,21 @@ public class ApplicationCheckRunner implements CommandLineRunner {
private Logger logger = LoggerFactory.getLogger("ApplicationCheckRunner");
@Value("${sip.ip}")
private String sipIp;
@Value("${media.ip}")
private String mediaIp;
@Value("${media.wanIp}")
private String mediaWanIp;
@Value("${media.hookIp}")
private String mediaHookIp;
@Value("${media.port}")
private int mediaPort;
@Value("${media.secret}")
private String mediaSecret;
@Value("${media.streamNoneReaderDelayMS}")
private String streamNoneReaderDelayMS;
@Value("${sip.ip}")
private String sipIP;
@Value("${server.port}")
private String serverPort;
@Value("${media.autoConfig}")
private boolean autoConfig;
@Autowired
private MediaConfig mediaConfig;
@Autowired
private SipConfig sipConfig;
@Override
public void run(String... args) throws Exception {
if (sipIP.equals("localhost") || sipIP.equals("127.0.0.1")) {
logger.error("sip.ip不能使用 {} ,请使用类似192.168.1.44这样的来自网卡的IP!!!", sipIP );
if (sipConfig.getSipIp().equals("localhost") || sipConfig.getSipIp().equals("127.0.0.1")) {
logger.error("sip.ip不能使用 {} ,请使用类似192.168.1.44这样的来自网卡的IP!!!", sipConfig.getSipIp() );
System.exit(1);
}
if (mediaIp.equals("localhost") || (mediaIp.equals("127.0.0.1") && mediaWanIp == null)) {
logger.warn("mediaIp.ip使用 {} ,将无法收到网络内其他设备的推流!!!", mediaIp );
if (mediaConfig.getIp().equals("localhost") || (mediaConfig.getIp().equals("127.0.0.1") && mediaConfig.getWanIp() == null)) {
logger.warn("mediaIp.ip使用 {} ,将无法收到网络内其他设备的推流!!!", mediaConfig.getIp() );
}
}

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

@ -0,0 +1,177 @@
package com.genersoft.iot.vmp.conf;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
@Configuration("mediaConfig")
public class MediaConfig {
@Value("${media.ip}")
private String ip;
@Value("${media.wanIp}")
private String wanIp;
@Value("${media.hookIp}")
private String hookIp;
@Value("${media.httpPort}")
private String httpPort;
@Value("${media.httpSSlPort}")
private String httpSSlPort;
@Value("${media.rtmpPort}")
private String rtmpPort;
@Value("${media.rtmpSSlPort}")
private String rtmpSSlPort;
@Value("${media.rtpProxyPort}")
private String rtpProxyPort;
@Value("${media.rtspPort}")
private String rtspPort;
@Value("${media.rtspSSLPort}")
private String rtspSSLPort;
@Value("${media.autoConfig}")
private boolean autoConfig;
@Value("${media.secret}")
private String secret;
@Value("${media.streamNoneReaderDelayMS}")
private String streamNoneReaderDelayMS;
@Value("${media.rtp.enable}")
private boolean rtpEnable;
@Value("${media.rtp.portRange}")
private String rtpPortRange;
public String getIp() {
return ip;
}
public void setIp(String ip) {
this.ip = ip;
}
public String getWanIp() {
return wanIp;
}
public void setWanIp(String wanIp) {
this.wanIp = wanIp;
}
public String getHookIp() {
return hookIp;
}
public void setHookIp(String hookIp) {
this.hookIp = hookIp;
}
public String getHttpPort() {
return httpPort;
}
public void setHttpPort(String httpPort) {
this.httpPort = httpPort;
}
public boolean isAutoConfig() {
return autoConfig;
}
public boolean getAutoConfig() {
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 String getHttpSSlPort() {
return httpSSlPort;
}
public void setHttpSSlPort(String httpSSlPort) {
this.httpSSlPort = httpSSlPort;
}
public String getRtmpPort() {
return rtmpPort;
}
public void setRtmpPort(String rtmpPort) {
this.rtmpPort = rtmpPort;
}
public String getRtmpSSlPort() {
return rtmpSSlPort;
}
public void setRtmpSSlPort(String rtmpSSlPort) {
this.rtmpSSlPort = rtmpSSlPort;
}
public String getRtpProxyPort() {
return rtpProxyPort;
}
public void setRtpProxyPort(String rtpProxyPort) {
this.rtpProxyPort = rtpProxyPort;
}
public String getRtspPort() {
return rtspPort;
}
public void setRtspPort(String rtspPort) {
this.rtspPort = rtspPort;
}
public String getRtspSSLPort() {
return rtspSSLPort;
}
public void setRtspSSLPort(String rtspSSLPort) {
this.rtspSSLPort = rtspSSLPort;
}
}

3
src/main/java/com/genersoft/iot/vmp/conf/security/WebSecurityConfig.java

@ -77,6 +77,7 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
// 可以直接访问的静态数据
web.ignoring()
.antMatchers("/")
.antMatchers("/#/**")
.antMatchers("/static/**")
.antMatchers("/index.html")
.antMatchers("/doc.html") // "/webjars/**", "/swagger-resources/**", "/v3/api-docs/**"
@ -111,7 +112,7 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
http.headers().contentTypeOptions().disable();
http.authorizeRequests()
// 放行接口
.antMatchers("/#/**", "/api/user/login","/index/hook/**").permitAll()
.antMatchers("/api/user/login","/index/hook/**").permitAll()
// 除上面外的所有请求全部需要鉴权认证
.anyRequest().authenticated()
// 异常处理(权限拒绝、登录失效等)

2
src/main/java/com/genersoft/iot/vmp/gb28181/event/offline/KeepaliveTimeoutListenerForPlatform.java

@ -38,7 +38,7 @@ public class KeepaliveTimeoutListenerForPlatform extends KeyExpirationEventMessa
public void onMessage(Message message, byte[] pattern) {
// 获取失效的key
String expiredKey = message.toString();
logger.info(expiredKey);
logger.debug(expiredKey);
if(!expiredKey.startsWith(VideoManagerConstants.PLATFORM_KEEPLIVEKEY_PREFIX)){
logger.debug("收到redis过期监听,但开头不是"+VideoManagerConstants.PLATFORM_KEEPLIVEKEY_PREFIX+",忽略");
return;

26
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java

@ -1,8 +1,6 @@
package com.genersoft.iot.vmp.gb28181.transmit.cmd.impl;
import java.text.ParseException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.sip.*;
import javax.sip.address.SipURI;
@ -10,11 +8,11 @@ import javax.sip.header.CallIdHeader;
import javax.sip.header.ViaHeader;
import javax.sip.message.Request;
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.MediaServerConfig;
import com.genersoft.iot.vmp.conf.MediaConfig;
import com.genersoft.iot.vmp.media.zlm.ZLMServerConfig;
import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe;
import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
@ -82,13 +80,13 @@ public class SIPCommander implements ISIPCommander {
@Autowired
private ZLMRESTfulUtils zlmresTfulUtils;
@Value("${media.rtp.enable}")
private boolean rtpEnable;
@Autowired
private MediaConfig mediaConfig;
@Value("${media.seniorSdp}")
@Value("${userSettings.seniorSdp}")
private boolean seniorSdp;
@Value("${media.autoApplyPlay}")
@Value("${userSettings.autoApplyPlay}")
private boolean autoApplyPlay;
@Value("${userSettings.waitTrack}")
@ -353,20 +351,20 @@ public class SIPCommander implements ISIPCommander {
try {
if (device == null) return;
String ssrc = streamSession.createPlaySsrc();
if (rtpEnable) {
if (mediaConfig.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();
MediaServerConfig mediaInfo = redisCatchStorage.getMediaInfo();
ZLMServerConfig mediaInfo = redisCatchStorage.getMediaInfo();
if (mediaInfo == null) {
logger.warn("点播时发现ZLM尚未连接...");
return;
}
String mediaPort = null;
// 使用动态udp端口
if (rtpEnable) {
if (mediaConfig.isRtpEnable()) {
mediaPort = zlmrtpServerFactory.createRTPServer(streamId) + "";
}else {
mediaPort = mediaInfo.getRtpProxyPort();
@ -470,7 +468,7 @@ public class SIPCommander implements ISIPCommander {
public void playbackStreamCmd(Device device, String channelId, String startTime, String endTime, ZLMHttpHookSubscribe.Event event
, SipSubscribe.Event errorEvent) {
try {
MediaServerConfig mediaInfo = redisCatchStorage.getMediaInfo();
ZLMServerConfig mediaInfo = redisCatchStorage.getMediaInfo();
String ssrc = streamSession.createPlayBackSsrc();
String streamId = String.format("%08x", Integer.parseInt(ssrc)).toUpperCase();
// 添加订阅
@ -495,7 +493,7 @@ public class SIPCommander implements ISIPCommander {
+DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(endTime) +"\r\n");
String mediaPort = null;
// 使用动态udp端口
if (rtpEnable) {
if (mediaConfig.isRtpEnable()) {
mediaPort = zlmrtpServerFactory.createRTPServer(streamId) + "";
}else {
mediaPort = mediaInfo.getRtpProxyPort();
@ -1445,7 +1443,7 @@ public class SIPCommander implements ISIPCommander {
@Override
public void closeRTPServer(Device device, String channelId) {
if (rtpEnable) {
if (mediaConfig.isRtpEnable()) {
String streamId = String.format("gb_play_%s_%s", device.getDeviceId(), channelId);
zlmrtpServerFactory.closeRTPServer(streamId);
}

4
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java

@ -1,5 +1,6 @@
package com.genersoft.iot.vmp.gb28181.transmit.cmd.impl;
import com.genersoft.iot.vmp.conf.MediaConfig;
import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatformCatch;
@ -63,9 +64,6 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform {
@Qualifier(value="udpSipProvider")
private SipProvider udpSipProvider;
@Value("${media.rtp.enable}")
private boolean rtpEnable;
@Override
public boolean register(ParentPlatform parentPlatform, SipSubscribe.Event errorEvent , SipSubscribe.Event okEvent) {
return register(parentPlatform, null, null, errorEvent, okEvent);

6
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/InviteRequestProcessor.java

@ -11,7 +11,7 @@ import javax.sip.header.*;
import javax.sip.message.Request;
import javax.sip.message.Response;
import com.genersoft.iot.vmp.conf.MediaServerConfig;
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;
@ -187,7 +187,7 @@ public class InviteRequestProcessor extends SIPRequestAbstractProcessor {
sendRtpItem.setStatus(1);
redisCatchStorage.updateSendRTPSever(sendRtpItem);
// TODO 添加对tcp的支持
MediaServerConfig mediaInfo = redisCatchStorage.getMediaInfo();
ZLMServerConfig mediaInfo = redisCatchStorage.getMediaInfo();
StringBuffer content = new StringBuffer(200);
content.append("v=0\r\n");
content.append("o="+"00000"+" 0 0 IN IP4 "+mediaInfo.getWanIp()+"\r\n");
@ -246,7 +246,7 @@ public class InviteRequestProcessor extends SIPRequestAbstractProcessor {
sendRtpItem.setStatus(1);
redisCatchStorage.updateSendRTPSever(sendRtpItem);
// TODO 添加对tcp的支持
MediaServerConfig mediaInfo = redisCatchStorage.getMediaInfo();
ZLMServerConfig mediaInfo = redisCatchStorage.getMediaInfo();
StringBuffer content = new StringBuffer(200);
content.append("v=0\r\n");
content.append("o="+"00000"+" 0 0 IN IP4 "+mediaInfo.getWanIp()+"\r\n");

14
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/RegisterRequestProcessor.java

@ -17,7 +17,9 @@ import javax.sip.message.Request;
import javax.sip.message.Response;
import com.genersoft.iot.vmp.gb28181.bean.WvpSipDate;
import gov.nist.javax.sip.RequestEventExt;
import gov.nist.javax.sip.header.SIPDateHeader;
import gov.nist.javax.sip.message.SIPRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;
@ -59,7 +61,9 @@ public class RegisterRequestProcessor extends SIPRequestAbstractProcessor {
@Override
public void process(RequestEvent evt) {
try {
logger.info("收到注册请求,开始处理");
RequestEventExt evtExt = (RequestEventExt)evt;
String requestAddress = evtExt.getRemoteIpAddress() + ":" + evtExt.getRemotePort();
logger.info("[{}] 收到注册请求,开始处理", requestAddress);
Request request = evt.getRequest();
Response response = null;
@ -78,9 +82,9 @@ public class RegisterRequestProcessor extends SIPRequestAbstractProcessor {
if (authorhead == null || !passwordCorrect) {
if (authorhead == null) {
logger.info("未携带授权头 回复401");
logger.info("[{}] 未携带授权头 回复401", requestAddress);
} else if (!passwordCorrect) {
logger.info("密码错误 回复401");
logger.info("[{}] 密码错误 回复401", requestAddress);
}
response = getMessageFactory().createResponse(Response.UNAUTHORIZED, request);
new DigestServerAuthenticationHelper().generateChallenge(getHeaderFactory(), response, sipConfig.getSipDomain());
@ -147,7 +151,7 @@ public class RegisterRequestProcessor extends SIPRequestAbstractProcessor {
// 保存到redis
// 下发catelog查询目录
if (registerFlag == 1 ) {
logger.info("注册成功! deviceId:" + device.getDeviceId());
logger.info("[{}] 注册成功! deviceId:" + device.getDeviceId(), requestAddress);
// boolean exists = storager.exists(device.getDeviceId());
device.setRegisterTimeMillis(System.currentTimeMillis());
storager.updateDevice(device);
@ -158,7 +162,7 @@ public class RegisterRequestProcessor extends SIPRequestAbstractProcessor {
handler.onRegister(device);
//}
} else if (registerFlag == 2) {
logger.info("注销成功! deviceId:" + device.getDeviceId());
logger.info("[{}] 注销成功! deviceId:" + device.getDeviceId(), requestAddress);
publisher.outlineEventPublish(device.getDeviceId(), VideoManagerConstants.EVENT_OUTLINE_UNREGISTER);
}
} catch (SipException | InvalidArgumentException | NoSuchAlgorithmException | ParseException e) {

13
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHTTPProxyController.java

@ -1,6 +1,6 @@
package com.genersoft.iot.vmp.media.zlm;
import com.genersoft.iot.vmp.conf.MediaServerConfig;
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;
@ -18,14 +18,11 @@ public class ZLMHTTPProxyController {
// private final static Logger logger = LoggerFactory.getLogger(ZLMHTTPProxyController.class);
// @Autowired
// private IVideoManagerStorager storager;
@Autowired
private IRedisCatchStorage redisCatchStorage;
@Value("${media.port}")
private int mediaHttpPort;
@Autowired
private MediaConfig mediaConfig;
@ResponseBody
@RequestMapping(value = "/**/**/**", produces = "application/json;charset=UTF-8")
@ -34,10 +31,10 @@ public class ZLMHTTPProxyController {
if (redisCatchStorage.getMediaInfo() == null) {
return "未接入流媒体";
}
MediaServerConfig mediaInfo = redisCatchStorage.getMediaInfo();
ZLMServerConfig mediaInfo = redisCatchStorage.getMediaInfo();
String requestURI = String.format("http://%s:%s%s?%s&%s",
mediaInfo.getLocalIP(),
mediaHttpPort,
mediaConfig.getHttpPort(),
request.getRequestURI().replace("/zlm",""),
mediaInfo.getHookAdminParams(),
request.getQueryString()

25
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java

@ -6,7 +6,7 @@ import java.util.UUID;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.genersoft.iot.vmp.common.StreamInfo;
import com.genersoft.iot.vmp.conf.MediaServerConfig;
import com.genersoft.iot.vmp.conf.MediaConfig;
import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
@ -53,23 +53,20 @@ public class ZLMHttpHookListener {
@Autowired
private IRedisCatchStorage redisCatchStorage;
@Autowired
private ZLMServerManger zlmServerManger;
@Autowired
private ZLMMediaListManager zlmMediaListManager;
@Autowired
private ZLMHttpHookSubscribe subscribe;
@Value("${media.autoApplyPlay}")
@Value("${userSettings.autoApplyPlay}")
private boolean autoApplyPlay;
@Value("${media.ip}")
private String mediaIp;
@Value("${media.wanIp}")
private String mediaWanIp;
@Value("${media.port}")
private int mediaPort;
@Autowired
private MediaConfig mediaConfig;
/**
* 流量统计事件播放器或推流器断开时并且耗用流量超过特定阈值时会触发此事件阈值通过配置文件general.flowThreshold配置此事件对回复不敏感
@ -388,12 +385,8 @@ public class ZLMHttpHookListener {
subscribe.response(json);
}
}
MediaServerConfig mediaServerConfig = JSON.toJavaObject(json, MediaServerConfig.class);
mediaServerConfig.setWanIp(StringUtils.isEmpty(mediaWanIp)? mediaIp: mediaWanIp);
mediaServerConfig.setLocalIP(mediaIp);
redisCatchStorage.updateMediaInfo(mediaServerConfig);
ZLMServerConfig ZLMServerConfig = JSON.toJavaObject(json, ZLMServerConfig.class);
zlmServerManger.updateServerCatch(ZLMServerConfig);
// 重新发起代理
JSONObject ret = new JSONObject();

4
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMMediaListManager.java

@ -1,9 +1,7 @@
package com.genersoft.iot.vmp.media.zlm;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.genersoft.iot.vmp.conf.MediaServerConfig;
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;
@ -126,7 +124,7 @@ public class ZLMMediaListManager {
public void clearAllSessions() {
logger.info("清空所有国标相关的session");
JSONObject allSessionJSON = zlmresTfulUtils.getAllSession();
MediaServerConfig mediaInfo = redisCatchStorage.getMediaInfo();
ZLMServerConfig mediaInfo = redisCatchStorage.getMediaInfo();
HashSet<String> allLocalPorts = new HashSet();
if (allSessionJSON.getInteger("code") == 0) {
JSONArray data = allSessionJSON.getJSONArray("data");

17
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRESTfulUtils.java

@ -2,10 +2,13 @@ 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 okhttp3.*;
import org.checkerframework.checker.units.qual.A;
import org.jetbrains.annotations.NotNull;
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.Component;
@ -20,14 +23,8 @@ public class ZLMRESTfulUtils {
private final static Logger logger = LoggerFactory.getLogger(ZLMRESTfulUtils.class);
@Value("${media.ip}")
private String mediaIp;
@Value("${media.port}")
private int mediaPort;
@Value("${media.secret}")
private String mediaSecret;
@Autowired
private MediaConfig mediaConfig;
public interface RequestCallback{
void run(JSONObject response);
@ -35,12 +32,12 @@ public class ZLMRESTfulUtils {
public JSONObject sendPost(String api, Map<String, Object> param, RequestCallback callback) {
OkHttpClient client = new OkHttpClient();
String url = String.format("http://%s:%s/index/api/%s", mediaIp, mediaPort, api);
String url = String.format("http://%s:%s/index/api/%s", mediaConfig.getIp(), mediaConfig.getHttpPort(), api);
JSONObject responseJSON = null;
logger.debug(url);
FormBody.Builder builder = new FormBody.Builder();
builder.add("secret",mediaSecret);
builder.add("secret",mediaConfig.getSecret());
if (param != null && param.keySet().size() > 0) {
for (String key : param.keySet()){
if (param.get(key) != null) {

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

@ -2,6 +2,7 @@ package com.genersoft.iot.vmp.media.zlm;
import com.alibaba.fastjson.JSONArray;
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 org.slf4j.Logger;
@ -18,8 +19,8 @@ public class ZLMRTPServerFactory {
private Logger logger = LoggerFactory.getLogger("ZLMRTPServerFactory");
@Value("${media.rtp.portRange}")
private String portRange;
@Autowired
private MediaConfig mediaConfig;
@Autowired
private ZLMRESTfulUtils zlmresTfulUtils;
@ -103,7 +104,7 @@ public class ZLMRTPServerFactory {
private int getPortFromportRange() {
if (currentPort == 0) {
String[] portRangeStrArray = portRange.split(",");
String[] portRangeStrArray = mediaConfig.getRtpPortRange().split(",");
portRangeArray[0] = Integer.parseInt(portRangeStrArray[0]);
portRangeArray[1] = Integer.parseInt(portRangeStrArray[1]);
}

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

@ -3,7 +3,8 @@ package com.genersoft.iot.vmp.media.zlm;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.genersoft.iot.vmp.conf.MediaServerConfig;
import com.genersoft.iot.vmp.conf.MediaConfig;
import com.genersoft.iot.vmp.conf.SipConfig;
import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
//import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
@ -34,36 +35,20 @@ public class ZLMRunner implements CommandLineRunner {
@Autowired
private IRedisCatchStorage redisCatchStorage;
@Value("${media.ip}")
private String mediaIp;
@Value("${media.wanIp}")
private String mediaWanIp;
@Value("${media.hookIp}")
private String mediaHookIp;
@Value("${media.port}")
private int mediaPort;
@Value("${media.secret}")
private String mediaSecret;
@Value("${media.streamNoneReaderDelayMS}")
private String streamNoneReaderDelayMS;
@Autowired
private MediaConfig mediaConfig;
@Value("${sip.ip}")
private String sipIP;
@Autowired
private SipConfig sipConfig;
@Value("${server.port}")
private String serverPort;
@Value("${media.autoConfig}")
private boolean autoConfig;
@Value("${server.ssl.enabled}")
private boolean sslEnabled;
private boolean startGetMedia = false;
@Autowired
private ZLMRESTfulUtils zlmresTfulUtils;
@ -73,6 +58,9 @@ public class ZLMRunner implements CommandLineRunner {
@Autowired
private ZLMHttpHookSubscribe hookSubscribe;
@Autowired
private ZLMServerManger zlmServerManger;
@Autowired
private IStreamProxyService streamProxyService;
@ -80,26 +68,28 @@ public class ZLMRunner implements CommandLineRunner {
public void run(String... strings) throws Exception {
// 订阅 zlm启动事件
hookSubscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_server_started,null,(response)->{
MediaServerConfig mediaServerConfig = JSONObject.toJavaObject(response, MediaServerConfig.class);
zLmRunning(mediaServerConfig);
ZLMServerConfig ZLMServerConfig = JSONObject.toJavaObject(response, ZLMServerConfig.class);
zLmRunning(ZLMServerConfig);
});
// 获取zlm信息
logger.info("等待zlm接入...");
MediaServerConfig mediaServerConfig = getMediaServerConfig();
startGetMedia = true;
ZLMServerConfig ZLMServerConfig = getMediaServerConfig();
if (mediaServerConfig != null) {
zLmRunning(mediaServerConfig);
if (ZLMServerConfig != null) {
zLmRunning(ZLMServerConfig);
}
}
public MediaServerConfig getMediaServerConfig() {
public ZLMServerConfig getMediaServerConfig() {
if (!startGetMedia) return null;
JSONObject responseJSON = zlmresTfulUtils.getMediaServerConfig();
MediaServerConfig mediaServerConfig = null;
ZLMServerConfig ZLMServerConfig = null;
if (responseJSON != null) {
JSONArray data = responseJSON.getJSONArray("data");
if (data != null && data.size() > 0) {
mediaServerConfig = JSON.parseObject(JSON.toJSONString(data.get(0)), MediaServerConfig.class);
ZLMServerConfig = JSON.parseObject(JSON.toJSONString(data.get(0)), ZLMServerConfig.class);
}
} else {
@ -109,20 +99,18 @@ public class ZLMRunner implements CommandLineRunner {
} catch (InterruptedException e) {
e.printStackTrace();
}
mediaServerConfig = getMediaServerConfig();
ZLMServerConfig = getMediaServerConfig();
}
return mediaServerConfig;
return ZLMServerConfig;
}
private void saveZLMConfig() {
logger.info("设置zlm...");
if (StringUtils.isEmpty(mediaHookIp)) {
mediaHookIp = sipIP;
}
if (StringUtils.isEmpty(mediaConfig.getHookIp())) mediaConfig.setHookIp(sipConfig.getSipIp());
String protocol = sslEnabled ? "https" : "http";
String hookPrex = String.format("%s://%s:%s/index/hook", protocol, mediaHookIp, serverPort);
String hookPrex = String.format("%s://%s:%s/index/hook", protocol, mediaConfig.getHookIp(), serverPort);
Map<String, Object> param = new HashMap<>();
param.put("api.secret",mediaSecret); // -profile:v Baseline
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","");
@ -139,7 +127,7 @@ public class ZLMRunner implements CommandLineRunner {
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",streamNoneReaderDelayMS);
param.put("general.streamNoneReaderDelayMS",mediaConfig.getStreamNoneReaderDelayMS());
JSONObject responseJSON = zlmresTfulUtils.setServerConfig(param);
@ -153,17 +141,12 @@ public class ZLMRunner implements CommandLineRunner {
/**
* zlm 连接成功或者zlm重启后
*/
private void zLmRunning(MediaServerConfig mediaServerConfig){
logger.info( "[ id: " + mediaServerConfig.getGeneralMediaServerId() + "] zlm接入成功...");
if (autoConfig) saveZLMConfig();
MediaServerConfig mediaInfo = redisCatchStorage.getMediaInfo();
if (mediaInfo != null && System.currentTimeMillis() - mediaInfo.getUpdateTime() < 50){
logger.info("[ id: " + mediaServerConfig.getGeneralMediaServerId() + "]zlm刚刚更新,忽略这次更新");
return;
}
mediaServerConfig.setLocalIP(mediaIp);
mediaServerConfig.setWanIp(StringUtils.isEmpty(mediaWanIp)? mediaIp: mediaWanIp);
redisCatchStorage.updateMediaInfo(mediaServerConfig);
private void zLmRunning(ZLMServerConfig zlmServerConfig){
logger.info( "[ id: " + zlmServerConfig.getGeneralMediaServerId() + "] zlm接入成功...");
// 关闭循环获取zlm配置
startGetMedia = false;
if (mediaConfig.getAutoConfig()) saveZLMConfig();
zlmServerManger.updateServerCatch(zlmServerConfig);
// 清空所有session
// zlmMediaListManager.clearAllSessions();

15
src/main/java/com/genersoft/iot/vmp/conf/MediaServerConfig.java → src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMServerConfig.java

@ -1,8 +1,8 @@
package com.genersoft.iot.vmp.conf;
package com.genersoft.iot.vmp.media.zlm;
import com.alibaba.fastjson.annotation.JSONField;
public class MediaServerConfig {
public class ZLMServerConfig {
@JSONField(name = "api.apiDebug")
private String apiDebug;
@ -157,6 +157,9 @@ public class MediaServerConfig {
@JSONField(name = "rtmp.port")
private String rtmpPort;
@JSONField(name = "rtmp.sslport")
private String rtmpSslPort;
@JSONField(name = "rtp.audioMtuSize")
private String rtpAudioMtuSize;
@ -749,4 +752,12 @@ public class MediaServerConfig {
public void setGeneralMediaServerId(String generalMediaServerId) {
this.generalMediaServerId = generalMediaServerId;
}
public String getRtmpSslPort() {
return rtmpSslPort;
}
public void setRtmpSslPort(String rtmpSslPort) {
this.rtmpSslPort = rtmpSslPort;
}
}

45
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMServerManger.java

@ -0,0 +1,45 @@
package com.genersoft.iot.vmp.media.zlm;
import com.alibaba.fastjson.annotation.JSONField;
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.setLocalIP(mediaConfig.getIp());
zlmServerConfig.setWanIp(StringUtils.isEmpty(mediaConfig.getWanIp())? mediaConfig.getIp(): mediaConfig.getWanIp());
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);
}
}

4
src/main/java/com/genersoft/iot/vmp/service/impl/MediaServiceImpl.java

@ -4,7 +4,7 @@ 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.MediaServerConfig;
import com.genersoft.iot.vmp.media.zlm.ZLMServerConfig;
import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
@ -28,7 +28,7 @@ public class MediaServiceImpl implements IMediaService {
@Override
public StreamInfo getStreamInfoByAppAndStream(String app, String stream, JSONArray tracks) {
MediaServerConfig mediaInfo = redisCatchStorage.getMediaInfo();
ZLMServerConfig mediaInfo = redisCatchStorage.getMediaInfo();
StreamInfo streamInfoResult = new StreamInfo();
streamInfoResult.setStreamId(stream);
streamInfoResult.setApp(app);

4
src/main/java/com/genersoft/iot/vmp/service/impl/StreamProxyServiceImpl.java

@ -1,7 +1,7 @@
package com.genersoft.iot.vmp.service.impl;
import com.alibaba.fastjson.JSONObject;
import com.genersoft.iot.vmp.conf.MediaServerConfig;
import com.genersoft.iot.vmp.media.zlm.ZLMServerConfig;
import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
@ -41,7 +41,7 @@ public class StreamProxyServiceImpl implements IStreamProxyService {
@Override
public String save(StreamProxyItem param) {
MediaServerConfig mediaInfo = redisCatchStorage.getMediaInfo();
ZLMServerConfig mediaInfo = redisCatchStorage.getMediaInfo();
String dstUrl = String.format("rtmp://%s:%s/%s/%s", "127.0.0.1", mediaInfo.getRtmpPort(), param.getApp(),
param.getStream() );
param.setDst_url(dstUrl);

8
src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java

@ -1,7 +1,7 @@
package com.genersoft.iot.vmp.storager;
import com.genersoft.iot.vmp.common.StreamInfo;
import com.genersoft.iot.vmp.conf.MediaServerConfig;
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;
@ -41,16 +41,16 @@ public interface IRedisCatchStorage {
/**
* 更新流媒体信息
* @param mediaServerConfig
* @param ZLMServerConfig
* @return
*/
boolean updateMediaInfo(MediaServerConfig mediaServerConfig);
boolean updateMediaInfo(ZLMServerConfig ZLMServerConfig);
/**
* 获取流媒体信息
* @return
*/
MediaServerConfig getMediaInfo();
ZLMServerConfig getMediaInfo();
Map<String, StreamInfo> queryPlayByDeviceId(String deviceId);

14
src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java

@ -2,7 +2,7 @@ package com.genersoft.iot.vmp.storager.impl;
import com.genersoft.iot.vmp.common.StreamInfo;
import com.genersoft.iot.vmp.common.VideoManagerConstants;
import com.genersoft.iot.vmp.conf.MediaServerConfig;
import com.genersoft.iot.vmp.media.zlm.ZLMServerConfig;
import com.genersoft.iot.vmp.gb28181.bean.*;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import com.genersoft.iot.vmp.storager.dao.DeviceChannelMapper;
@ -86,13 +86,13 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage {
/**
* 更新流媒体信息
* @param mediaServerConfig
* @param ZLMServerConfig
* @return
*/
@Override
public boolean updateMediaInfo(MediaServerConfig mediaServerConfig) {
mediaServerConfig.setUpdateTime(System.currentTimeMillis());
return redis.set(VideoManagerConstants.MEDIA_SERVER_PREFIX,mediaServerConfig);
public boolean updateMediaInfo(ZLMServerConfig ZLMServerConfig) {
ZLMServerConfig.setUpdateTime(System.currentTimeMillis());
return redis.set(VideoManagerConstants.MEDIA_SERVER_PREFIX, ZLMServerConfig);
}
/**
@ -100,8 +100,8 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage {
* @return
*/
@Override
public MediaServerConfig getMediaInfo() {
return (MediaServerConfig)redis.get(VideoManagerConstants.MEDIA_SERVER_PREFIX);
public ZLMServerConfig getMediaInfo() {
return (ZLMServerConfig)redis.get(VideoManagerConstants.MEDIA_SERVER_PREFIX);
}
@Override

4
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/play/PlayController.java

@ -1,7 +1,7 @@
package com.genersoft.iot.vmp.vmanager.gb28181.play;
import com.genersoft.iot.vmp.common.StreamInfo;
import com.genersoft.iot.vmp.conf.MediaServerConfig;
import com.genersoft.iot.vmp.media.zlm.ZLMServerConfig;
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;
@ -162,7 +162,7 @@ public class PlayController {
logger.warn("视频转码API调用失败!, 视频流已停止推流!");
return new ResponseEntity<String>("推流信息在流媒体中不存在, 视频流可能已停止推流", HttpStatus.OK);
} else {
MediaServerConfig mediaInfo = redisCatchStorage.getMediaInfo();
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);

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

@ -67,17 +67,25 @@ media:
# [可选] zlm服务器的hook所使用的IP, 默认使用sip.ip
hookIp:
# [必须修改] zlm服务器的http.port
port: 80
httpPort: 80
# [可选] zlm服务器的http.sslport, 置空使用zlm配置文件配置
httpSSlPort:
# [可选] zlm服务器的rtmp.port, 置空使用zlm配置文件配置
rtmpPort:
# [可选] zlm服务器的rtmp.sslport, 置空使用zlm配置文件配置
rtmpSSlPort:
# [可选] zlm服务器的 rtp_proxy.port, 置空使用zlm配置文件配置
rtpProxyPort:
# [可选] zlm服务器的 rtsp.port, 置空使用zlm配置文件配置
rtspPort:
# [可选] zlm服务器的 rtsp.sslport, 置空使用zlm配置文件配置
rtspSSLPort:
# [可选] 是否自动配置ZLM, 如果希望手动配置ZLM, 可以设为false, 不建议新接触的用户修改
autoConfig: true
# [可选] zlm服务器的hook.admin_params=secret
secret: 035c73f7-bb6b-4889-a715-d9eb2d1925cc
# [可选] zlm服务器的general.streamNoneReaderDelayMS
streamNoneReaderDelayMS: 18000 # 无人观看多久自动关闭流, -1表示永不自动关闭,即 关闭按需拉流
# [可选] 自动点播, 使用固定流地址进行播放时,如果未点播则自动进行点播, 需要rtp.enable=true
autoApplyPlay: false
# [可选] 部分设备需要扩展SDP,需要打开此设置
seniorSdp: false
# 启用多端口模式, 多端口模式使用端口区分每路流,兼容性更好。 单端口使用流的ssrc区分, 点播超时建议使用多端口测试
rtp:
# [可选] 是否启用多端口模式, 开启后会在portRange范围内选择端口用于媒体流传输
@ -95,9 +103,13 @@ logging:
level:
com:
genersoft:
iot: debug
iot: info
# [根据业务需求配置]
userSettings:
# [可选] 自动点播, 使用固定流地址进行播放时,如果未点播则自动进行点播, 需要rtp.enable=true
autoApplyPlay: false
# [可选] 部分设备需要扩展SDP,需要打开此设置
seniorSdp: false
# 保存移动位置历史轨迹:true:保留历史数据,false:仅保留最后的位置(默认)
savePositionHistory: false
# 点播等待超时时间,单位:毫秒

Loading…
Cancel
Save