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