src/main/java/com/genersoft/iot/vmp/conf/UserSetting.java
@@ -35,6 +35,8 @@ private Boolean useSourceIpAsStreamIp = Boolean.FALSE; private Boolean sipUseSourceIpAsRemoteAddress = Boolean.TRUE; private Boolean streamOnDemand = Boolean.TRUE; private Boolean pushAuthority = Boolean.TRUE; @@ -196,4 +198,12 @@ public void setSyncChannelOnDeviceOnline(Boolean syncChannelOnDeviceOnline) { this.syncChannelOnDeviceOnline = syncChannelOnDeviceOnline; } public Boolean getSipUseSourceIpAsRemoteAddress() { return sipUseSourceIpAsRemoteAddress; } public void setSipUseSourceIpAsRemoteAddress(Boolean sipUseSourceIpAsRemoteAddress) { this.sipUseSourceIpAsRemoteAddress = sipUseSourceIpAsRemoteAddress; } } src/main/java/com/genersoft/iot/vmp/gb28181/bean/RemoteAddressInfo.java
New file @@ -0,0 +1,27 @@ package com.genersoft.iot.vmp.gb28181.bean; public class RemoteAddressInfo { private String ip; private int port; public RemoteAddressInfo(String ip, int port) { this.ip = ip; this.port = port; } public String getIp() { return ip; } public void setIp(String ip) { this.ip = ip; } public int getPort() { return port; } public void setPort(int port) { this.port = port; } } src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/RegisterRequestProcessor.java
@@ -1,13 +1,16 @@ package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl; import com.genersoft.iot.vmp.conf.SipConfig; import com.genersoft.iot.vmp.conf.UserSetting; import com.genersoft.iot.vmp.gb28181.auth.DigestServerAuthenticationHelper; import com.genersoft.iot.vmp.gb28181.bean.Device; import com.genersoft.iot.vmp.gb28181.bean.RemoteAddressInfo; import com.genersoft.iot.vmp.gb28181.bean.WvpSipDate; import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver; import com.genersoft.iot.vmp.gb28181.transmit.SIPSender; import com.genersoft.iot.vmp.gb28181.transmit.event.request.ISIPRequestProcessor; import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent; import com.genersoft.iot.vmp.gb28181.utils.SipUtils; import com.genersoft.iot.vmp.service.IDeviceService; import com.genersoft.iot.vmp.utils.DateUtil; import gov.nist.javax.sip.RequestEventExt; @@ -55,6 +58,9 @@ @Autowired private SIPSender sipSender; @Autowired private UserSetting userSetting; @Override public void afterPropertiesSet() throws Exception { @@ -125,15 +131,9 @@ // 添加Expires头 response.addHeader(request.getExpires()); // 获取到通信地址等信息 ViaHeader viaHeader = (ViaHeader) request.getHeader(ViaHeader.NAME); String received = viaHeader.getReceived(); int rPort = viaHeader.getRPort(); // 解析本地地址替代 if (ObjectUtils.isEmpty(received) || rPort == -1) { received = viaHeader.getHost(); rPort = viaHeader.getPort(); } RemoteAddressInfo remoteAddressInfo = SipUtils.getRemoteAddressFromRequest(request, userSetting.getSipUseSourceIpAsRemoteAddress()); if (device == null) { device = new Device(); device.setStreamMode("UDP"); @@ -143,9 +143,9 @@ device.setDeviceId(deviceId); device.setOnline(0); } device.setIp(received); device.setPort(rPort); device.setHostAddress(received.concat(":").concat(String.valueOf(rPort))); device.setIp(remoteAddressInfo.getIp()); device.setPort(remoteAddressInfo.getPort()); device.setHostAddress(remoteAddressInfo.getIp().concat(":").concat(String.valueOf(remoteAddressInfo.getPort()))); device.setLocalIp(request.getLocalAddress().getHostAddress()); if (request.getExpires().getExpires() == 0) { // 注销成功 src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/KeepaliveNotifyMessageHandler.java
@@ -1,14 +1,14 @@ package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.notify.cmd; import com.genersoft.iot.vmp.conf.UserSetting; import com.genersoft.iot.vmp.gb28181.bean.Device; import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; import com.genersoft.iot.vmp.gb28181.event.EventPublisher; import com.genersoft.iot.vmp.gb28181.bean.RemoteAddressInfo; import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent; import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler; import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.notify.NotifyMessageHandler; import com.genersoft.iot.vmp.gb28181.utils.SipUtils; import com.genersoft.iot.vmp.service.IDeviceService; import com.genersoft.iot.vmp.storager.IRedisCatchStorage; import com.genersoft.iot.vmp.storager.IVideoManagerStorage; import com.genersoft.iot.vmp.utils.DateUtil; import gov.nist.javax.sip.message.SIPRequest; import org.dom4j.Element; @@ -17,13 +17,10 @@ import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.util.ObjectUtils; import org.springframework.util.StringUtils; import javax.sip.InvalidArgumentException; import javax.sip.RequestEvent; import javax.sip.SipException; import javax.sip.header.ViaHeader; import javax.sip.message.Response; import java.text.ParseException; @@ -33,6 +30,7 @@ @Component public class KeepaliveNotifyMessageHandler extends SIPRequestProcessorParent implements InitializingBean, IMessageHandler { private Logger logger = LoggerFactory.getLogger(KeepaliveNotifyMessageHandler.class); private final static String cmdType = "Keepalive"; @@ -41,6 +39,9 @@ @Autowired private IDeviceService deviceService; @Autowired private UserSetting userSetting; @Override public void afterPropertiesSet() throws Exception { @@ -53,25 +54,19 @@ // 未注册的设备不做处理 return; } SIPRequest request = (SIPRequest) evt.getRequest(); // 回复200 OK try { responseAck((SIPRequest) evt.getRequest(), Response.OK); responseAck(request, Response.OK); } catch (SipException | InvalidArgumentException | ParseException e) { logger.error("[命令发送失败] 国标级联 心跳回复: {}", e.getMessage()); logger.error("[命令发送失败] 心跳回复: {}", e.getMessage()); } // 判断RPort是否改变,改变则说明路由nat信息变化,修改设备信息 // 获取到通信地址等信息 ViaHeader viaHeader = (ViaHeader) evt.getRequest().getHeader(ViaHeader.NAME); String received = viaHeader.getReceived(); int rPort = viaHeader.getRPort(); // 解析本地地址替代 if (ObjectUtils.isEmpty(received) || rPort == -1) { received = viaHeader.getHost(); rPort = viaHeader.getPort(); } if (device.getPort() != rPort) { device.setPort(rPort); device.setHostAddress(received.concat(":").concat(String.valueOf(rPort))); RemoteAddressInfo remoteAddressInfo = SipUtils.getRemoteAddressFromRequest(request, userSetting.getSipUseSourceIpAsRemoteAddress()); if (!device.getIp().equalsIgnoreCase(remoteAddressInfo.getIp()) || device.getPort() != remoteAddressInfo.getPort()) { device.setPort(remoteAddressInfo.getPort()); device.setHostAddress(remoteAddressInfo.getIp().concat(":").concat(String.valueOf(remoteAddressInfo.getPort()))); device.setIp(remoteAddressInfo.getIp()); } device.setKeepaliveTime(DateUtil.getNow()); src/main/java/com/genersoft/iot/vmp/gb28181/utils/SipUtils.java
@@ -1,9 +1,11 @@ package com.genersoft.iot.vmp.gb28181.utils; import com.genersoft.iot.vmp.gb28181.bean.RemoteAddressInfo; import com.genersoft.iot.vmp.utils.GitUtil; import gov.nist.javax.sip.address.AddressImpl; import gov.nist.javax.sip.address.SipUri; import gov.nist.javax.sip.header.Subject; import gov.nist.javax.sip.message.SIPRequest; import org.springframework.util.ObjectUtils; import javax.sip.PeerUnavailableException; @@ -119,4 +121,25 @@ return builder.toString(); } public static RemoteAddressInfo getRemoteAddressFromRequest(SIPRequest request, boolean sipUseSourceIpAsRemoteAddress) { String remoteAddress; int remotePort; if (sipUseSourceIpAsRemoteAddress) { remoteAddress = request.getRemoteAddress().getHostAddress(); remotePort = request.getRemotePort(); }else { // 判断RPort是否改变,改变则说明路由nat信息变化,修改设备信息 // 获取到通信地址等信息 remoteAddress = request.getTopmostViaHeader().getReceived(); remotePort = request.getTopmostViaHeader().getPort(); // 解析本地地址替代 if (ObjectUtils.isEmpty(remoteAddress) || remotePort == -1) { remoteAddress = request.getViaHost(); remotePort = request.getViaPort(); } } return new RemoteAddressInfo(remoteAddress, remotePort); } } src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java
@@ -18,6 +18,7 @@ import com.genersoft.iot.vmp.service.*; import com.genersoft.iot.vmp.storager.IRedisCatchStorage; import com.genersoft.iot.vmp.storager.IVideoManagerStorage; import com.genersoft.iot.vmp.vmanager.bean.StreamContent; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -347,7 +348,7 @@ } StreamInfo streamInfoByAppAndStream = mediaService.getStreamInfoByAppAndStream(mediaServerItem, param.getApp(), param.getStream(), tracks, callId); param.setStreamInfo(streamInfoByAppAndStream); param.setStreamInfo(new StreamContent(streamInfoByAppAndStream)); redisCatchStorage.addStream(mediaServerItem, type, param.getApp(), param.getStream(), param); if (param.getOriginType() == OriginType.RTSP_PUSH.ordinal() || param.getOriginType() == OriginType.RTMP_PUSH.ordinal() @@ -364,7 +365,7 @@ } GbStream gbStream = storager.getGbStream(param.getApp(), param.getStream()); if (gbStream != null) { // eventPublisher.catalogEventPublishForStream(null, gbStream, CatalogEvent.OFF); // eventPublisher.catalogEventPublishForStream(null, gbStream, CatalogEvent.OFF); } zlmMediaListManager.removeMedia(param.getApp(), param.getStream()); } @@ -527,7 +528,7 @@ @ResponseBody @PostMapping(value = "/on_stream_not_found", produces = "application/json;charset=UTF-8") public JSONObject onStreamNotFound(@RequestBody OnStreamNotFoundHookParam param){ logger.info("[ZLM HOOK] 流未找到:{}->{}->{}/{}" + param.getMediaServerId(), param.getSchema(), param.getApp(), param.getStream()); logger.info("[ZLM HOOK] 流未找到:{}->{}->{}/{}", param.getMediaServerId(), param.getSchema(), param.getApp(), param.getStream()); taskExecutor.execute(()->{ MediaServerItem mediaInfo = mediaServerService.getOne(param.getMediaServerId()); if (userSetting.isAutoApplyPlay() && mediaInfo != null) { src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnStreamChangedHookParam.java
@@ -1,6 +1,6 @@ package com.genersoft.iot.vmp.media.zlm.dto.hook; import com.genersoft.iot.vmp.common.StreamInfo; import com.genersoft.iot.vmp.vmanager.bean.StreamContent; import java.util.List; @@ -291,7 +291,7 @@ } } private StreamInfo streamInfo; private StreamContent streamInfo; public String getApp() { return app; @@ -407,11 +407,11 @@ this.docker = docker; } public StreamInfo getStreamInfo() { public StreamContent getStreamInfo() { return streamInfo; } public void setStreamInfo(StreamInfo streamInfo) { public void setStreamInfo(StreamContent streamInfo) { this.streamInfo = streamInfo; } src/main/java/com/genersoft/iot/vmp/service/impl/DeviceServiceImpl.java
@@ -332,7 +332,6 @@ device.setUpdateTime(DateUtil.getNow()); if (deviceMapper.update(device) > 0) { redisCatchStorage.updateDevice(device); } } src/main/java/com/genersoft/iot/vmp/vmanager/bean/StreamContent.java
New file @@ -0,0 +1,325 @@ package com.genersoft.iot.vmp.vmanager.bean; import com.genersoft.iot.vmp.common.StreamInfo; public class StreamContent { private String app; private String stream; private String ip; private String flv; private String https_flv; private String ws_flv; private String wss_flv; private String fmp4; private String https_fmp4; private String ws_fmp4; private String wss_fmp4; private String hls; private String https_hls; private String ws_hls; private String wss_hls; private String ts; private String https_ts; private String ws_ts; private String wss_ts; private String rtmp; private String rtmps; private String rtsp; private String rtsps; private String rtc; private String rtcs; private String mediaServerId; private Object tracks; public StreamContent(StreamInfo streamInfo) { if (streamInfo == null) { return; } this.app = streamInfo.getApp(); this.stream = streamInfo.getStream(); if (streamInfo.getFlv() != null) { this.flv = streamInfo.getFlv().getUrl(); } if (streamInfo.getHttps_flv() != null) { this.https_flv = streamInfo.getHttps_flv().getUrl(); } if (streamInfo.getWs_flv() != null) { this.ws_flv = streamInfo.getWs_flv().getUrl(); } if (streamInfo.getWss_flv() != null) { this.wss_flv = streamInfo.getWss_flv().getUrl(); } if (streamInfo.getFmp4() != null) { this.fmp4 = streamInfo.getFmp4().getUrl(); } if (streamInfo.getWs_fmp4() != null) { this.ws_fmp4 = streamInfo.getWs_fmp4().getUrl(); } if (streamInfo.getWss_fmp4() != null) { this.wss_fmp4 = streamInfo.getWss_fmp4().getUrl(); } if (streamInfo.getHls() != null) { this.hls = streamInfo.getHls().getUrl(); } if (streamInfo.getHttps_hls() != null) { this.https_hls = streamInfo.getHttps_hls().getUrl(); } if (streamInfo.getWs_hls() != null) { this.ws_hls = streamInfo.getWs_hls().getUrl(); } if (streamInfo.getWss_hls() != null) { this.wss_hls = streamInfo.getWss_hls().getUrl(); } if (streamInfo.getTs() != null) { this.ts = streamInfo.getTs().getUrl(); } if (streamInfo.getHttps_ts() != null) { this.https_ts = streamInfo.getHttps_ts().getUrl(); } if (streamInfo.getWs_ts() != null) { this.ws_ts = streamInfo.getWs_ts().getUrl(); } if (streamInfo.getRtmp() != null) { this.rtmp = streamInfo.getRtmp().getUrl(); } if (streamInfo.getRtmps() != null) { this.rtmps = streamInfo.getRtmps().getUrl(); } if (streamInfo.getRtsp() != null) { this.rtsp = streamInfo.getRtsp().getUrl(); } if (streamInfo.getRtsps() != null) { this.rtsps = streamInfo.getRtsps().getUrl(); } if (streamInfo.getRtc() != null) { this.rtc = streamInfo.getRtc().getUrl(); } if (streamInfo.getRtcs() != null) { this.rtcs = streamInfo.getRtcs().getUrl(); } this.mediaServerId = streamInfo.getMediaServerId(); this.tracks = streamInfo.getTracks(); } public String getApp() { return app; } public void setApp(String app) { this.app = app; } public String getStream() { return stream; } public void setStream(String stream) { this.stream = stream; } public String getIp() { return ip; } public void setIp(String ip) { this.ip = ip; } public String getFlv() { return flv; } public void setFlv(String flv) { this.flv = flv; } public String getHttps_flv() { return https_flv; } public void setHttps_flv(String https_flv) { this.https_flv = https_flv; } public String getWs_flv() { return ws_flv; } public void setWs_flv(String ws_flv) { this.ws_flv = ws_flv; } public String getWss_flv() { return wss_flv; } public void setWss_flv(String wss_flv) { this.wss_flv = wss_flv; } public String getFmp4() { return fmp4; } public void setFmp4(String fmp4) { this.fmp4 = fmp4; } public String getHttps_fmp4() { return https_fmp4; } public void setHttps_fmp4(String https_fmp4) { this.https_fmp4 = https_fmp4; } public String getWs_fmp4() { return ws_fmp4; } public void setWs_fmp4(String ws_fmp4) { this.ws_fmp4 = ws_fmp4; } public String getWss_fmp4() { return wss_fmp4; } public void setWss_fmp4(String wss_fmp4) { this.wss_fmp4 = wss_fmp4; } public String getHls() { return hls; } public void setHls(String hls) { this.hls = hls; } public String getHttps_hls() { return https_hls; } public void setHttps_hls(String https_hls) { this.https_hls = https_hls; } public String getWs_hls() { return ws_hls; } public void setWs_hls(String ws_hls) { this.ws_hls = ws_hls; } public String getWss_hls() { return wss_hls; } public void setWss_hls(String wss_hls) { this.wss_hls = wss_hls; } public String getTs() { return ts; } public void setTs(String ts) { this.ts = ts; } public String getHttps_ts() { return https_ts; } public void setHttps_ts(String https_ts) { this.https_ts = https_ts; } public String getWs_ts() { return ws_ts; } public void setWs_ts(String ws_ts) { this.ws_ts = ws_ts; } public String getWss_ts() { return wss_ts; } public void setWss_ts(String wss_ts) { this.wss_ts = wss_ts; } public String getRtmp() { return rtmp; } public void setRtmp(String rtmp) { this.rtmp = rtmp; } public String getRtmps() { return rtmps; } public void setRtmps(String rtmps) { this.rtmps = rtmps; } public String getRtsp() { return rtsp; } public void setRtsp(String rtsp) { this.rtsp = rtsp; } public String getRtsps() { return rtsps; } public void setRtsps(String rtsps) { this.rtsps = rtsps; } public String getRtc() { return rtc; } public void setRtc(String rtc) { this.rtc = rtc; } public String getRtcs() { return rtcs; } public void setRtcs(String rtcs) { this.rtcs = rtcs; } public String getMediaServerId() { return mediaServerId; } public void setMediaServerId(String mediaServerId) { this.mediaServerId = mediaServerId; } public Object getTracks() { return tracks; } public void setTracks(Object tracks) { this.tracks = tracks; } } src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/media/MediaController.java
@@ -5,10 +5,11 @@ import com.genersoft.iot.vmp.conf.security.SecurityUtils; import com.genersoft.iot.vmp.conf.security.dto.LoginUser; import com.genersoft.iot.vmp.media.zlm.dto.StreamAuthorityInfo; import com.genersoft.iot.vmp.service.IStreamProxyService; import com.genersoft.iot.vmp.service.IMediaService; import com.genersoft.iot.vmp.service.IStreamProxyService; import com.genersoft.iot.vmp.storager.IRedisCatchStorage; import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; import com.genersoft.iot.vmp.vmanager.bean.StreamContent; import com.genersoft.iot.vmp.vmanager.bean.WVPResult; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; @@ -53,11 +54,11 @@ @Parameter(name = "useSourceIpAsStreamIp", description = "是否使用请求IP作为返回的地址IP") @GetMapping(value = "/stream_info_by_app_and_stream") @ResponseBody public StreamInfo getStreamInfoByAppAndStream(HttpServletRequest request, @RequestParam String app, @RequestParam String stream, @RequestParam(required = false) String mediaServerId, @RequestParam(required = false) String callId, @RequestParam(required = false) Boolean useSourceIpAsStreamIp){ public StreamContent getStreamInfoByAppAndStream(HttpServletRequest request, @RequestParam String app, @RequestParam String stream, @RequestParam(required = false) String mediaServerId, @RequestParam(required = false) String callId, @RequestParam(required = false) Boolean useSourceIpAsStreamIp){ boolean authority = false; if (callId != null) { // 权限校验 @@ -90,7 +91,7 @@ WVPResult<StreamInfo> result = new WVPResult<>(); if (streamInfo != null){ return streamInfo; return new StreamContent(streamInfo); }else { //获取流失败,重启拉流后重试一次 streamProxyService.stop(app,stream); @@ -109,7 +110,7 @@ streamInfo = mediaService.getStreamInfoByAppAndStreamWithCheck(app, stream, mediaServerId, authority); } if (streamInfo != null){ return streamInfo; return new StreamContent(streamInfo); }else { throw new ControllerException(ErrorCode.ERROR100); } src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/play/PlayController.java
@@ -21,6 +21,7 @@ import com.genersoft.iot.vmp.storager.IVideoManagerStorage; import com.genersoft.iot.vmp.vmanager.bean.DeferredResultEx; import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; import com.genersoft.iot.vmp.vmanager.bean.StreamContent; import com.genersoft.iot.vmp.vmanager.bean.WVPResult; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; @@ -80,8 +81,8 @@ @Parameter(name = "deviceId", description = "设备国标编号", required = true) @Parameter(name = "channelId", description = "通道国标编号", required = true) @GetMapping("/start/{deviceId}/{channelId}") public DeferredResult<WVPResult<StreamInfo>> play(HttpServletRequest request, @PathVariable String deviceId, @PathVariable String channelId) { public DeferredResult<WVPResult<StreamContent>> play(HttpServletRequest request, @PathVariable String deviceId, @PathVariable String channelId) { // 获取可用的zlm Device device = storager.queryVideoDevice(deviceId); @@ -93,8 +94,8 @@ msg.setKey(key); String uuid = UUID.randomUUID().toString(); msg.setId(uuid); DeferredResult<WVPResult<StreamInfo>> result = new DeferredResult<>(userSetting.getPlayTimeout().longValue()); DeferredResultEx<WVPResult<StreamInfo>> deferredResultEx = new DeferredResultEx<>(result); DeferredResult<WVPResult<StreamContent>> result = new DeferredResult<>(userSetting.getPlayTimeout().longValue()); DeferredResultEx<WVPResult<StreamContent>> deferredResultEx = new DeferredResultEx<>(result); result.onTimeout(()->{ logger.info("点播接口等待超时"); @@ -106,24 +107,24 @@ resultHolder.invokeResult(msg); }); if (userSetting.getUseSourceIpAsStreamIp()) { // TODO 在点播未成功的情况下在此调用接口点播会导致返回的流地址ip错误 deferredResultEx.setFilter(result1 -> { WVPResult<StreamInfo> wvpResult1 = (WVPResult<StreamInfo>)result1; WVPResult<StreamInfo> clone = null; try { clone = (WVPResult<StreamInfo>)wvpResult1.clone(); } catch (CloneNotSupportedException e) { throw new RuntimeException(e); WVPResult<StreamContent> resultStream = null; if (wvpResult1.getCode() == ErrorCode.SUCCESS.getCode()) { StreamInfo data = wvpResult1.getData().clone(); if (userSetting.getUseSourceIpAsStreamIp()) { data.channgeStreamIp(request.getLocalName()); } resultStream = new WVPResult<>(); resultStream.setCode(wvpResult1.getCode()); resultStream.setMsg(wvpResult1.getMsg()); resultStream.setData(new StreamContent(wvpResult1.getData())); } if (clone.getCode() == ErrorCode.SUCCESS.getCode()) { StreamInfo data = clone.getData().clone(); data.channgeStreamIp(request.getLocalName()); clone.setData(data); } return clone; return resultStream; }); } // 录像查询以channelId作为deviceId查询 resultHolder.put(key, uuid, deferredResultEx); src/main/java/com/genersoft/iot/vmp/vmanager/streamProxy/StreamProxyController.java
@@ -1,13 +1,13 @@ package com.genersoft.iot.vmp.vmanager.streamProxy; import com.alibaba.fastjson2.JSONObject; import com.genersoft.iot.vmp.common.StreamInfo; import com.genersoft.iot.vmp.conf.exception.ControllerException; import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem; import com.genersoft.iot.vmp.service.IMediaServerService; import com.genersoft.iot.vmp.service.IStreamProxyService; import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; import com.genersoft.iot.vmp.vmanager.bean.StreamContent; import com.github.pagehelper.PageInfo; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; @@ -58,7 +58,7 @@ }) @PostMapping(value = "/save") @ResponseBody public StreamInfo save(@RequestBody StreamProxyItem param){ public StreamContent save(@RequestBody StreamProxyItem param){ logger.info("添加代理: " + JSONObject.toJSONString(param)); if (ObjectUtils.isEmpty(param.getMediaServerId())) { param.setMediaServerId("auto"); @@ -69,7 +69,7 @@ if (ObjectUtils.isEmpty(param.getGbId())) { param.setGbId(null); } return streamProxyService.save(param); return new StreamContent(streamProxyService.save(param)); } @GetMapping(value = "/ffmpeg_cmd/list") src/main/java/com/genersoft/iot/vmp/vmanager/streamPush/StreamPushController.java
@@ -11,22 +11,16 @@ import com.genersoft.iot.vmp.gb28181.bean.GbStream; import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage; import com.genersoft.iot.vmp.media.zlm.dto.StreamAuthorityInfo; import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem; import com.genersoft.iot.vmp.service.IMediaServerService; import com.genersoft.iot.vmp.service.IMediaService; import com.genersoft.iot.vmp.service.IStreamPushService; import com.genersoft.iot.vmp.service.impl.StreamPushUploadFileHandler; import com.genersoft.iot.vmp.vmanager.bean.BatchGBStreamParam; import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; import com.genersoft.iot.vmp.vmanager.bean.StreamPushExcelDto; import com.genersoft.iot.vmp.vmanager.bean.WVPResult; import com.genersoft.iot.vmp.vmanager.bean.*; import com.github.pagehelper.PageInfo; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; import org.apache.poi.sl.usermodel.Sheet; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -34,12 +28,10 @@ import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; import org.springframework.util.ObjectUtils; import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.*; import org.springframework.web.context.request.async.DeferredResult; import org.springframework.web.multipart.MultipartFile; import javax.servlet.http.HttpServletRequest; import java.io.IOException; import java.io.InputStream; import java.util.HashMap; @@ -243,8 +235,8 @@ @Parameter(name = "app", description = "应用名", required = true) @Parameter(name = "stream", description = "流id", required = true) @Parameter(name = "mediaServerId", description = "媒体服务器id") public StreamInfo getPlayUrl(@RequestParam String app,@RequestParam String stream, @RequestParam(required = false) String mediaServerId){ public StreamContent getPlayUrl(@RequestParam String app, @RequestParam String stream, @RequestParam(required = false) String mediaServerId){ boolean authority = false; // 是否登陆用户, 登陆用户返回完整信息 LoginUser userInfo = SecurityUtils.getUserInfo(); @@ -259,7 +251,7 @@ if (streamInfo == null){ throw new ControllerException(ErrorCode.ERROR100.getCode(), "获取播放地址失败"); } return streamInfo; return new StreamContent(streamInfo); } /** src/main/resources/all-application.yml
@@ -195,6 +195,8 @@ gb-send-stream-strict: false # 设备上线时是否自动同步通道 sync-channel-on-device-online: false # 设备上线时是否自动同步通道 sip-use-source-ip-as-remote-address: true # 关闭在线文档(生产环境建议关闭) springdoc: web_src/src/components/dialog/devicePlayer.vue
@@ -53,93 +53,93 @@ 更多地址<i class="el-icon-arrow-down el-icon--right"></i> </el-button> <el-dropdown-menu slot="dropdown" > <el-dropdown-item v-if="streamInfo.flv" :command="streamInfo.flv.url"> <el-dropdown-item v-if="streamInfo.flv" :command="streamInfo.flv"> <el-tag >FLV:</el-tag> <span>{{ streamInfo.flv.url }}</span> <span>{{ streamInfo.flv }}</span> </el-dropdown-item> <el-dropdown-item v-if="streamInfo.https_flv" :command="streamInfo.https_flv.url"> <el-dropdown-item v-if="streamInfo.https_flv" :command="streamInfo.https_flv"> <el-tag >FLV(https):</el-tag> <span>{{ streamInfo.https_flv.url }}</span> <span>{{ streamInfo.https_flv }}</span> </el-dropdown-item> <el-dropdown-item v-if="streamInfo.ws_flv" :command="streamInfo.ws_flv.url"> <el-dropdown-item v-if="streamInfo.ws_flv" :command="streamInfo.ws_flv"> <el-tag >FLV(ws):</el-tag> <span >{{ streamInfo.ws_flv.url }}</span> <span >{{ streamInfo.ws_flv }}</span> </el-dropdown-item> <el-dropdown-item v-if="streamInfo.wss_flv" :command="streamInfo.wss_flv.url"> <el-dropdown-item v-if="streamInfo.wss_flv" :command="streamInfo.wss_flv"> <el-tag >FLV(wss):</el-tag> <span>{{ streamInfo.wss_flv.url }}</span> <span>{{ streamInfo.wss_flv }}</span> </el-dropdown-item> <el-dropdown-item v-if="streamInfo.fmp4" :command="streamInfo.fmp4.url"> <el-dropdown-item v-if="streamInfo.fmp4" :command="streamInfo.fmp4"> <el-tag >FMP4:</el-tag> <span>{{ streamInfo.fmp4.url }}</span> <span>{{ streamInfo.fmp4 }}</span> </el-dropdown-item> <el-dropdown-item v-if="streamInfo.https_fmp4" :command="streamInfo.https_fmp4.url"> <el-dropdown-item v-if="streamInfo.https_fmp4" :command="streamInfo.https_fmp4"> <el-tag >FMP4(https):</el-tag> <span>{{ streamInfo.https_fmp4.url }}</span> <span>{{ streamInfo.https_fmp4 }}</span> </el-dropdown-item> <el-dropdown-item v-if="streamInfo.ws_fmp4" :command="streamInfo.ws_fmp4.url"> <el-dropdown-item v-if="streamInfo.ws_fmp4" :command="streamInfo.ws_fmp4"> <el-tag >FMP4(ws):</el-tag> <span>{{ streamInfo.ws_fmp4.url }}</span> <span>{{ streamInfo.ws_fmp4 }}</span> </el-dropdown-item> <el-dropdown-item v-if="streamInfo.wss_fmp4" :command="streamInfo.wss_fmp4.url"> <el-dropdown-item v-if="streamInfo.wss_fmp4" :command="streamInfo.wss_fmp4"> <el-tag >FMP4(wss):</el-tag> <span>{{ streamInfo.wss_fmp4.url }}</span> <span>{{ streamInfo.wss_fmp4 }}</span> </el-dropdown-item> <el-dropdown-item v-if="streamInfo.hls" :command="streamInfo.hls.url"> <el-dropdown-item v-if="streamInfo.hls" :command="streamInfo.hls"> <el-tag>HLS:</el-tag> <span>{{ streamInfo.hls.url }}</span> <span>{{ streamInfo.hls }}</span> </el-dropdown-item> <el-dropdown-item v-if="streamInfo.https_hls" :command="streamInfo.https_hls.url"> <el-dropdown-item v-if="streamInfo.https_hls" :command="streamInfo.https_hls"> <el-tag >HLS(https):</el-tag> <span>{{ streamInfo.https_hls.url }}</span> <span>{{ streamInfo.https_hls }}</span> </el-dropdown-item> <el-dropdown-item v-if="streamInfo.ws_hls" :command="streamInfo.ws_hls.url"> <el-dropdown-item v-if="streamInfo.ws_hls" :command="streamInfo.ws_hls"> <el-tag >HLS(ws):</el-tag> <span>{{ streamInfo.ws_hls.url }}</span> <span>{{ streamInfo.ws_hls }}</span> </el-dropdown-item> <el-dropdown-item v-if="streamInfo.wss_hls" :command="streamInfo.wss_hls.url"> <el-dropdown-item v-if="streamInfo.wss_hls" :command="streamInfo.wss_hls"> <el-tag >HLS(wss):</el-tag> <span>{{ streamInfo.wss_hls.url }}</span> <span>{{ streamInfo.wss_hls }}</span> </el-dropdown-item> <el-dropdown-item v-if="streamInfo.ts" :command="streamInfo.ts.url"> <el-dropdown-item v-if="streamInfo.ts" :command="streamInfo.ts"> <el-tag>TS:</el-tag> <span>{{ streamInfo.ts.url }}</span> <span>{{ streamInfo.ts }}</span> </el-dropdown-item> <el-dropdown-item v-if="streamInfo.https_ts" :command="streamInfo.https_ts.url"> <el-dropdown-item v-if="streamInfo.https_ts" :command="streamInfo.https_ts"> <el-tag>TS(https):</el-tag> <span>{{ streamInfo.https_ts.url }}</span> <span>{{ streamInfo.https_ts }}</span> </el-dropdown-item> <el-dropdown-item v-if="streamInfo.ws_ts" :command="streamInfo.ws_ts.url"> <el-dropdown-item v-if="streamInfo.ws_ts" :command="streamInfo.ws_ts"> <el-tag>TS(ws):</el-tag> <span>{{ streamInfo.ws_ts.url }}</span> <span>{{ streamInfo.ws_ts }}</span> </el-dropdown-item> <el-dropdown-item v-if="streamInfo.wss_ts" :command="streamInfo.wss_ts.url"> <el-dropdown-item v-if="streamInfo.wss_ts" :command="streamInfo.wss_ts"> <el-tag>TS(wss):</el-tag> <span>{{ streamInfo.wss_ts.url }}</span> <span>{{ streamInfo.wss_ts }}</span> </el-dropdown-item> <el-dropdown-item v-if="streamInfo.rtc" :command="streamInfo.rtc.url"> <el-dropdown-item v-if="streamInfo.rtc" :command="streamInfo.rtc"> <el-tag >RTC:</el-tag> <span>{{ streamInfo.rtc.url }}</span> <span>{{ streamInfo.rtc }}</span> </el-dropdown-item> <el-dropdown-item v-if="streamInfo.rtcs" :command="streamInfo.rtcs.url"> <el-dropdown-item v-if="streamInfo.rtcs" :command="streamInfo.rtcs"> <el-tag >RTCS:</el-tag> <span>{{ streamInfo.rtcs.url }}</span> <span>{{ streamInfo.rtcs }}</span> </el-dropdown-item> <el-dropdown-item v-if="streamInfo.rtmp" :command="streamInfo.rtmp.url"> <el-dropdown-item v-if="streamInfo.rtmp" :command="streamInfo.rtmp"> <el-tag >RTMP:</el-tag> <span>{{ streamInfo.rtmp.url }}</span> <span>{{ streamInfo.rtmp }}</span> </el-dropdown-item> <el-dropdown-item v-if="streamInfo.rtmps" :command="streamInfo.rtmps.url"> <el-dropdown-item v-if="streamInfo.rtmps" :command="streamInfo.rtmps"> <el-tag >RTMPS:</el-tag> <span>{{ streamInfo.rtmps.url }}</span> <span>{{ streamInfo.rtmps }}</span> </el-dropdown-item> <el-dropdown-item v-if="streamInfo.rtsp" :command="streamInfo.rtsp.url"> <el-dropdown-item v-if="streamInfo.rtsp" :command="streamInfo.rtsp"> <el-tag >RTSP:</el-tag> <span>{{ streamInfo.rtsp.url }}</span> <span>{{ streamInfo.rtsp }}</span> </el-dropdown-item> <el-dropdown-item v-if="streamInfo.rtsps" :command="streamInfo.rtsps.url"> <el-dropdown-item v-if="streamInfo.rtsps" :command="streamInfo.rtsps"> <el-tag >RTSPS:</el-tag> <span>{{ streamInfo.rtsps.url }}</span> <span>{{ streamInfo.rtsps }}</span> </el-dropdown-item> </el-dropdown-menu> </el-dropdown> @@ -450,9 +450,9 @@ getUrlByStreamInfo(){ console.log(this.streamInfo) if (location.protocol === "https:") { this.videoUrl = this.streamInfo[this.player[this.activePlayer][1]].url this.videoUrl = this.streamInfo[this.player[this.activePlayer][1]] }else { this.videoUrl = this.streamInfo[this.player[this.activePlayer][0]].url this.videoUrl = this.streamInfo[this.player[this.activePlayer][0]] } return this.videoUrl;