Commit 89a9ab4534f10a224f70e546db838423e84a1965

Authored by 64850858
1 parent 06d78575

添加zlm集群支持

Showing 75 changed files with 2415 additions and 898 deletions
... ... @@ -196,6 +196,16 @@
196 196 <version>1.12</version>
197 197 </dependency>
198 198  
  199 +<!-- &lt;!&ndash; 检测文件编码 &ndash;&gt;-->
  200 +<!-- &lt;!&ndash; https://mvnrepository.com/artifact/cpdetector/cpdetector &ndash;&gt;-->
  201 +<!-- <dependency>-->
  202 +<!-- <groupId>cpdetector</groupId>-->
  203 +<!-- <artifactId>cpdetector</artifactId>-->
  204 +<!-- <version>1.0.8</version>-->
  205 +<!-- </dependency>-->
  206 +
  207 +
  208 +
199 209 <!-- onvif协议栈 -->
200 210 <dependency>
201 211 <groupId>be.teletask</groupId>
... ...
sql/mysql.sql
... ... @@ -138,6 +138,7 @@ create table stream_proxy
138 138 timeout_ms int null,
139 139 ffmpeg_cmd_key varchar(255) null,
140 140 rtp_type varchar(50) null,
  141 + mediaServerId varchar(50) null,
141 142 enable_hls bit(1) null,
142 143 enable_mp4 bit(1) null,
143 144 enable bit(1) not null,
... ... @@ -166,4 +167,28 @@ create table user
166 167 create_time varchar(50) not null
167 168 );
168 169  
169   -insert into user (username, password, roleId, create_time) values ('admin', '21232f297a57a5a743894a0e4a801fc3', '0', '2021-04-13 14:14:57');
170 170 \ No newline at end of file
  171 +insert into user (username, password, roleId, create_time) values ('admin', '21232f297a57a5a743894a0e4a801fc3', '0', '2021-04-13 14:14:57');
  172 +
  173 +create table media_server (
  174 + id varchar(255)
  175 + primary key,
  176 + ip varchar(50) NOT NULL,
  177 + hookIp varchar(50) NOT NULL,
  178 + sdpIp varchar(50) NOT NULL,
  179 + streamIp varchar(50) NOT NULL,
  180 + httpPort int NOT NULL,
  181 + httpSSlPort int NOT NULL,
  182 + rtmpPort int NOT NULL,
  183 + rtmpSSlPort int NOT NULL,
  184 + rtpProxyPort int NOT NULL,
  185 + rtspPort int NOT NULL,
  186 + rtspSSLPort int NOT NULL,
  187 + autoConfig int NOT NULL,
  188 + secret varchar(50) NOT NULL,
  189 + streamNoneReaderDelayMS int NOT NULL,
  190 + rtpEnable int NOT NULL,
  191 + rtpPortRange varchar(50) NOT NULL,
  192 + recordAssistPort int NOT NULL,
  193 + createTime varchar(50) not null,
  194 + updateTime varchar(50) not null
  195 +);
171 196 \ No newline at end of file
... ...
src/main/java/com/genersoft/iot/vmp/common/StreamInfo.java
... ... @@ -19,6 +19,7 @@ public class StreamInfo {
19 19 private String rtmp;
20 20 private String rtsp;
21 21 private String rtc;
  22 + private String mediaServerId;
22 23 private JSONArray tracks;
23 24  
24 25 public static class TransactionInfo{
... ... @@ -165,4 +166,12 @@ public class StreamInfo {
165 166 public void setTransactionInfo(TransactionInfo transactionInfo) {
166 167 this.transactionInfo = transactionInfo;
167 168 }
  169 +
  170 + public String getMediaServerId() {
  171 + return mediaServerId;
  172 + }
  173 +
  174 + public void setMediaServerId(String mediaServerId) {
  175 + this.mediaServerId = mediaServerId;
  176 + }
168 177 }
... ...
src/main/java/com/genersoft/iot/vmp/common/VideoManagerConstants.java
... ... @@ -10,33 +10,31 @@ public class VideoManagerConstants {
10 10  
11 11 public static final String WVP_SERVER_PREFIX = "VMP_wvp_server";
12 12  
13   - public static final String MEDIA_SERVER_PREFIX = "VMP_media_server";
  13 + public static final String MEDIA_SERVER_PREFIX = "VMP_MEDIA_SERVER_";
14 14  
15   - public static final String MEDIA_STREAM_PREFIX = "VMP_media_stream";
  15 + public static final String MEDIA_STREAM_PREFIX = "VMP_MEDIA_STREAM";
16 16  
17   - public static final String DEVICE_PREFIX = "VMP_device_";
  17 + public static final String DEVICE_PREFIX = "VMP_DEVICE_";
18 18  
19   - public static final String CACHEKEY_PREFIX = "VMP_channel_";
  19 + public static final String CACHEKEY_PREFIX = "VMP_CHANNEL_";
20 20  
21 21 public static final String KEEPLIVEKEY_PREFIX = "VMP_keeplive_";
22 22  
23   - public static final String PLAYER_PREFIX = "VMP_player_";
  23 + public static final String PLAYER_PREFIX = "VMP_PLAYER_";
24 24  
25   - public static final String PLAY_BLACK_PREFIX = "VMP_playback_";
  25 + public static final String PLAY_BLACK_PREFIX = "VMP_PLAYBACK_";
26 26  
27   - public static final String PLATFORM_PREFIX = "VMP_platform";
  27 + public static final String PLATFORM_KEEPLIVEKEY_PREFIX = "VMP_PLATFORM_KEEPLIVE_";
28 28  
29   - public static final String PLATFORM_KEEPLIVEKEY_PREFIX = "VMP_platform_keeplive_";
  29 + public static final String PLATFORM_CATCH_PREFIX = "VMP_PLATFORM_CATCH_";
30 30  
31   - public static final String PLATFORM_CATCH_PREFIX = "VMP_platform_catch_";
  31 + public static final String PLATFORM_REGISTER_PREFIX = "VMP_PLATFORM_REGISTER_";
32 32  
33   - public static final String PLATFORM_REGISTER_PREFIX = "VMP_platform_register_";
  33 + public static final String PLATFORM_REGISTER_INFO_PREFIX = "VMP_PLATFORM_REGISTER_INFO_";
34 34  
35   - public static final String PLATFORM_REGISTER_INFO_PREFIX = "VMP_platform_register_info_";
  35 + public static final String PLATFORM_SEND_RTP_INFO_PREFIX = "VMP_PLATFORM_SEND_RTP_INFO_";
36 36  
37   - public static final String PLATFORM_SEND_RTP_INFO_PREFIX = "VMP_platform_send_rtp_info_";
38   -
39   - public static final String Pattern_Topic = "VMP_keeplive_platform_";
  37 + public static final String Pattern_Topic = "VMP_KEEPLIVE_PLATFORM_";
40 38  
41 39 public static final String EVENT_ONLINE_REGISTER = "1";
42 40  
... ...
src/main/java/com/genersoft/iot/vmp/conf/MediaConfig.java
1 1 package com.genersoft.iot.vmp.conf;
2 2  
  3 +import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
  4 +import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
3 5 import org.springframework.beans.factory.annotation.Value;
4 6 import org.springframework.context.annotation.Configuration;
5 7 import org.springframework.util.StringUtils;
6 8  
7 9 @Configuration("mediaConfig")
8   -public class MediaConfig {
  10 +public class MediaConfig implements IMediaServerItem {
  11 +
  12 + @Value("${media.id:}")
  13 + private String id;
9 14  
10 15 @Value("${media.ip}")
11 16 private String ip;
... ... @@ -25,22 +30,22 @@ public class MediaConfig {
25 30 @Value("${media.http-port}")
26 31 private Integer httpPort;
27 32  
28   - @Value("${media.http-ssl-port:}")
  33 + @Value("${media.http-ssl-port:0}")
29 34 private Integer httpSSlPort;
30 35  
31   - @Value("${media.rtmp-port:}")
  36 + @Value("${media.rtmp-port:0}")
32 37 private Integer rtmpPort;
33 38  
34   - @Value("${media.rtmp-ssl-port:}")
  39 + @Value("${media.rtmp-ssl-port:0}")
35 40 private Integer rtmpSSlPort;
36 41  
37   - @Value("${media.rtp-proxy-port:}")
  42 + @Value("${media.rtp-proxy-port:0}")
38 43 private Integer rtpProxyPort;
39 44  
40   - @Value("${media.rtsp-port:}")
  45 + @Value("${media.rtsp-port:0}")
41 46 private Integer rtspPort;
42 47  
43   - @Value("${media.rtsp-ssl-port:}")
  48 + @Value("${media.rtsp-ssl-port:0}")
44 49 private Integer rtspSSLPort;
45 50  
46 51 @Value("${media.auto-config:true}")
... ... @@ -61,6 +66,23 @@ public class MediaConfig {
61 66 @Value("${media.record-assist-port:0}")
62 67 private Integer recordAssistPort;
63 68  
  69 + private String updateTime;
  70 +
  71 + private String createTime;
  72 +
  73 + private boolean docker = false;
  74 +
  75 + private int count;
  76 +
  77 +
  78 + public String getId() {
  79 + return id;
  80 + }
  81 +
  82 + public void setId(String id) {
  83 + this.id = id;
  84 + }
  85 +
64 86 public String getIp() {
65 87 return ip;
66 88 }
... ... @@ -82,82 +104,114 @@ public class MediaConfig {
82 104 this.hookIp = hookIp;
83 105 }
84 106  
85   - public String getSdpIp() {
86   - if (StringUtils.isEmpty(sdpIp)){
87   - return ip;
88   - }else {
89   - return sdpIp;
90   - }
  107 + public String getSipIp() {
  108 + return sipIp;
91 109 }
92 110  
93   - public void setSdpIp(String sdpIp) {
94   - this.sdpIp = sdpIp;
  111 + public void setSipIp(String sipIp) {
  112 + this.sipIp = sipIp;
95 113 }
96 114  
97   - public String getStreamIp() {
98   - if (StringUtils.isEmpty(streamIp)){
99   - return ip;
100   - }else {
101   - return streamIp;
102   - }
  115 + public void setSdpIp(String sdpIp) {
  116 + this.sdpIp = sdpIp;
103 117 }
104 118  
105 119 public void setStreamIp(String streamIp) {
106 120 this.streamIp = streamIp;
107 121 }
108 122  
109   - public Integer getHttpPort() {
  123 + public int getHttpPort() {
110 124 return httpPort;
111 125 }
112 126  
  127 + @Override
  128 + public void setHttpPort(int httpPort) {
  129 +
  130 + }
  131 +
113 132 public void setHttpPort(Integer httpPort) {
114 133 this.httpPort = httpPort;
115 134 }
116 135  
117   - public Integer getHttpSSlPort() {
  136 + public int getHttpSSlPort() {
118 137 return httpSSlPort;
119 138 }
120 139  
  140 + @Override
  141 + public void setHttpSSlPort(int httpSSlPort) {
  142 +
  143 + }
  144 +
121 145 public void setHttpSSlPort(Integer httpSSlPort) {
122 146 this.httpSSlPort = httpSSlPort;
123 147 }
124 148  
125   - public Integer getRtmpPort() {
  149 + public int getRtmpPort() {
126 150 return rtmpPort;
127 151 }
128 152  
  153 + @Override
  154 + public void setRtmpPort(int rtmpPort) {
  155 +
  156 + }
  157 +
129 158 public void setRtmpPort(Integer rtmpPort) {
130 159 this.rtmpPort = rtmpPort;
131 160 }
132 161  
133   - public Integer getRtmpSSlPort() {
  162 + public int getRtmpSSlPort() {
134 163 return rtmpSSlPort;
135 164 }
136 165  
  166 + @Override
  167 + public void setRtmpSSlPort(int rtmpSSlPort) {
  168 +
  169 + }
  170 +
137 171 public void setRtmpSSlPort(Integer rtmpSSlPort) {
138 172 this.rtmpSSlPort = rtmpSSlPort;
139 173 }
140 174  
141   - public Integer getRtpProxyPort() {
142   - return rtpProxyPort;
  175 + public int getRtpProxyPort() {
  176 + if (rtpProxyPort == null) {
  177 + return 0;
  178 + }else {
  179 + return rtpProxyPort;
  180 + }
  181 +
  182 + }
  183 +
  184 + @Override
  185 + public void setRtpProxyPort(int rtpProxyPort) {
  186 +
143 187 }
144 188  
145 189 public void setRtpProxyPort(Integer rtpProxyPort) {
146 190 this.rtpProxyPort = rtpProxyPort;
147 191 }
148 192  
149   - public Integer getRtspPort() {
  193 + public int getRtspPort() {
150 194 return rtspPort;
151 195 }
152 196  
  197 + @Override
  198 + public void setRtspPort(int rtspPort) {
  199 +
  200 + }
  201 +
153 202 public void setRtspPort(Integer rtspPort) {
154 203 this.rtspPort = rtspPort;
155 204 }
156 205  
157   - public Integer getRtspSSLPort() {
  206 + public int getRtspSSLPort() {
158 207 return rtspSSLPort;
159 208 }
160 209  
  210 + @Override
  211 + public void setRtspSSLPort(int rtspSSLPort) {
  212 +
  213 + }
  214 +
161 215 public void setRtspSSLPort(Integer rtspSSLPort) {
162 216 this.rtspSSLPort = rtspSSLPort;
163 217 }
... ... @@ -202,11 +256,101 @@ public class MediaConfig {
202 256 this.rtpPortRange = rtpPortRange;
203 257 }
204 258  
205   - public Integer getRecordAssistPort() {
  259 + public int getRecordAssistPort() {
206 260 return recordAssistPort;
207 261 }
208 262  
  263 + @Override
  264 + public void setRecordAssistPort(int recordAssistPort) {
  265 +
  266 + }
  267 +
209 268 public void setRecordAssistPort(Integer recordAssistPort) {
210 269 this.recordAssistPort = recordAssistPort;
211 270 }
  271 +
  272 + @Override
  273 + public boolean isDocker() {
  274 + return docker;
  275 + }
  276 +
  277 + @Override
  278 + public void setDocker(boolean docker) {
  279 + this.docker = docker;
  280 + }
  281 +
  282 + public String getSdpIp() {
  283 + if (StringUtils.isEmpty(sdpIp)){
  284 + return ip;
  285 + }else {
  286 + return sdpIp;
  287 + }
  288 + }
  289 +
  290 + public String getStreamIp() {
  291 + if (StringUtils.isEmpty(streamIp)){
  292 + return ip;
  293 + }else {
  294 + return streamIp;
  295 + }
  296 + }
  297 +
  298 +
  299 +
  300 + public MediaServerItem getMediaSerItem(){
  301 + MediaServerItem mediaServerItem = new MediaServerItem();
  302 + mediaServerItem.setId(id);
  303 + mediaServerItem.setIp(ip);
  304 + mediaServerItem.setDocker(true);
  305 + mediaServerItem.setHookIp(hookIp);
  306 + mediaServerItem.setSdpIp(sdpIp);
  307 + mediaServerItem.setStreamIp(streamIp);
  308 + mediaServerItem.setHttpPort(httpPort);
  309 + mediaServerItem.setHttpSSlPort(httpSSlPort);
  310 + mediaServerItem.setRtmpPort(rtmpPort);
  311 + mediaServerItem.setRtmpSSlPort(rtmpSSlPort);
  312 + mediaServerItem.setRtpProxyPort(rtpProxyPort);
  313 + mediaServerItem.setRtspPort(rtspPort);
  314 + mediaServerItem.setRtspSSLPort(rtspSSLPort);
  315 + mediaServerItem.setAutoConfig(autoConfig);
  316 + mediaServerItem.setSecret(secret);
  317 + mediaServerItem.setStreamNoneReaderDelayMS(streamNoneReaderDelayMS);
  318 + mediaServerItem.setRtpEnable(rtpEnable);
  319 + mediaServerItem.setRtpPortRange(rtpPortRange);
  320 + mediaServerItem.setRecordAssistPort(recordAssistPort);
  321 + mediaServerItem.setCreateTime(createTime);
  322 + mediaServerItem.setUpdateTime(updateTime);
  323 + mediaServerItem.setCount(count);
  324 + return mediaServerItem;
  325 + }
  326 +
  327 + @Override
  328 + public String getUpdateTime() {
  329 + return updateTime;
  330 + }
  331 +
  332 + @Override
  333 + public void setUpdateTime(String updateTime) {
  334 + this.updateTime = updateTime;
  335 + }
  336 +
  337 + @Override
  338 + public String getCreateTime() {
  339 + return createTime;
  340 + }
  341 +
  342 + @Override
  343 + public void setCreateTime(String createTime) {
  344 + this.createTime = createTime;
  345 + }
  346 +
  347 + @Override
  348 + public int getCount() {
  349 + return count;
  350 + }
  351 +
  352 + @Override
  353 + public void setCount(int count) {
  354 + this.count = count;
  355 + }
212 356 }
... ...
src/main/java/com/genersoft/iot/vmp/conf/ProxyServletConfig.java
1 1 package com.genersoft.iot.vmp.conf;
2 2  
  3 +import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
  4 +import com.genersoft.iot.vmp.service.IMediaServerService;
  5 +import org.apache.catalina.connector.ClientAbortException;
  6 +import org.apache.http.HttpHost;
3 7 import org.apache.http.HttpRequest;
4 8 import org.apache.http.HttpResponse;
5   -import org.apache.catalina.connector.ClientAbortException;
6 9 import org.mitre.dsmiley.httpproxy.ProxyServlet;
7 10 import org.slf4j.Logger;
8 11 import org.slf4j.LoggerFactory;
9 12 import org.springframework.beans.factory.annotation.Autowired;
  13 +import org.springframework.beans.factory.annotation.Value;
10 14 import org.springframework.boot.web.servlet.ServletRegistrationBean;
11 15 import org.springframework.context.annotation.Bean;
12 16 import org.springframework.context.annotation.Configuration;
... ... @@ -24,13 +28,16 @@ public class ProxyServletConfig {
24 28 private final static Logger logger = LoggerFactory.getLogger(ProxyServletConfig.class);
25 29  
26 30 @Autowired
27   - private MediaConfig mediaConfig;
  31 + private IMediaServerService mediaServerService;
  32 +
  33 + @Value("${server.port}")
  34 + private int serverPort;
28 35  
29 36 @Bean
30 37 public ServletRegistrationBean zlmServletRegistrationBean(){
31 38 ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new ZLMProxySerlet(),"/zlm/*");
32 39 servletRegistrationBean.setName("zlm_Proxy");
33   - servletRegistrationBean.addInitParameter("targetUri", String.format("http://%s:%s", mediaConfig.getIp(), mediaConfig.getHttpPort()));
  40 + servletRegistrationBean.addInitParameter("targetUri", "http://127.0.0.1:6080");
34 41 servletRegistrationBean.addUrlMappings();
35 42 if (logger.isDebugEnabled()) {
36 43 servletRegistrationBean.addInitParameter("log", "true");
... ... @@ -38,24 +45,26 @@ public class ProxyServletConfig {
38 45 return servletRegistrationBean;
39 46 }
40 47  
41   - class ZLMProxySerlet extends ProxyServlet{
42   -
43   -
44   -
  48 + class ZLMProxySerlet extends ProxyServlet{
45 49 @Override
46 50 protected String rewriteQueryStringFromRequest(HttpServletRequest servletRequest, String queryString) {
47 51 String queryStr = super.rewriteQueryStringFromRequest(servletRequest, queryString);
48   - if (!StringUtils.isEmpty(queryStr)) {
49   - queryStr += "&secret=" + mediaConfig.getSecret();
50   - }else {
51   - queryStr = "secret=" + mediaConfig.getSecret();
  52 + IMediaServerItem mediaInfo = getMediaInfoByUri(servletRequest.getRequestURI());
  53 + if (mediaInfo != null) {
  54 + if (!StringUtils.isEmpty(queryStr)) {
  55 + queryStr += "&secret=" + mediaInfo.getSecret();
  56 + }else {
  57 + queryStr = "secret=" + mediaInfo.getSecret();
  58 + }
52 59 }
53 60 return queryStr;
54 61 }
55 62  
  63 + /**
  64 + * 异常处理
  65 + */
56 66 @Override
57 67 protected void handleRequestException(HttpRequest proxyRequest, HttpResponse proxyResonse, Exception e){
58   - //System.out.println(e.getMessage());
59 68 try {
60 69 super.handleRequestException(proxyRequest, proxyResonse, e);
61 70 } catch (ServletException servletException) {
... ... @@ -72,6 +81,64 @@ public class ProxyServletConfig {
72 81 logger.error("zlm 代理失败: ", e);
73 82 }
74 83 }
  84 +
  85 + /**
  86 + * 对于为按照格式请求的可以直接返回404
  87 + */
  88 + @Override
  89 + protected String getTargetUri(HttpServletRequest servletRequest) {
  90 + String requestURI = servletRequest.getRequestURI();
  91 + IMediaServerItem mediaInfo = getMediaInfoByUri(requestURI);
  92 +
  93 + String uri = null;
  94 + if (mediaInfo != null) {
  95 +// String realRequestURI = requestURI.substring(requestURI.indexOf(mediaInfo.getId())+ mediaInfo.getId().length());
  96 + uri = String.format("http://%s:%s", mediaInfo.getIp(), mediaInfo.getHttpPort());
  97 + }else {
  98 + uri = "http://127.0.0.1:" + serverPort +"/index/hook/null"; // 只是一个能返回404的请求而已, 其他的也可以
  99 + }
  100 + return uri;
  101 + }
  102 +
  103 + /**
  104 + * 动态替换请求目标
  105 + */
  106 + @Override
  107 + protected HttpHost getTargetHost(HttpServletRequest servletRequest) {
  108 + String requestURI = servletRequest.getRequestURI();
  109 + IMediaServerItem mediaInfo = getMediaInfoByUri(requestURI);
  110 + HttpHost host;
  111 + if (mediaInfo != null) {
  112 + host = new HttpHost(mediaInfo.getIp(), mediaInfo.getHttpPort());
  113 + }else {
  114 + host = new HttpHost("127.0.0.1", serverPort);
  115 + }
  116 + return host;
  117 +
  118 + }
  119 +
  120 + /**
  121 + * 根据uri获取流媒体信息
  122 + */
  123 + IMediaServerItem getMediaInfoByUri(String uri){
  124 + String[] split = uri.split("/");
  125 + String mediaServerId = split[2];
  126 + return mediaServerService.getOne(mediaServerId);
  127 + }
  128 +
  129 + /**
  130 + * 去掉url中的标志信息
  131 + */
  132 + @Override
  133 + protected String rewriteUrlFromRequest(HttpServletRequest servletRequest) {
  134 + String requestURI = servletRequest.getRequestURI();
  135 + IMediaServerItem mediaInfo = getMediaInfoByUri(requestURI);
  136 + String url = super.rewriteUrlFromRequest(servletRequest);
  137 + if (mediaInfo == null) {
  138 + return url;
  139 + }
  140 + return url.replace(mediaInfo.getId() + "/", "");
  141 + }
75 142 }
76 143  
77 144 }
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/SipLayer.java
... ... @@ -95,20 +95,43 @@ public class SipLayer implements SipListener {
95 95 tcpListeningPoint = sipStack.createListeningPoint(sipConfig.getMonitorIp(), sipConfig.getSipPort(), "TCP");
96 96 tcpSipProvider = sipStack.createSipProvider(tcpListeningPoint);
97 97 tcpSipProvider.addSipListener(this);
98   - logger.info("Sip Server TCP 启动成功 port {" + sipConfig.getSipPort() + "}");
99   - } catch (TransportNotSupportedException | InvalidArgumentException | TooManyListenersException | ObjectInUseException e) {
100   - logger.error(String.format("创建SIP服务失败: %s", e.getMessage()));
  98 + logger.info("Sip Server TCP 启动成功 port {" + sipConfig.getMonitorIp() + ":" + sipConfig.getSipPort() + "}");
  99 +// } catch (TransportNotSupportedException | InvalidArgumentException | TooManyListenersException | ObjectInUseException e) {
  100 +// logger.error(String.format("创建SIP服务失败: %s", e.getMessage()));
  101 +// }
  102 + } catch (TransportNotSupportedException e) {
  103 + e.printStackTrace();
  104 + } catch (InvalidArgumentException e) {
  105 + logger.error("无法使用 [ {}:{} ]作为SIP[ TCP ]服务,可排查: 1. sip.monitor-ip 是否为本机网卡IP; 2. sip.port 是否已被占用"
  106 + , sipConfig.getMonitorIp(), sipConfig.getSipPort());
  107 + } catch (TooManyListenersException e) {
  108 + e.printStackTrace();
  109 + } catch (ObjectInUseException e) {
  110 + e.printStackTrace();
101 111 }
102 112 return tcpSipProvider;
103 113 }
104 114  
105 115 @Bean("udpSipProvider")
106 116 @DependsOn("sipStack")
107   - private SipProvider startUdpListener() throws Exception {
108   - ListeningPoint udpListeningPoint = sipStack.createListeningPoint(sipConfig.getMonitorIp(), sipConfig.getSipPort(), "UDP");
109   - SipProvider udpSipProvider = sipStack.createSipProvider(udpListeningPoint);
110   - udpSipProvider.addSipListener(this);
111   - logger.info("Sip Server UDP 启动成功 port {" + sipConfig.getSipPort() + "}");
  117 + private SipProvider startUdpListener() {
  118 + ListeningPoint udpListeningPoint = null;
  119 + SipProvider udpSipProvider = null;
  120 + try {
  121 + udpListeningPoint = sipStack.createListeningPoint(sipConfig.getMonitorIp(), sipConfig.getSipPort(), "UDP");
  122 + udpSipProvider = sipStack.createSipProvider(udpListeningPoint);
  123 + udpSipProvider.addSipListener(this);
  124 + } catch (TransportNotSupportedException e) {
  125 + e.printStackTrace();
  126 + } catch (InvalidArgumentException e) {
  127 + logger.error("无法使用 [ {}:{} ]作为SIP[ UDP ]服务,可排查: 1. sip.monitor-ip 是否为本机网卡IP; 2. sip.port 是否已被占用"
  128 + , sipConfig.getMonitorIp(), sipConfig.getSipPort());
  129 + } catch (TooManyListenersException e) {
  130 + e.printStackTrace();
  131 + } catch (ObjectInUseException e) {
  132 + e.printStackTrace();
  133 + }
  134 + logger.info("Sip Server UDP 启动成功 port [" + sipConfig.getMonitorIp() + ":" + sipConfig.getSipPort() + "]");
112 135 return udpSipProvider;
113 136 }
114 137  
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/bean/Device.java
... ... @@ -94,6 +94,11 @@ public class Device {
94 94 */
95 95 private String updateTime;
96 96  
  97 + /**
  98 + * 设备使用的媒体id, 默认为null
  99 + */
  100 + private String mediaServerId;
  101 +
97 102 public String getDeviceId() {
98 103 return deviceId;
99 104 }
... ... @@ -229,4 +234,12 @@ public class Device {
229 234 public void setUpdateTime(String updateTime) {
230 235 this.updateTime = updateTime;
231 236 }
  237 +
  238 + public String getMediaServerId() {
  239 + return mediaServerId;
  240 + }
  241 +
  242 + public void setMediaServerId(String mediaServerId) {
  243 + this.mediaServerId = mediaServerId;
  244 + }
232 245 }
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/bean/GbStream.java
... ... @@ -9,6 +9,7 @@ public class GbStream extends PlatformGbStream{
9 9 private String stream;
10 10 private String gbId;
11 11 private String name;
  12 + private String mediaServerId;
12 13 private double longitude;
13 14 private double latitude;
14 15 private String streamType;
... ... @@ -77,4 +78,12 @@ public class GbStream extends PlatformGbStream{
77 78 public void setStatus(boolean status) {
78 79 this.status = status;
79 80 }
  81 +
  82 + public String getMediaServerId() {
  83 + return mediaServerId;
  84 + }
  85 +
  86 + public void setMediaServerId(String mediaServerId) {
  87 + this.mediaServerId = mediaServerId;
  88 + }
80 89 }
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/bean/SendRtpItem.java
... ... @@ -66,6 +66,11 @@ public class SendRtpItem {
66 66 */
67 67 private int localPort;
68 68  
  69 + /**
  70 + * 使用的流媒体
  71 + */
  72 + private String mediaServerId;
  73 +
69 74 public String getIp() {
70 75 return ip;
71 76 }
... ... @@ -161,4 +166,12 @@ public class SendRtpItem {
161 166 public void setTcpActive(boolean tcpActive) {
162 167 this.tcpActive = tcpActive;
163 168 }
  169 +
  170 + public String getMediaServerId() {
  171 + return mediaServerId;
  172 + }
  173 +
  174 + public void setMediaServerId(String mediaServerId) {
  175 + this.mediaServerId = mediaServerId;
  176 + }
164 177 }
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/event/platformNotRegister/PlatformNotRegisterEventLister.java
... ... @@ -6,6 +6,9 @@ import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
6 6 import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
7 7 import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform;
8 8 import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
  9 +import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
  10 +import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
  11 +import com.genersoft.iot.vmp.service.IMediaServerService;
9 12 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
10 13 import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
11 14 import org.slf4j.Logger;
... ... @@ -32,6 +35,8 @@ public class PlatformNotRegisterEventLister implements ApplicationListener&lt;Platf
32 35 private IVideoManagerStorager storager;
33 36 @Autowired
34 37 private IRedisCatchStorage redisCatchStorage;
  38 + @Autowired
  39 + private IMediaServerService mediaServerService;
35 40  
36 41 @Autowired
37 42 private SIPCommanderFroPlatform sipCommanderFroPlatform;
... ... @@ -62,22 +67,24 @@ public class PlatformNotRegisterEventLister implements ApplicationListener&lt;Platf
62 67 logger.info("停止[ {} ]的所有推流", event.getPlatformGbID());
63 68 StringBuilder app = new StringBuilder();
64 69 StringBuilder stream = new StringBuilder();
65   - for (int i = 0; i < sendRtpItems.size(); i++) {
  70 + for (SendRtpItem sendRtpItem : sendRtpItems) {
66 71 if (app.length() != 0) {
67 72 app.append(",");
68 73 }
69   - app.append(sendRtpItems.get(i).getApp());
  74 + app.append(sendRtpItem.getApp());
70 75 if (stream.length() != 0) {
71 76 stream.append(",");
72 77 }
73   - stream.append(sendRtpItems.get(i).getStreamId());
74   - redisCatchStorage.deleteSendRTPServer(event.getPlatformGbID(), sendRtpItems.get(i).getChannelId());
  78 + stream.append(sendRtpItem.getStreamId());
  79 + redisCatchStorage.deleteSendRTPServer(event.getPlatformGbID(), sendRtpItem.getChannelId());
  80 + IMediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId());
  81 + Map<String, Object> param = new HashMap<>();
  82 + param.put("vhost", "__defaultVhost__");
  83 + param.put("app", app.toString());
  84 + param.put("stream", stream.toString());
  85 + zlmrtpServerFactory.stopSendRtpStream(mediaInfo, param);
75 86 }
76   - Map<String, Object> param = new HashMap<>();
77   - param.put("vhost","__defaultVhost__");
78   - param.put("app", app.toString());
79   - param.put("stream", stream.toString());
80   - zlmrtpServerFactory.stopSendRtpStream(param);
  87 +
81 88  
82 89 }
83 90  
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPProcessorFactory.java
... ... @@ -9,6 +9,7 @@ import javax.sip.message.Response;
9 9  
10 10 import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform;
11 11 import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
  12 +import com.genersoft.iot.vmp.service.IMediaServerService;
12 13 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
13 14 import com.genersoft.iot.vmp.gb28181.transmit.response.impl.*;
14 15 import com.genersoft.iot.vmp.service.IPlayService;
... ... @@ -104,6 +105,9 @@ public class SIPProcessorFactory {
104 105 @Autowired
105 106 private ZLMRTPServerFactory zlmrtpServerFactory;
106 107  
  108 + @Autowired
  109 + private IMediaServerService mediaServerService;
  110 +
107 111  
108 112 // 注:这里使用注解会导致循环依赖注入,暂用springBean
109 113 private SipProvider tcpSipProvider;
... ... @@ -128,6 +132,7 @@ public class SIPProcessorFactory {
128 132 processor.setStorager(storager);
129 133 processor.setRedisCatchStorage(redisCatchStorage);
130 134 processor.setZlmrtpServerFactory(zlmrtpServerFactory);
  135 + processor.setMediaServerService(mediaServerService);
131 136 return processor;
132 137 } else if (Request.REGISTER.equals(method)) {
133 138 RegisterRequestProcessor processor = new RegisterRequestProcessor();
... ... @@ -148,6 +153,7 @@ public class SIPProcessorFactory {
148 153 processor.setRequestEvent(evt);
149 154 processor.setRedisCatchStorage(redisCatchStorage);
150 155 processor.setZlmrtpServerFactory(zlmrtpServerFactory);
  156 + processor.setMediaServerService(mediaServerService);
151 157 return processor;
152 158 } else if (Request.BYE.equals(method)) {
153 159 ByeRequestProcessor processor = new ByeRequestProcessor();
... ... @@ -155,6 +161,7 @@ public class SIPProcessorFactory {
155 161 processor.setRedisCatchStorage(redisCatchStorage);
156 162 processor.setZlmrtpServerFactory(zlmrtpServerFactory);
157 163 processor.setSIPCommander(cmder);
  164 + processor.setMediaServerService(mediaServerService);
158 165 return processor;
159 166 } else if (Request.CANCEL.equals(method)) {
160 167 CancelRequestProcessor processor = new CancelRequestProcessor();
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java
... ... @@ -3,6 +3,8 @@ package com.genersoft.iot.vmp.gb28181.transmit.cmd;
3 3 import com.genersoft.iot.vmp.gb28181.bean.Device;
4 4 import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
5 5 import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe;
  6 +import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
  7 +import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
6 8  
7 9 /**
8 10 * @Description:设备能力接口,用于定义设备的控制、查询能力
... ... @@ -90,7 +92,7 @@ public interface ISIPCommander {
90 92 * @param device 视频设备
91 93 * @param channelId 预览通道
92 94 */
93   - void playStreamCmd(Device device, String channelId, ZLMHttpHookSubscribe.Event event, SipSubscribe.Event errorEvent);
  95 + void playStreamCmd(IMediaServerItem mediaServerItem, Device device, String channelId, ZLMHttpHookSubscribe.Event event, SipSubscribe.Event errorEvent);
94 96  
95 97 /**
96 98 * 请求回放视频流
... ... @@ -100,7 +102,7 @@ public interface ISIPCommander {
100 102 * @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss
101 103 * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss
102 104 */
103   - void playbackStreamCmd(Device device, String channelId, String startTime, String endTime, ZLMHttpHookSubscribe.Event event, SipSubscribe.Event errorEvent);
  105 + void playbackStreamCmd(IMediaServerItem mediaServerItem,Device device, String channelId, String startTime, String endTime, ZLMHttpHookSubscribe.Event event, SipSubscribe.Event errorEvent);
104 106  
105 107 /**
106 108 * 视频流停止
... ... @@ -288,12 +290,4 @@ public interface ISIPCommander {
288 290 * @return true = 命令发送成功
289 291 */
290 292 boolean alarmSubscribe(Device device, int expires, String startPriority, String endPriority, String alarmMethod, String alarmType, String startTime, String endTime);
291   -
292   -
293   - /**
294   - * 释放rtpserver
295   - * @param device
296   - * @param channelId
297   - */
298   - void closeRTPServer(Device device, String channelId);
299 293 }
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java
... ... @@ -13,11 +13,10 @@ import com.alibaba.fastjson.JSONObject;
13 13 import com.genersoft.iot.vmp.common.StreamInfo;
14 14 import com.genersoft.iot.vmp.conf.MediaConfig;
15 15 import com.genersoft.iot.vmp.conf.UserSetup;
16   -import com.genersoft.iot.vmp.media.zlm.ZLMServerConfig;
  16 +import com.genersoft.iot.vmp.media.zlm.*;
17 17 import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
18   -import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe;
19   -import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
20   -import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
  18 +import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
  19 +import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
21 20 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
22 21 import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
23 22 import gov.nist.javax.sip.message.SIPRequest;
... ... @@ -37,6 +36,7 @@ import com.genersoft.iot.vmp.gb28181.transmit.cmd.SIPRequestHeaderProvider;
37 36 import com.genersoft.iot.vmp.gb28181.utils.DateUtil;
38 37 import com.genersoft.iot.vmp.gb28181.utils.NumericUtil;
39 38 import com.genersoft.iot.vmp.gb28181.utils.XmlUtil;
  39 +import org.springframework.util.StringUtils;
40 40  
41 41 /**
42 42 * @Description:设备能力接口,用于定义设备的控制、查询能力
... ... @@ -78,12 +78,6 @@ public class SIPCommander implements ISIPCommander {
78 78 private ZLMRTPServerFactory zlmrtpServerFactory;
79 79  
80 80 @Autowired
81   - private ZLMRESTfulUtils zlmresTfulUtils;
82   -
83   - @Autowired
84   - private MediaConfig mediaConfig;
85   -
86   - @Autowired
87 81 private UserSetup userSetup;
88 82  
89 83 @Autowired
... ... @@ -340,48 +334,45 @@ public class SIPCommander implements ISIPCommander {
340 334 * @param errorEvent sip错误订阅
341 335 */
342 336 @Override
343   - public void playStreamCmd(Device device, String channelId, ZLMHttpHookSubscribe.Event event, SipSubscribe.Event errorEvent) {
  337 + public void playStreamCmd(IMediaServerItem mediaServerItem, Device device, String channelId, ZLMHttpHookSubscribe.Event event, SipSubscribe.Event errorEvent) {
344 338 String streamId = null;
345 339 try {
346 340 if (device == null) return;
  341 + String streamMode = device.getStreamMode().toUpperCase();
  342 +
347 343 String ssrc = streamSession.createPlaySsrc();
348   - if (mediaConfig.isRtpEnable()) {
  344 + if (mediaServerItem.isRtpEnable()) {
349 345 streamId = String.format("gb_play_%s_%s", device.getDeviceId(), channelId);
350 346 }else {
351 347 streamId = String.format("%08x", Integer.parseInt(ssrc)).toUpperCase();
352 348 }
353   - String streamMode = device.getStreamMode().toUpperCase();
354   - ZLMServerConfig mediaInfo = redisCatchStorage.getMediaInfo();
355   - if (mediaInfo == null) {
356   - logger.warn("点播时发现ZLM尚未连接...");
357   - return;
358   - }
359 349 Integer mediaPort = null;
360 350 // 使用动态udp端口
361   - if (mediaConfig.isRtpEnable()) {
362   - mediaPort = zlmrtpServerFactory.createRTPServer(streamId);
  351 + if (mediaServerItem.isRtpEnable()) {
  352 + mediaPort = zlmrtpServerFactory.createRTPServer(mediaServerItem, streamId);
363 353 }else {
364   - mediaPort = mediaInfo.getRtpProxyPort();
  354 + mediaPort = mediaServerItem.getRtpProxyPort();
365 355 }
366   -
  356 + logger.info("{} 分配的ZLM为: {} [{}:{}]", streamId, mediaServerItem.getId(), mediaServerItem.getIp(), mediaPort);
367 357 // 添加订阅
368 358 JSONObject subscribeKey = new JSONObject();
369 359 subscribeKey.put("app", "rtp");
370 360 subscribeKey.put("stream", streamId);
371 361 subscribeKey.put("regist", true);
372   -
373   - subscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey, json->{
  362 + subscribeKey.put("mediaServerId", mediaServerItem.getId());
  363 + subscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey,
  364 + (IMediaServerItem mediaServerItemInUse, JSONObject json)->{
374 365 if (userSetup.isWaitTrack() && json.getJSONArray("tracks") == null) return;
375   - event.response(json);
  366 + event.response(mediaServerItemInUse, json);
376 367 subscribe.removeSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey);
377 368 });
378 369 //
379 370 StringBuffer content = new StringBuffer(200);
380 371 content.append("v=0\r\n");
381 372 // content.append("o=" + sipConfig.getSipId() + " 0 0 IN IP4 "+mediaInfo.getWanIp()+"\r\n");
382   - content.append("o="+"00000"+" 0 0 IN IP4 "+mediaInfo.getSdpIp()+"\r\n");
  373 + content.append("o="+"00000"+" 0 0 IN IP4 "+ mediaServerItem.getSdpIp() +"\r\n");
383 374 content.append("s=Play\r\n");
384   - content.append("c=IN IP4 "+mediaInfo.getSdpIp()+"\r\n");
  375 + content.append("c=IN IP4 "+ mediaServerItem.getSdpIp() +"\r\n");
385 376 content.append("t=0 0\r\n");
386 377  
387 378 if (userSetup.isSeniorSdp()) {
... ... @@ -459,21 +450,32 @@ public class SIPCommander implements ISIPCommander {
459 450 * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss
460 451 */
461 452 @Override
462   - public void playbackStreamCmd(Device device, String channelId, String startTime, String endTime, ZLMHttpHookSubscribe.Event event
  453 + public void playbackStreamCmd(IMediaServerItem mediaServerItem,Device device, String channelId, String startTime, String endTime, ZLMHttpHookSubscribe.Event event
463 454 , SipSubscribe.Event errorEvent) {
464 455 try {
465   - ZLMServerConfig mediaInfo = redisCatchStorage.getMediaInfo();
466 456 String ssrc = streamSession.createPlayBackSsrc();
467 457 String streamId = String.format("%08x", Integer.parseInt(ssrc)).toUpperCase();
  458 +
  459 + Integer mediaPort = null;
  460 + // 使用动态udp端口
  461 + if (mediaServerItem.isRtpEnable()) {
  462 + mediaPort = zlmrtpServerFactory.createRTPServer(mediaServerItem, streamId);
  463 + }else {
  464 + mediaPort = mediaServerItem.getRtpProxyPort();
  465 + }
  466 + logger.info("{} 分配的ZLM为: {} [{}:{}]", streamId, mediaServerItem.getId(), mediaServerItem.getIp(), mediaPort);
  467 +
468 468 // 添加订阅
469 469 JSONObject subscribeKey = new JSONObject();
470 470 subscribeKey.put("app", "rtp");
471 471 subscribeKey.put("stream", streamId);
472 472 subscribeKey.put("regist", true);
  473 + subscribeKey.put("mediaServerId", mediaServerItem.getId());
473 474 logger.debug("录像回放添加订阅,订阅内容:" + subscribeKey.toString());
474   - subscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey, json->{
  475 + subscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey,
  476 + (IMediaServerItem mediaServerItemInUse, JSONObject json)->{
475 477 if (userSetup.isWaitTrack() && json.getJSONArray("tracks") == null) return;
476   - event.response(json);
  478 + event.response(mediaServerItemInUse, json);
477 479 subscribe.removeSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey);
478 480 });
479 481  
... ... @@ -482,16 +484,12 @@ public class SIPCommander implements ISIPCommander {
482 484 content.append("o="+sipConfig.getSipId()+" 0 0 IN IP4 "+sipConfig.getSipIp()+"\r\n");
483 485 content.append("s=Playback\r\n");
484 486 content.append("u="+channelId+":0\r\n");
485   - content.append("c=IN IP4 "+mediaInfo.getSdpIp()+"\r\n");
  487 + content.append("c=IN IP4 "+mediaServerItem.getSdpIp()+"\r\n");
486 488 content.append("t="+DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(startTime)+" "
487 489 +DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(endTime) +"\r\n");
488   - Integer mediaPort = null;
489   - // 使用动态udp端口
490   - if (mediaConfig.isRtpEnable()) {
491   - mediaPort = zlmrtpServerFactory.createRTPServer(streamId);
492   - }else {
493   - mediaPort = mediaInfo.getRtpProxyPort();
494   - }
  490 +
  491 +
  492 +
495 493 String streamMode = device.getStreamMode().toUpperCase();
496 494  
497 495 if (userSetup.isSeniorSdp()) {
... ... @@ -560,56 +558,63 @@ public class SIPCommander implements ISIPCommander {
560 558  
561 559  
562 560 /**
563   - * 视频流停止
564   - *
  561 + * 视频流停止, 不使用回调
565 562 */
566 563 @Override
567 564 public void streamByeCmd(String deviceId, String channelId) {
568 565 streamByeCmd(deviceId, channelId, null);
569 566 }
  567 +
  568 + /**
  569 + * 视频流停止
  570 + */
570 571 @Override
571 572 public void streamByeCmd(String deviceId, String channelId, SipSubscribe.Event okEvent) {
572   -
  573 + StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(deviceId, channelId);
573 574 try {
574 575 ClientTransaction transaction = streamSession.getTransaction(deviceId, channelId);
575 576 // 服务重启后, 无法直接发送bye, 通过手动构建发送
  577 +// if (transaction == null) {
  578 +//
  579 +// if (streamInfo != null) {
  580 +// MediaServerItem mediaServerItem = redisCatchStorage.getMediaInfo(streamInfo.getMediaServerId());
  581 +// JSONObject mediaList = zlmresTfulUtils.getMediaList(mediaServerItem,streamInfo.getApp(), streamInfo.getStreamId());
  582 +// if (mediaList != null) { // 仍在推流才发送
  583 +// if (mediaList.getInteger("code") == 0) {
  584 +// JSONArray data = mediaList.getJSONArray("data");
  585 +// if (data != null && data.size() > 0) {
  586 +// Device device = storager.queryVideoDevice(deviceId);
  587 +// if (device != null) {
  588 +// StreamInfo.TransactionInfo transactionInfo = streamInfo.getTransactionInfo();
  589 +// try {
  590 +// Request byteRequest = headerProvider.createByteRequest(device, channelId,
  591 +// transactionInfo.branch,
  592 +// transactionInfo.localTag,
  593 +// transactionInfo.remoteTag,
  594 +// transactionInfo.callId);
  595 +// transmitRequest(device, byteRequest);
  596 +// } catch (InvalidArgumentException e) {
  597 +// e.printStackTrace();
  598 +// }
  599 +// }
  600 +// }
  601 +// }
  602 +// }
  603 +// redisCatchStorage.stopPlay(streamInfo);
  604 +// }
  605 +//
  606 +// if (okEvent != null) {
  607 +// okEvent.response(null);
  608 +// }
  609 +// return;
  610 +// }
576 611 if (transaction == null) {
577   -
578   - StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(deviceId, channelId);
579   - if (streamInfo != null) {
580   - JSONObject mediaList = zlmresTfulUtils.getMediaList(streamInfo.getApp(), streamInfo.getStreamId());
581   - if (mediaList != null) { // 仍在推流才发送
582   - if (mediaList.getInteger("code") == 0) {
583   - JSONArray data = mediaList.getJSONArray("data");
584   - if (data != null && data.size() > 0) {
585   - Device device = storager.queryVideoDevice(deviceId);
586   - if (device != null) {
587   - StreamInfo.TransactionInfo transactionInfo = streamInfo.getTransactionInfo();
588   - try {
589   - Request byteRequest = headerProvider.createByteRequest(device, channelId,
590   - transactionInfo.branch,
591   - transactionInfo.localTag,
592   - transactionInfo.remoteTag,
593   - transactionInfo.callId);
594   - transmitRequest(device, byteRequest);
595   - } catch (InvalidArgumentException e) {
596   - e.printStackTrace();
597   - }
598   - }
599   - }
600   - }
601   - }
602   - redisCatchStorage.stopPlay(streamInfo);
603   - }
604   -
605   - if (okEvent != null) {
606   - okEvent.response(null);
607   - }
  612 + logger.warn("[ {} -> {}]停止视频流的时候发现事务已丢失", deviceId, channelId);
608 613 return;
609 614 }
610   -
611 615 Dialog dialog = transaction.getDialog();
612 616 if (dialog == null) {
  617 + logger.warn("[ {} -> {}]停止视频流的时候发现对话已丢失", deviceId, channelId);
613 618 return;
614 619 }
615 620 Request byeRequest = dialog.createRequest(Request.BYE);
... ... @@ -632,7 +637,7 @@ public class SIPCommander implements ISIPCommander {
632 637 }
633 638  
634 639 dialog.sendRequest(clientTransaction);
635   - zlmrtpServerFactory.closeRTPServer(streamSession.getStreamId(deviceId, channelId));
  640 +
636 641 streamSession.remove(deviceId, channelId);
637 642 } catch (SipException | ParseException e) {
638 643 e.printStackTrace();
... ... @@ -721,7 +726,7 @@ public class SIPCommander implements ISIPCommander {
721 726 cmdXml.append("<Control>\r\n");
722 727 cmdXml.append("<CmdType>DeviceControl</CmdType>\r\n");
723 728 cmdXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
724   - if (XmlUtil.isEmpty(channelId)) {
  729 + if (StringUtils.isEmpty(channelId)) {
725 730 cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
726 731 } else {
727 732 cmdXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
... ... @@ -821,16 +826,16 @@ public class SIPCommander implements ISIPCommander {
821 826 cmdXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
822 827 cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
823 828 cmdXml.append("<AlarmCmd>ResetAlarm</AlarmCmd>\r\n");
824   - if (!XmlUtil.isEmpty(alarmMethod) || !XmlUtil.isEmpty(alarmType)) {
  829 + if (!StringUtils.isEmpty(alarmMethod) || !StringUtils.isEmpty(alarmType)) {
825 830 cmdXml.append("<Info>\r\n");
826 831 }
827   - if (!XmlUtil.isEmpty(alarmMethod)) {
  832 + if (!StringUtils.isEmpty(alarmMethod)) {
828 833 cmdXml.append("<AlarmMethod>" + alarmMethod + "</AlarmMethod>\r\n");
829 834 }
830   - if (!XmlUtil.isEmpty(alarmType)) {
  835 + if (!StringUtils.isEmpty(alarmType)) {
831 836 cmdXml.append("<AlarmType>" + alarmType + "</AlarmType>\r\n");
832 837 }
833   - if (!XmlUtil.isEmpty(alarmMethod) || !XmlUtil.isEmpty(alarmType)) {
  838 + if (!StringUtils.isEmpty(alarmMethod) || !StringUtils.isEmpty(alarmType)) {
834 839 cmdXml.append("</Info>\r\n");
835 840 }
836 841 cmdXml.append("</Control>\r\n");
... ... @@ -863,7 +868,7 @@ public class SIPCommander implements ISIPCommander {
863 868 cmdXml.append("<Control>\r\n");
864 869 cmdXml.append("<CmdType>DeviceControl</CmdType>\r\n");
865 870 cmdXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
866   - if (XmlUtil.isEmpty(channelId)) {
  871 + if (StringUtils.isEmpty(channelId)) {
867 872 cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
868 873 } else {
869 874 cmdXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
... ... @@ -901,7 +906,7 @@ public class SIPCommander implements ISIPCommander {
901 906 cmdXml.append("<Control>\r\n");
902 907 cmdXml.append("<CmdType>DeviceControl</CmdType>\r\n");
903 908 cmdXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
904   - if (XmlUtil.isEmpty(channelId)) {
  909 + if (StringUtils.isEmpty(channelId)) {
905 910 cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
906 911 } else {
907 912 cmdXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
... ... @@ -969,13 +974,13 @@ public class SIPCommander implements ISIPCommander {
969 974 cmdXml.append("<Control>\r\n");
970 975 cmdXml.append("<CmdType>DeviceConfig</CmdType>\r\n");
971 976 cmdXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
972   - if (XmlUtil.isEmpty(channelId)) {
  977 + if (StringUtils.isEmpty(channelId)) {
973 978 cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
974 979 } else {
975 980 cmdXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
976 981 }
977 982 cmdXml.append("<BasicParam>\r\n");
978   - if (!XmlUtil.isEmpty(name)) {
  983 + if (!StringUtils.isEmpty(name)) {
979 984 cmdXml.append("<Name>" + name + "</Name>\r\n");
980 985 }
981 986 if (NumericUtil.isInteger(expiration)) {
... ... @@ -1169,22 +1174,22 @@ public class SIPCommander implements ISIPCommander {
1169 1174 cmdXml.append("<CmdType>Alarm</CmdType>\r\n");
1170 1175 cmdXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
1171 1176 cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
1172   - if (!XmlUtil.isEmpty(startPriority)) {
  1177 + if (!StringUtils.isEmpty(startPriority)) {
1173 1178 cmdXml.append("<StartAlarmPriority>" + startPriority + "</StartAlarmPriority>\r\n");
1174 1179 }
1175   - if (!XmlUtil.isEmpty(endPriority)) {
  1180 + if (!StringUtils.isEmpty(endPriority)) {
1176 1181 cmdXml.append("<EndAlarmPriority>" + endPriority + "</EndAlarmPriority>\r\n");
1177 1182 }
1178   - if (!XmlUtil.isEmpty(alarmMethod)) {
  1183 + if (!StringUtils.isEmpty(alarmMethod)) {
1179 1184 cmdXml.append("<AlarmMethod>" + alarmMethod + "</AlarmMethod>\r\n");
1180 1185 }
1181   - if (!XmlUtil.isEmpty(alarmType)) {
  1186 + if (!StringUtils.isEmpty(alarmType)) {
1182 1187 cmdXml.append("<AlarmType>" + alarmType + "</AlarmType>\r\n");
1183 1188 }
1184   - if (!XmlUtil.isEmpty(startTime)) {
  1189 + if (!StringUtils.isEmpty(startTime)) {
1185 1190 cmdXml.append("<StartAlarmTime>" + startTime + "</StartAlarmTime>\r\n");
1186 1191 }
1187   - if (!XmlUtil.isEmpty(endTime)) {
  1192 + if (!StringUtils.isEmpty(endTime)) {
1188 1193 cmdXml.append("<EndAlarmTime>" + endTime + "</EndAlarmTime>\r\n");
1189 1194 }
1190 1195 cmdXml.append("</Query>\r\n");
... ... @@ -1218,7 +1223,7 @@ public class SIPCommander implements ISIPCommander {
1218 1223 cmdXml.append("<Query>\r\n");
1219 1224 cmdXml.append("<CmdType>ConfigDownload</CmdType>\r\n");
1220 1225 cmdXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
1221   - if (XmlUtil.isEmpty(channelId)) {
  1226 + if (StringUtils.isEmpty(channelId)) {
1222 1227 cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
1223 1228 } else {
1224 1229 cmdXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
... ... @@ -1253,7 +1258,7 @@ public class SIPCommander implements ISIPCommander {
1253 1258 cmdXml.append("<Query>\r\n");
1254 1259 cmdXml.append("<CmdType>PresetQuery</CmdType>\r\n");
1255 1260 cmdXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
1256   - if (XmlUtil.isEmpty(channelId)) {
  1261 + if (StringUtils.isEmpty(channelId)) {
1257 1262 cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
1258 1263 } else {
1259 1264 cmdXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
... ... @@ -1365,22 +1370,22 @@ public class SIPCommander implements ISIPCommander {
1365 1370 cmdXml.append("<CmdType>Alarm</CmdType>\r\n");
1366 1371 cmdXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
1367 1372 cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
1368   - if (!XmlUtil.isEmpty(startPriority)) {
  1373 + if (!StringUtils.isEmpty(startPriority)) {
1369 1374 cmdXml.append("<StartAlarmPriority>" + startPriority + "</StartAlarmPriority>\r\n");
1370 1375 }
1371   - if (!XmlUtil.isEmpty(endPriority)) {
  1376 + if (!StringUtils.isEmpty(endPriority)) {
1372 1377 cmdXml.append("<EndAlarmPriority>" + endPriority + "</EndAlarmPriority>\r\n");
1373 1378 }
1374   - if (!XmlUtil.isEmpty(alarmMethod)) {
  1379 + if (!StringUtils.isEmpty(alarmMethod)) {
1375 1380 cmdXml.append("<AlarmMethod>" + alarmMethod + "</AlarmMethod>\r\n");
1376 1381 }
1377   - if (!XmlUtil.isEmpty(alarmType)) {
  1382 + if (!StringUtils.isEmpty(alarmType)) {
1378 1383 cmdXml.append("<AlarmType>" + alarmType + "</AlarmType>\r\n");
1379 1384 }
1380   - if (!XmlUtil.isEmpty(startTime)) {
  1385 + if (!StringUtils.isEmpty(startTime)) {
1381 1386 cmdXml.append("<StartAlarmTime>" + startTime + "</StartAlarmTime>\r\n");
1382 1387 }
1383   - if (!XmlUtil.isEmpty(endTime)) {
  1388 + if (!StringUtils.isEmpty(endTime)) {
1384 1389 cmdXml.append("<EndAlarmTime>" + endTime + "</EndAlarmTime>\r\n");
1385 1390 }
1386 1391 cmdXml.append("</Query>\r\n");
... ... @@ -1431,16 +1436,4 @@ public class SIPCommander implements ISIPCommander {
1431 1436 clientTransaction.sendRequest();
1432 1437 return clientTransaction;
1433 1438 }
1434   -
1435   -
1436   -
1437   -
1438   - @Override
1439   - public void closeRTPServer(Device device, String channelId) {
1440   - if (mediaConfig.isRtpEnable()) {
1441   - String streamId = String.format("gb_play_%s_%s", device.getDeviceId(), channelId);
1442   - zlmrtpServerFactory.closeRTPServer(streamId);
1443   - }
1444   - streamSession.remove(device.getDeviceId(), channelId);
1445   - }
1446 1439 }
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/SIPRequestAbstractProcessor.java
... ... @@ -16,6 +16,8 @@ import javax.sip.message.Request;
16 16 import gov.nist.javax.sip.SipStackImpl;
17 17 import gov.nist.javax.sip.message.SIPRequest;
18 18 import gov.nist.javax.sip.stack.SIPServerTransaction;
  19 +import org.slf4j.Logger;
  20 +import org.slf4j.LoggerFactory;
19 21  
20 22 /**
21 23 * @Description:处理接收IPCamera发来的SIP协议请求消息
... ... @@ -24,6 +26,8 @@ import gov.nist.javax.sip.stack.SIPServerTransaction;
24 26 */
25 27 public abstract class SIPRequestAbstractProcessor implements ISIPRequestProcessor {
26 28  
  29 + private final static Logger logger = LoggerFactory.getLogger(SIPRequestAbstractProcessor.class);
  30 +
27 31 protected RequestEvent evt;
28 32  
29 33 private SipProvider tcpSipProvider;
... ... @@ -64,9 +68,9 @@ public abstract class SIPRequestAbstractProcessor implements ISIPRequestProcesso
64 68 }
65 69 }
66 70 } catch (TransactionAlreadyExistsException e) {
67   - e.printStackTrace();
  71 + logger.error(e.getMessage());
68 72 } catch (TransactionUnavailableException e) {
69   - e.printStackTrace();
  73 + logger.error(e.getMessage());
70 74 }
71 75 }
72 76 return serverTransaction;
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/AckRequestProcessor.java
... ... @@ -13,6 +13,9 @@ import com.genersoft.iot.vmp.common.StreamInfo;
13 13 import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
14 14 import com.genersoft.iot.vmp.gb28181.transmit.request.SIPRequestAbstractProcessor;
15 15 import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
  16 +import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
  17 +import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
  18 +import com.genersoft.iot.vmp.service.IMediaServerService;
16 19 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
17 20 import org.slf4j.Logger;
18 21 import org.slf4j.LoggerFactory;
... ... @@ -30,6 +33,8 @@ public class AckRequestProcessor extends SIPRequestAbstractProcessor {
30 33  
31 34 private ZLMRTPServerFactory zlmrtpServerFactory;
32 35  
  36 + private IMediaServerService mediaServerService;
  37 +
33 38 /**
34 39 * 处理 ACK请求
35 40 *
... ... @@ -76,18 +81,22 @@ public class AckRequestProcessor extends SIPRequestAbstractProcessor {
76 81 while (!rtpPushed) {
77 82 try {
78 83 if (System.currentTimeMillis() - startTime < 30 * 1000) {
79   - if (zlmrtpServerFactory.isStreamReady(streamInfo.getApp(), streamInfo.getStreamId())) {
  84 + IMediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId());
  85 + if (zlmrtpServerFactory.isStreamReady(mediaInfo, streamInfo.getApp(), streamInfo.getStreamId())) {
80 86 rtpPushed = true;
81   - logger.info("已获取设备推流,开始向上级推流");
82   - zlmrtpServerFactory.startSendRtpStream(param);
  87 + logger.info("已获取设备推流[{}/{}],开始向上级推流[{}:{}]",
  88 + streamInfo.getApp() ,streamInfo.getStreamId(), sendRtpItem.getIp(), sendRtpItem.getPort());
  89 + zlmrtpServerFactory.startSendRtpStream(mediaInfo, param);
83 90 } else {
84   - logger.info("等待设备推流.......");
  91 + logger.info("等待设备推流[{}/{}].......",
  92 + streamInfo.getApp() ,streamInfo.getStreamId());
85 93 Thread.sleep(1000);
86 94 continue;
87 95 }
88 96 } else {
89 97 rtpPushed = true;
90   - logger.info("设备推流超时,终止向上级推流");
  98 + logger.info("设备推流[{}/{}]超时,终止向上级推流",
  99 + streamInfo.getApp() ,streamInfo.getStreamId());
91 100 }
92 101 } catch (InterruptedException e) {
93 102 e.printStackTrace();
... ... @@ -123,4 +132,12 @@ public class AckRequestProcessor extends SIPRequestAbstractProcessor {
123 132 public void setZlmrtpServerFactory(ZLMRTPServerFactory zlmrtpServerFactory) {
124 133 this.zlmrtpServerFactory = zlmrtpServerFactory;
125 134 }
  135 +
  136 + public IMediaServerService getMediaServerService() {
  137 + return mediaServerService;
  138 + }
  139 +
  140 + public void setMediaServerService(IMediaServerService mediaServerService) {
  141 + this.mediaServerService = mediaServerService;
  142 + }
126 143 }
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/ByeRequestProcessor.java
... ... @@ -15,6 +15,9 @@ import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
15 15 import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander;
16 16 import com.genersoft.iot.vmp.gb28181.transmit.request.SIPRequestAbstractProcessor;
17 17 import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
  18 +import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
  19 +import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
  20 +import com.genersoft.iot.vmp.service.IMediaServerService;
18 21 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
19 22 import org.slf4j.Logger;
20 23 import org.slf4j.LoggerFactory;
... ... @@ -38,6 +41,8 @@ public class ByeRequestProcessor extends SIPRequestAbstractProcessor {
38 41  
39 42 private ZLMRTPServerFactory zlmrtpServerFactory;
40 43  
  44 + private IMediaServerService mediaServerService;
  45 +
41 46 /**
42 47 * 处理BYE请求
43 48 * @param evt
... ... @@ -60,9 +65,10 @@ public class ByeRequestProcessor extends SIPRequestAbstractProcessor {
60 65 param.put("stream",streamId);
61 66 param.put("ssrc",sendRtpItem.getSsrc());
62 67 logger.info("停止向上级推流:" + streamId);
63   - zlmrtpServerFactory.stopSendRtpStream(param);
  68 + IMediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId());
  69 + zlmrtpServerFactory.stopSendRtpStream(mediaInfo, param);
64 70 redisCatchStorage.deleteSendRTPServer(platformGbId, channelId);
65   - if (zlmrtpServerFactory.totalReaderCount(sendRtpItem.getApp(), streamId) == 0) {
  71 + if (zlmrtpServerFactory.totalReaderCount(mediaInfo, sendRtpItem.getApp(), streamId) == 0) {
66 72 logger.info(streamId + "无其它观看者,通知设备停止推流");
67 73 cmder.streamByeCmd(sendRtpItem.getDeviceId(), channelId);
68 74 }
... ... @@ -112,4 +118,11 @@ public class ByeRequestProcessor extends SIPRequestAbstractProcessor {
112 118 this.cmder = cmder;
113 119 }
114 120  
  121 + public IMediaServerService getMediaServerService() {
  122 + return mediaServerService;
  123 + }
  124 +
  125 + public void setMediaServerService(IMediaServerService mediaServerService) {
  126 + this.mediaServerService = mediaServerService;
  127 + }
115 128 }
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/InviteRequestProcessor.java
... ... @@ -11,12 +11,16 @@ import javax.sip.header.*;
11 11 import javax.sip.message.Request;
12 12 import javax.sip.message.Response;
13 13  
  14 +import com.genersoft.iot.vmp.common.StreamInfo;
14 15 import com.genersoft.iot.vmp.media.zlm.ZLMServerConfig;
15 16 import com.genersoft.iot.vmp.gb28181.bean.*;
16 17 import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
17 18 import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform;
18 19 import com.genersoft.iot.vmp.gb28181.transmit.request.SIPRequestAbstractProcessor;
19 20 import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
  21 +import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
  22 +import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
  23 +import com.genersoft.iot.vmp.service.IMediaServerService;
20 24 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
21 25 import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
22 26 import com.genersoft.iot.vmp.vmanager.gb28181.play.bean.PlayResult;
... ... @@ -51,6 +55,8 @@ public class InviteRequestProcessor extends SIPRequestAbstractProcessor {
51 55  
52 56 private ZLMRTPServerFactory zlmrtpServerFactory;
53 57  
  58 + private IMediaServerService mediaServerService;
  59 +
54 60 public ZLMRTPServerFactory getZlmrtpServerFactory() {
55 61 return zlmrtpServerFactory;
56 62 }
... ... @@ -91,6 +97,7 @@ public class InviteRequestProcessor extends SIPRequestAbstractProcessor {
91 97 // 查询平台下是否有该通道
92 98 DeviceChannel channel = storager.queryChannelInParentPlatform(requesterId, channelId);
93 99 GbStream gbStream = storager.queryStreamInParentPlatform(requesterId, channelId);
  100 + IMediaServerItem mediaServerItem = null;
94 101 // 不是通道可能是直播流
95 102 if (channel != null && gbStream == null ) {
96 103 if (channel.getStatus() == 0) {
... ... @@ -100,8 +107,15 @@ public class InviteRequestProcessor extends SIPRequestAbstractProcessor {
100 107 }
101 108 responseAck(evt, Response.CALL_IS_BEING_FORWARDED); // 通道存在,发181,呼叫转接中
102 109 }else if(channel == null && gbStream != null){
103   - Boolean streamReady = zlmrtpServerFactory.isStreamReady(gbStream.getApp(), gbStream.getStream());
104   - if (!streamReady) {
  110 + String mediaServerId = gbStream.getMediaServerId();
  111 + mediaServerItem = mediaServerService.getOne(mediaServerId);
  112 + if (mediaServerItem == null) {
  113 + logger.info("[ app={}, stream={} ]zlm找不到,返回410",gbStream.getApp(), gbStream.getStream());
  114 + responseAck(evt, Response.GONE, "media server not found");
  115 + return;
  116 + }
  117 + Boolean streamReady = zlmrtpServerFactory.isStreamReady(mediaServerItem, gbStream.getApp(), gbStream.getStream());
  118 + if (!streamReady ) {
105 119 logger.info("[ app={}, stream={} ]通道离线,返回400",gbStream.getApp(), gbStream.getStream());
106 120 responseAck(evt, Response.BAD_REQUEST, "channel [" + gbStream.getGbId() + "] offline");
107 121 return;
... ... @@ -130,8 +144,8 @@ public class InviteRequestProcessor extends SIPRequestAbstractProcessor {
130 144 //boolean recvonly = false;
131 145 boolean mediaTransmissionTCP = false;
132 146 Boolean tcpActive = null;
133   - for (int i = 0; i < mediaDescriptions.size(); i++) {
134   - MediaDescription mediaDescription = (MediaDescription)mediaDescriptions.get(i);
  147 + for (Object description : mediaDescriptions) {
  148 + MediaDescription mediaDescription = (MediaDescription) description;
135 149 Media media = mediaDescription.getMedia();
136 150  
137 151 Vector mediaFormats = media.getMediaFormats(false);
... ... @@ -147,7 +161,7 @@ public class InviteRequestProcessor extends SIPRequestAbstractProcessor {
147 161 mediaTransmissionTCP = true;
148 162 if ("active".equals(setup)) {
149 163 tcpActive = true;
150   - }else if ("passive".equals(setup)) {
  164 + } else if ("passive".equals(setup)) {
151 165 tcpActive = false;
152 166 }
153 167 }
... ... @@ -174,7 +188,13 @@ public class InviteRequestProcessor extends SIPRequestAbstractProcessor {
174 188 responseAck(evt, Response.SERVER_INTERNAL_ERROR);
175 189 return;
176 190 }
177   - SendRtpItem sendRtpItem = zlmrtpServerFactory.createSendRtpItem(addressStr, port, ssrc, requesterId,
  191 + mediaServerItem = playService.getNewMediaServerItem(device);
  192 + if (mediaServerItem == null) {
  193 + logger.warn("未找到可用的zlm");
  194 + responseAck(evt, Response.BUSY_HERE);
  195 + return;
  196 + }
  197 + SendRtpItem sendRtpItem = zlmrtpServerFactory.createSendRtpItem(mediaServerItem, addressStr, port, ssrc, requesterId,
178 198 device.getDeviceId(), channelId,
179 199 mediaTransmissionTCP);
180 200 if (tcpActive != null) {
... ... @@ -189,18 +209,18 @@ public class InviteRequestProcessor extends SIPRequestAbstractProcessor {
189 209 // 写入redis, 超时时回复
190 210 redisCatchStorage.updateSendRTPSever(sendRtpItem);
191 211 // 通知下级推流,
192   - PlayResult playResult = playService.play(device.getDeviceId(), channelId, (responseJSON)->{
  212 + PlayResult playResult = playService.play(mediaServerItem,device.getDeviceId(), channelId, (mediaServerItemInUSe, responseJSON)->{
193 213 // 收到推流, 回复200OK, 等待ack
194 214 // if (sendRtpItem == null) return;
195 215 sendRtpItem.setStatus(1);
196 216 redisCatchStorage.updateSendRTPSever(sendRtpItem);
197 217 // TODO 添加对tcp的支持
198   - ZLMServerConfig mediaInfo = redisCatchStorage.getMediaInfo();
  218 +
199 219 StringBuffer content = new StringBuffer(200);
200 220 content.append("v=0\r\n");
201   - content.append("o="+"00000"+" 0 0 IN IP4 "+mediaInfo.getSdpIp()+"\r\n");
  221 + content.append("o="+"00000"+" 0 0 IN IP4 "+mediaServerItemInUSe.getSdpIp()+"\r\n");
202 222 content.append("s=Play\r\n");
203   - content.append("c=IN IP4 "+mediaInfo.getSdpIp()+"\r\n");
  223 + content.append("c=IN IP4 "+mediaServerItemInUSe.getSdpIp()+"\r\n");
204 224 content.append("t=0 0\r\n");
205 225 content.append("m=video "+ sendRtpItem.getLocalPort()+" RTP/AVP 96\r\n");
206 226 content.append("a=sendonly\r\n");
... ... @@ -217,7 +237,7 @@ public class InviteRequestProcessor extends SIPRequestAbstractProcessor {
217 237 } catch (ParseException e) {
218 238 e.printStackTrace();
219 239 }
220   - } ,(event -> {
  240 + } ,((event) -> {
221 241 // 未知错误。直接转发设备点播的错误
222 242 Response response = null;
223 243 try {
... ... @@ -232,7 +252,7 @@ public class InviteRequestProcessor extends SIPRequestAbstractProcessor {
232 252 }
233 253  
234 254 }else if (gbStream != null) {
235   - SendRtpItem sendRtpItem = zlmrtpServerFactory.createSendRtpItem(addressStr, port, ssrc, requesterId,
  255 + SendRtpItem sendRtpItem = zlmrtpServerFactory.createSendRtpItem(mediaServerItem, addressStr, port, ssrc, requesterId,
236 256 gbStream.getApp(), gbStream.getStream(), channelId,
237 257 mediaTransmissionTCP);
238 258  
... ... @@ -251,12 +271,11 @@ public class InviteRequestProcessor extends SIPRequestAbstractProcessor {
251 271 sendRtpItem.setStatus(1);
252 272 redisCatchStorage.updateSendRTPSever(sendRtpItem);
253 273 // TODO 添加对tcp的支持
254   - ZLMServerConfig mediaInfo = redisCatchStorage.getMediaInfo();
255 274 StringBuffer content = new StringBuffer(200);
256 275 content.append("v=0\r\n");
257   - content.append("o="+"00000"+" 0 0 IN IP4 "+mediaInfo.getSdpIp()+"\r\n");
  276 + content.append("o="+"00000"+" 0 0 IN IP4 "+mediaServerItem.getSdpIp()+"\r\n");
258 277 content.append("s=Play\r\n");
259   - content.append("c=IN IP4 "+mediaInfo.getSdpIp()+"\r\n");
  278 + content.append("c=IN IP4 "+mediaServerItem.getSdpIp()+"\r\n");
260 279 content.append("t=0 0\r\n");
261 280 content.append("m=video "+ sendRtpItem.getLocalPort()+" RTP/AVP 96\r\n");
262 281 content.append("a=sendonly\r\n");
... ... @@ -444,4 +463,12 @@ public class InviteRequestProcessor extends SIPRequestAbstractProcessor {
444 463 public void setRedisCatchStorage(IRedisCatchStorage redisCatchStorage) {
445 464 this.redisCatchStorage = redisCatchStorage;
446 465 }
  466 +
  467 + public IMediaServerService getMediaServerService() {
  468 + return mediaServerService;
  469 + }
  470 +
  471 + public void setMediaServerService(IMediaServerService mediaServerService) {
  472 + this.mediaServerService = mediaServerService;
  473 + }
447 474 }
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/MessageRequestProcessor.java
... ... @@ -282,7 +282,7 @@ public class MessageRequestProcessor extends SIPRequestAbstractProcessor {
282 282 //String result = XmlUtil.getText(rootElement, "Result");
283 283 // 回复200 OK
284 284 responseAck(evt);
285   - if (rootElement.getName().equals("Response")) {//} !XmlUtil.isEmpty(result)) {
  285 + if (rootElement.getName().equals("Response")) {//} !StringUtils.isEmpty(result)) {
286 286 // 此处是对本平台发出DeviceControl指令的应答
287 287 JSONObject json = new JSONObject();
288 288 XmlUtil.node2Json(rootElement, json);
... ... @@ -299,7 +299,7 @@ public class MessageRequestProcessor extends SIPRequestAbstractProcessor {
299 299 String platformId = ((SipURI) ((HeaderAddress) evt.getRequest().getHeader(FromHeader.NAME)).getAddress().getURI()).getUser();
300 300 String targetGBId = ((SipURI) ((HeaderAddress) evt.getRequest().getHeader(ToHeader.NAME)).getAddress().getURI()).getUser();
301 301 // 远程启动功能
302   - if (!XmlUtil.isEmpty(XmlUtil.getText(rootElement, "TeleBoot"))) {
  302 + if (!StringUtils.isEmpty(XmlUtil.getText(rootElement, "TeleBoot"))) {
303 303 if (deviceId.equals(targetGBId)) {
304 304 // 远程启动本平台:需要在重新启动程序后先对SipStack解绑
305 305 logger.info("执行远程启动本平台命令");
... ... @@ -337,7 +337,7 @@ public class MessageRequestProcessor extends SIPRequestAbstractProcessor {
337 337 }
338 338 }
339 339 // 云台/前端控制命令
340   - if (!XmlUtil.isEmpty(XmlUtil.getText(rootElement,"PTZCmd")) && !deviceId.equals(targetGBId)) {
  340 + if (!StringUtils.isEmpty(XmlUtil.getText(rootElement,"PTZCmd")) && !deviceId.equals(targetGBId)) {
341 341 String cmdString = XmlUtil.getText(rootElement,"PTZCmd");
342 342 Device device = storager.queryVideoDeviceByPlatformIdAndChannelId(platformId, deviceId);
343 343 cmder.fronEndCmd(device, deviceId, cmdString);
... ... @@ -421,7 +421,7 @@ public class MessageRequestProcessor extends SIPRequestAbstractProcessor {
421 421 String deviceId = XmlUtil.getText(rootElement, "DeviceID");
422 422 // 回复200 OK
423 423 responseAck(evt);
424   - if (rootElement.getName().equals("Response")) {// !XmlUtil.isEmpty(result)) {
  424 + if (rootElement.getName().equals("Response")) {// !StringUtils.isEmpty(result)) {
425 425 // 此处是对本平台发出DeviceControl指令的应答
426 426 JSONObject json = new JSONObject();
427 427 XmlUtil.node2Json(rootElement, json);
... ... @@ -718,7 +718,7 @@ public class MessageRequestProcessor extends SIPRequestAbstractProcessor {
718 718 deviceAlarm.setLatitude(0.00);
719 719 }
720 720  
721   - if (!XmlUtil.isEmpty(deviceAlarm.getAlarmMethod())) {
  721 + if (!StringUtils.isEmpty(deviceAlarm.getAlarmMethod())) {
722 722 if ( deviceAlarm.getAlarmMethod().equals("4")) {
723 723 MobilePosition mobilePosition = new MobilePosition();
724 724 mobilePosition.setDeviceId(deviceAlarm.getDeviceId());
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/utils/XmlUtil.java
... ... @@ -17,6 +17,7 @@ import org.dom4j.Element;
17 17 import org.dom4j.io.SAXReader;
18 18 import org.slf4j.Logger;
19 19 import org.slf4j.LoggerFactory;
  20 +import org.springframework.util.StringUtils;
20 21  
21 22 /**
22 23 * 基于dom4j的工具包
... ... @@ -114,12 +115,12 @@ public class XmlUtil {
114 115 // 如果是属性
115 116 for (Object o : element.attributes()) {
116 117 Attribute attr = (Attribute) o;
117   - if (!isEmpty(attr.getValue())) {
  118 + if (!StringUtils.isEmpty(attr.getValue())) {
118 119 json.put("@" + attr.getName(), attr.getValue());
119 120 }
120 121 }
121 122 List<Element> chdEl = element.elements();
122   - if (chdEl.isEmpty() && !isEmpty(element.getText())) {// 如果没有子元素,只有一个值
  123 + if (chdEl.isEmpty() && !StringUtils.isEmpty(element.getText())) {// 如果没有子元素,只有一个值
123 124 json.put(element.getName(), element.getText());
124 125 }
125 126  
... ... @@ -150,7 +151,7 @@ public class XmlUtil {
150 151 } else { // 子元素没有子元素
151 152 for (Object o : element.attributes()) {
152 153 Attribute attr = (Attribute) o;
153   - if (!isEmpty(attr.getValue())) {
  154 + if (!StringUtils.isEmpty(attr.getValue())) {
154 155 json.put("@" + attr.getName(), attr.getValue());
155 156 }
156 157 }
... ... @@ -160,11 +161,4 @@ public class XmlUtil {
160 161 }
161 162 }
162 163 }
163   -
164   - public static boolean isEmpty(String str) {
165   - if (str == null || str.trim().isEmpty() || "null".equals(str)) {
166   - return true;
167   - }
168   - return false;
169   - }
170 164 }
... ...
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHTTPProxyController.java deleted 100644 → 0
1   -//package com.genersoft.iot.vmp.media.zlm;
2   -//
3   -//import com.genersoft.iot.vmp.conf.MediaConfig;
4   -//import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
5   -//import org.springframework.beans.factory.annotation.Autowired;
6   -//import org.springframework.beans.factory.annotation.Value;
7   -//import org.springframework.web.bind.annotation.*;
8   -//import org.springframework.web.client.HttpClientErrorException;
9   -//import org.springframework.web.client.RestTemplate;
10   -//
11   -//import javax.servlet.http.HttpServletRequest;
12   -//import javax.servlet.http.HttpServletResponse;
13   -//
14   -//@RestController
15   -//@RequestMapping("/zlm")
16   -//public class ZLMHTTPProxyController {
17   -//
18   -//
19   -// // private final static Logger logger = LoggerFactory.getLogger(ZLMHTTPProxyController.class);
20   -//
21   -// @Autowired
22   -// private IRedisCatchStorage redisCatchStorage;
23   -//
24   -// @Autowired
25   -// private MediaConfig mediaConfig;
26   -//
27   -// @ResponseBody
28   -// @RequestMapping(value = "/**/**/**", produces = "application/json;charset=UTF-8")
29   -// public Object proxy(HttpServletRequest request, HttpServletResponse response){
30   -//
31   -// if (redisCatchStorage.getMediaInfo() == null) {
32   -// return "未接入流媒体";
33   -// }
34   -// ZLMServerConfig mediaInfo = redisCatchStorage.getMediaInfo();
35   -// String requestURI = String.format("http://%s:%s%s?%s&%s",
36   -// mediaInfo.getLocalIP(),
37   -// mediaConfig.getHttpPort(),
38   -// request.getRequestURI().replace("/zlm",""),
39   -// mediaInfo.getHookAdminParams(),
40   -// request.getQueryString()
41   -// );
42   -// // 发送请求
43   -// RestTemplate restTemplate = new RestTemplate();
44   -// //将指定的url返回的参数自动封装到自定义好的对应类对象中
45   -// Object result = null;
46   -// try {
47   -// result = restTemplate.getForObject(requestURI,Object.class);
48   -//
49   -// }catch (HttpClientErrorException httpClientErrorException) {
50   -// response.setStatus(httpClientErrorException.getStatusCode().value());
51   -// }
52   -// return result;
53   -// }
54   -//}
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java
... ... @@ -9,6 +9,9 @@ import com.genersoft.iot.vmp.common.StreamInfo;
9 9 import com.genersoft.iot.vmp.conf.MediaConfig;
10 10 import com.genersoft.iot.vmp.conf.UserSetup;
11 11 import com.genersoft.iot.vmp.gb28181.bean.Device;
  12 +import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
  13 +import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
  14 +import com.genersoft.iot.vmp.service.IMediaServerService;
12 15 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
13 16 import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
14 17 import com.genersoft.iot.vmp.service.IPlayService;
... ... @@ -53,10 +56,10 @@ public class ZLMHttpHookListener {
53 56 private IRedisCatchStorage redisCatchStorage;
54 57  
55 58 @Autowired
56   - private ZLMRESTfulUtils zlmresTfulUtils;
  59 + private IMediaServerService mediaServerService;
57 60  
58 61 @Autowired
59   - private ZLMServerManger zlmServerManger;
  62 + private ZLMRESTfulUtils zlmresTfulUtils;
60 63  
61 64 @Autowired
62 65 private ZLMMediaListManager zlmMediaListManager;
... ... @@ -81,6 +84,7 @@ public class ZLMHttpHookListener {
81 84 if (logger.isDebugEnabled()) {
82 85 logger.debug("ZLM HOOK on_flow_report API调用,参数:" + json.toString());
83 86 }
  87 + String mediaServerId = json.getString("mediaServerId");
84 88 JSONObject ret = new JSONObject();
85 89 ret.put("code", 0);
86 90 ret.put("msg", "success");
... ... @@ -98,6 +102,7 @@ public class ZLMHttpHookListener {
98 102 if (logger.isDebugEnabled()) {
99 103 logger.debug("ZLM HOOK on_http_access API 调用,参数:" + json.toString());
100 104 }
  105 + String mediaServerId = json.getString("mediaServerId");
101 106 JSONObject ret = new JSONObject();
102 107 ret.put("code", 0);
103 108 ret.put("err", "");
... ... @@ -117,9 +122,14 @@ public class ZLMHttpHookListener {
117 122 if (logger.isDebugEnabled()) {
118 123 logger.debug("ZLM HOOK on_play API调用,参数:" + json.toString());
119 124 }
  125 + String mediaServerId = json.getString("mediaServerId");
120 126 ZLMHttpHookSubscribe.Event subscribe = this.subscribe.getSubscribe(ZLMHttpHookSubscribe.HookType.on_play, json);
121 127 if (subscribe != null ) {
122   - subscribe.response(json);
  128 + IMediaServerItem mediaInfo = mediaServerService.getOne(mediaServerId);
  129 + if (mediaInfo != null) {
  130 + subscribe.response(mediaInfo, json);
  131 + }
  132 +
123 133 }
124 134 JSONObject ret = new JSONObject();
125 135 ret.put("code", 0);
... ... @@ -133,20 +143,25 @@ public class ZLMHttpHookListener {
133 143 */
134 144 @ResponseBody
135 145 @PostMapping(value = "/on_publish", produces = "application/json;charset=UTF-8")
136   - public ResponseEntity<String> onPublish(@RequestBody JSONObject json){
  146 + public ResponseEntity<String> onPublish(@RequestBody JSONObject json) {
137 147  
138 148 logger.debug("ZLM HOOK on_publish API调用,参数:" + json.toString());
139 149  
  150 + String mediaServerId = json.getString("mediaServerId");
140 151 ZLMHttpHookSubscribe.Event subscribe = this.subscribe.getSubscribe(ZLMHttpHookSubscribe.HookType.on_publish, json);
141   - if (subscribe != null) subscribe.response(json);
142   -
  152 + if (subscribe != null) {
  153 + IMediaServerItem mediaInfo = mediaServerService.getOne(mediaServerId);
  154 + if (mediaInfo != null) {
  155 + subscribe.response(mediaInfo, json);
  156 + }
  157 + }
143 158 JSONObject ret = new JSONObject();
144 159 ret.put("code", 0);
145 160 ret.put("msg", "success");
146 161 ret.put("enableHls", true);
147 162 ret.put("enableMP4", userSetup.isRecordPushLive());
148 163 ret.put("enableRtxp", true);
149   - return new ResponseEntity<String>(ret.toString(),HttpStatus.OK);
  164 + return new ResponseEntity<String>(ret.toString(), HttpStatus.OK);
150 165 }
151 166  
152 167 /**
... ... @@ -160,6 +175,7 @@ public class ZLMHttpHookListener {
160 175 if (logger.isDebugEnabled()) {
161 176 logger.debug("ZLM HOOK on_record_mp4 API调用,参数:" + json.toString());
162 177 }
  178 + String mediaServerId = json.getString("mediaServerId");
163 179 JSONObject ret = new JSONObject();
164 180 ret.put("code", 0);
165 181 ret.put("msg", "success");
... ... @@ -177,6 +193,7 @@ public class ZLMHttpHookListener {
177 193 if (logger.isDebugEnabled()) {
178 194 logger.debug("ZLM HOOK on_rtsp_realm API调用,参数:" + json.toString());
179 195 }
  196 + String mediaServerId = json.getString("mediaServerId");
180 197 JSONObject ret = new JSONObject();
181 198 ret.put("code", 0);
182 199 ret.put("realm", "");
... ... @@ -195,6 +212,7 @@ public class ZLMHttpHookListener {
195 212 if (logger.isDebugEnabled()) {
196 213 logger.debug("ZLM HOOK on_rtsp_auth API调用,参数:" + json.toString());
197 214 }
  215 + String mediaServerId = json.getString("mediaServerId");
198 216 JSONObject ret = new JSONObject();
199 217 ret.put("code", 0);
200 218 ret.put("encrypted", false);
... ... @@ -216,9 +234,15 @@ public class ZLMHttpHookListener {
216 234 // TODO 如果是带有rtpstream则开启按需拉流
217 235 // String app = json.getString("app");
218 236 // String stream = json.getString("stream");
219   -
  237 + String mediaServerId = json.getString("mediaServerId");
220 238 ZLMHttpHookSubscribe.Event subscribe = this.subscribe.getSubscribe(ZLMHttpHookSubscribe.HookType.on_shell_login, json);
221   - if (subscribe != null) subscribe.response(json);
  239 + if (subscribe != null ) {
  240 + IMediaServerItem mediaInfo = mediaServerService.getOne(mediaServerId);
  241 + if (mediaInfo != null) {
  242 + subscribe.response(mediaInfo, json);
  243 + }
  244 +
  245 + }
222 246  
223 247 JSONObject ret = new JSONObject();
224 248 ret.put("code", 0);
... ... @@ -237,9 +261,15 @@ public class ZLMHttpHookListener {
237 261 if (logger.isDebugEnabled()) {
238 262 logger.debug("ZLM HOOK on_stream_changed API调用,参数:" + json.toString());
239 263 }
240   -
  264 + String mediaServerId = json.getString("mediaServerId");
241 265 ZLMHttpHookSubscribe.Event subscribe = this.subscribe.getSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, json);
242   - if (subscribe != null) subscribe.response(json);
  266 + if (subscribe != null ) {
  267 + IMediaServerItem mediaInfo = mediaServerService.getOne(mediaServerId);
  268 + if (mediaInfo != null) {
  269 + subscribe.response(mediaInfo, json);
  270 + }
  271 +
  272 + }
243 273  
244 274 // 流消失移除redis play
245 275 String app = json.getString("app");
... ... @@ -251,6 +281,11 @@ public class ZLMHttpHookListener {
251 281 logger.info("[stream: " + streamId + "] on_stream_changed->>" + schema);
252 282 }
253 283 if ("rtmp".equals(schema)){
  284 + if (regist) {
  285 + mediaServerService.addCount(mediaServerId);
  286 + }else {
  287 + mediaServerService.removeCount(mediaServerId);
  288 + }
254 289 if ("rtp".equals(app) && !regist ) {
255 290 StreamInfo streamInfo = redisCatchStorage.queryPlayByStreamId(streamId);
256 291 if (streamInfo!=null){
... ... @@ -262,10 +297,11 @@ public class ZLMHttpHookListener {
262 297 }
263 298 }else {
264 299 if (!"rtp".equals(app) ){
  300 + IMediaServerItem mediaServerItem = mediaServerService.getOne(mediaServerId);
265 301 if (regist) {
266   - zlmMediaListManager.addMedia(app, streamId);
  302 + zlmMediaListManager.addMedia(mediaServerItem, app, streamId);
267 303 }else {
268   - zlmMediaListManager.removeMedia(app, streamId);
  304 + zlmMediaListManager.removeMedia( app, streamId);
269 305 }
270 306 }
271 307 }
... ... @@ -288,7 +324,7 @@ public class ZLMHttpHookListener {
288 324 if (logger.isDebugEnabled()) {
289 325 logger.debug("ZLM HOOK on_stream_none_reader API调用,参数:" + json.toString());
290 326 }
291   -
  327 + String mediaServerId = json.getString("mediaServerId");
292 328 String streamId = json.getString("stream");
293 329 String app = json.getString("app");
294 330  
... ... @@ -329,11 +365,12 @@ public class ZLMHttpHookListener {
329 365 @ResponseBody
330 366 @PostMapping(value = "/on_stream_not_found", produces = "application/json;charset=UTF-8")
331 367 public ResponseEntity<String> onStreamNotFound(@RequestBody JSONObject json){
332   -
333 368 if (logger.isDebugEnabled()) {
334 369 logger.debug("ZLM HOOK on_stream_not_found API调用,参数:" + json.toString());
335 370 }
336   - if (userSetup.isAutoApplyPlay()) {
  371 + String mediaServerId = json.getString("mediaServerId");
  372 + IMediaServerItem mediaInfo = mediaServerService.getOne(mediaServerId);
  373 + if (userSetup.isAutoApplyPlay() && mediaInfo != null) {
337 374 String app = json.getString("app");
338 375 String streamId = json.getString("stream");
339 376 if ("rtp".equals(app) && streamId.contains("gb_play") ) {
... ... @@ -344,9 +381,9 @@ public class ZLMHttpHookListener {
344 381 Device device = storager.queryVideoDevice(deviceId);
345 382 if (device != null) {
346 383 UUID uuid = UUID.randomUUID();
347   - cmder.playStreamCmd(device, channelId, (JSONObject response) -> {
  384 + cmder.playStreamCmd(mediaInfo, device, channelId, (IMediaServerItem mediaServerItemInuse, JSONObject response) -> {
348 385 logger.info("收到订阅消息: " + response.toJSONString());
349   - playService.onPublishHandlerForPlay(response, deviceId, channelId, uuid.toString());
  386 + playService.onPublishHandlerForPlay(mediaServerItemInuse, response, deviceId, channelId, uuid.toString());
350 387 }, null);
351 388 }
352 389  
... ... @@ -367,26 +404,19 @@ public class ZLMHttpHookListener {
367 404 */
368 405 @ResponseBody
369 406 @PostMapping(value = "/on_server_started", produces = "application/json;charset=UTF-8")
370   - public ResponseEntity<String> onServerStarted(HttpServletRequest request, @RequestBody JSONObject json){
  407 + public ResponseEntity<String> onServerStarted(HttpServletRequest request, @RequestBody JSONObject jsonObject){
371 408  
372 409 if (logger.isDebugEnabled()) {
373   - logger.debug("ZLM HOOK on_server_started API调用,参数:" + json.toString());
  410 + logger.debug("ZLM HOOK on_server_started API调用,参数:" + jsonObject.toString());
374 411 }
375   -
376   -// String data = json.getString("data");
377   -// List<MediaServerConfig> mediaServerConfigs = JSON.parseArray(JSON.toJSONString(json), MediaServerConfig.class);
378   -// MediaServerConfig mediaServerConfig = mediaServerConfigs.get(0);
379   -
  412 + String remoteAddr = request.getRemoteAddr();
  413 + jsonObject.put("ip", remoteAddr);
380 414 List<ZLMHttpHookSubscribe.Event> subscribes = this.subscribe.getSubscribes(ZLMHttpHookSubscribe.HookType.on_server_started);
381   - if (subscribes != null && subscribes.size() > 0) {
  415 + if (subscribes != null && subscribes.size() > 0) {
382 416 for (ZLMHttpHookSubscribe.Event subscribe : subscribes) {
383   - subscribe.response(json);
  417 + subscribe.response(null, jsonObject);
384 418 }
385 419 }
386   - ZLMServerConfig ZLMServerConfig = JSON.toJavaObject(json, ZLMServerConfig.class);
387   - zlmServerManger.updateServerCatch(ZLMServerConfig);
388   - // 重新发起代理
389   -
390 420 JSONObject ret = new JSONObject();
391 421 ret.put("code", 0);
392 422 ret.put("msg", "success");
... ...
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookSubscribe.java
1 1 package com.genersoft.iot.vmp.media.zlm;
2 2  
3 3 import com.alibaba.fastjson.JSONObject;
  4 +import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
  5 +import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
4 6 import org.springframework.stereotype.Component;
5 7  
6 8 import java.util.*;
... ... @@ -30,7 +32,7 @@ public class ZLMHttpHookSubscribe {
30 32 }
31 33  
32 34 public interface Event{
33   - void response(JSONObject response);
  35 + void response(IMediaServerItem mediaServerItem, JSONObject response);
34 36 }
35 37  
36 38 private Map<HookType, Map<JSONObject, ZLMHttpHookSubscribe.Event>> allSubscribes = new ConcurrentHashMap<>();
... ...
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMMediaListManager.java
... ... @@ -2,6 +2,8 @@ package com.genersoft.iot.vmp.media.zlm;
2 2  
3 3 import com.alibaba.fastjson.JSONArray;
4 4 import com.alibaba.fastjson.JSONObject;
  5 +import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
  6 +import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
5 7 import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem;
6 8 import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem;
7 9 import com.genersoft.iot.vmp.gb28181.bean.GbStream;
... ... @@ -45,11 +47,11 @@ public class ZLMMediaListManager {
45 47 private ZLMHttpHookSubscribe subscribe;
46 48  
47 49  
48   - public void updateMediaList() {
  50 + public void updateMediaList(MediaServerItem mediaServerItem) {
49 51 storager.clearMediaList();
50 52  
51 53 // 使用异步的当时更新媒体流列表
52   - zlmresTfulUtils.getMediaList((mediaList ->{
  54 + zlmresTfulUtils.getMediaList(mediaServerItem, (mediaList ->{
53 55 if (mediaList == null) return;
54 56 String dataStr = mediaList.getString("data");
55 57  
... ... @@ -57,10 +59,10 @@ public class ZLMMediaListManager {
57 59 Map<String, StreamPushItem> result = new HashMap<>();
58 60 List<StreamPushItem> streamPushItems = null;
59 61 // 获取所有的国标关联
60   - List<GbStream> gbStreams = gbStreamMapper.selectAll();
  62 +// List<GbStream> gbStreams = gbStreamMapper.selectAllByMediaServerId(mediaServerItem.getId());
61 63 if (code == 0 ) {
62 64 if (dataStr != null) {
63   - streamPushItems = streamPushService.handleJSON(dataStr);
  65 + streamPushItems = streamPushService.handleJSON(dataStr, mediaServerItem);
64 66 }
65 67 }else {
66 68 logger.warn("更新视频流失败,错误code: " + code);
... ... @@ -72,24 +74,27 @@ public class ZLMMediaListManager {
72 74 JSONObject jsonObject = new JSONObject();
73 75 jsonObject.put("app", streamPushItem.getApp());
74 76 jsonObject.put("stream", streamPushItem.getStream());
75   - subscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_play,jsonObject,(response)->{
76   - updateMedia(response.getString("app"), response.getString("stream"));
77   - });
  77 + jsonObject.put("mediaServerId", mediaServerItem.getId());
  78 + subscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_play,jsonObject,
  79 + (IMediaServerItem mediaServerItemInuse, JSONObject response)->{
  80 + updateMedia(mediaServerItem, response.getString("app"), response.getString("stream"));
  81 + }
  82 + );
78 83 }
79 84 }
80 85 }));
81 86  
82 87 }
83 88  
84   - public void addMedia(String app, String streamId) {
  89 + public void addMedia(IMediaServerItem mediaServerItem, String app, String streamId) {
85 90 //使用异步更新推流
86   - updateMedia(app, streamId);
  91 + updateMedia(mediaServerItem, app, streamId);
87 92 }
88 93  
89 94  
90   - public void updateMedia(String app, String streamId) {
  95 + public void updateMedia(IMediaServerItem mediaServerItem, String app, String streamId) {
91 96 //使用异步更新推流
92   - zlmresTfulUtils.getMediaList(app, streamId, "rtmp", json->{
  97 + zlmresTfulUtils.getMediaList(mediaServerItem, app, streamId, "rtmp", json->{
93 98  
94 99 if (json == null) return;
95 100 String dataStr = json.getString("data");
... ... @@ -99,7 +104,7 @@ public class ZLMMediaListManager {
99 104 List<StreamPushItem> streamPushItems = null;
100 105 if (code == 0 ) {
101 106 if (dataStr != null) {
102   - streamPushItems = streamPushService.handleJSON(dataStr);
  107 + streamPushItems = streamPushService.handleJSON(dataStr, mediaServerItem);
103 108 }
104 109 }else {
105 110 logger.warn("更新视频流失败,错误code: " + code);
... ... @@ -122,32 +127,32 @@ public class ZLMMediaListManager {
122 127 }
123 128 }
124 129  
125   - public void clearAllSessions() {
126   - logger.info("清空所有国标相关的session");
127   - JSONObject allSessionJSON = zlmresTfulUtils.getAllSession();
128   - ZLMServerConfig mediaInfo = redisCatchStorage.getMediaInfo();
129   - HashSet<String> allLocalPorts = new HashSet();
130   - if (allSessionJSON.getInteger("code") == 0) {
131   - JSONArray data = allSessionJSON.getJSONArray("data");
132   - if (data.size() > 0) {
133   - for (int i = 0; i < data.size(); i++) {
134   - JSONObject sessionJOSN = data.getJSONObject(i);
135   - Integer local_port = sessionJOSN.getInteger("local_port");
136   - if (!local_port.equals(Integer.valueOf(mediaInfo.getHttpPort())) &&
137   - !local_port.equals(Integer.valueOf(mediaInfo.getHttpSSLport())) &&
138   - !local_port.equals(Integer.valueOf(mediaInfo.getRtmpPort())) &&
139   - !local_port.equals(Integer.valueOf(mediaInfo.getRtspPort())) &&
140   - !local_port.equals(Integer.valueOf(mediaInfo.getRtspSSlport())) &&
141   - !local_port.equals(Integer.valueOf(mediaInfo.getHookOnFlowReport()))){
142   - allLocalPorts.add(sessionJOSN.getInteger("local_port") + "");
143   - }
144   - }
145   - }
146   - }
147   - if (allLocalPorts.size() > 0) {
148   - List<String> result = new ArrayList<>(allLocalPorts);
149   - String localPortSStr = String.join(",", result);
150   - zlmresTfulUtils.kickSessions(localPortSStr);
151   - }
152   - }
  130 +// public void clearAllSessions() {
  131 +// logger.info("清空所有国标相关的session");
  132 +// JSONObject allSessionJSON = zlmresTfulUtils.getAllSession();
  133 +// ZLMServerConfig mediaInfo = redisCatchStorage.getMediaInfo();
  134 +// HashSet<String> allLocalPorts = new HashSet();
  135 +// if (allSessionJSON.getInteger("code") == 0) {
  136 +// JSONArray data = allSessionJSON.getJSONArray("data");
  137 +// if (data.size() > 0) {
  138 +// for (int i = 0; i < data.size(); i++) {
  139 +// JSONObject sessionJOSN = data.getJSONObject(i);
  140 +// Integer local_port = sessionJOSN.getInteger("local_port");
  141 +// if (!local_port.equals(Integer.valueOf(mediaInfo.getHttpPort())) &&
  142 +// !local_port.equals(Integer.valueOf(mediaInfo.getHttpSSLport())) &&
  143 +// !local_port.equals(Integer.valueOf(mediaInfo.getRtmpPort())) &&
  144 +// !local_port.equals(Integer.valueOf(mediaInfo.getRtspPort())) &&
  145 +// !local_port.equals(Integer.valueOf(mediaInfo.getRtspSSlport())) &&
  146 +// !local_port.equals(Integer.valueOf(mediaInfo.getHookOnFlowReport()))){
  147 +// allLocalPorts.add(sessionJOSN.getInteger("local_port") + "");
  148 +// }
  149 +// }
  150 +// }
  151 +// }
  152 +// if (allLocalPorts.size() > 0) {
  153 +// List<String> result = new ArrayList<>(allLocalPorts);
  154 +// String localPortSStr = String.join(",", result);
  155 +// zlmresTfulUtils.kickSessions(localPortSStr);
  156 +// }
  157 +// }
153 158 }
... ...
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRESTfulUtils.java
... ... @@ -3,6 +3,8 @@ package com.genersoft.iot.vmp.media.zlm;
3 3 import com.alibaba.fastjson.JSON;
4 4 import com.alibaba.fastjson.JSONObject;
5 5 import com.genersoft.iot.vmp.conf.MediaConfig;
  6 +import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
  7 +import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
6 8 import okhttp3.*;
7 9 import org.jetbrains.annotations.NotNull;
8 10 import org.slf4j.Logger;
... ... @@ -21,23 +23,18 @@ public class ZLMRESTfulUtils {
21 23  
22 24 private final static Logger logger = LoggerFactory.getLogger(ZLMRESTfulUtils.class);
23 25  
24   - @Autowired
25   - private MediaConfig mediaConfig;
26   -
27   -
28   -
29 26 public interface RequestCallback{
30 27 void run(JSONObject response);
31 28 }
32 29  
33   - public JSONObject sendPost(String api, Map<String, Object> param, RequestCallback callback) {
  30 + public JSONObject sendPost(IMediaServerItem mediaServerItem, String api, Map<String, Object> param, RequestCallback callback) {
34 31 OkHttpClient client = new OkHttpClient();
35   - String url = String.format("http://%s:%s/index/api/%s", mediaConfig.getIp(), mediaConfig.getHttpPort(), api);
  32 + String url = String.format("http://%s:%s/index/api/%s", mediaServerItem.getIp(), mediaServerItem.getHttpPort(), api);
36 33 JSONObject responseJSON = null;
37 34 logger.debug(url);
38 35  
39 36 FormBody.Builder builder = new FormBody.Builder();
40   - builder.add("secret",mediaConfig.getSecret());
  37 + builder.add("secret",mediaServerItem.getSecret());
41 38 if (param != null && param.keySet().size() > 0) {
42 39 for (String key : param.keySet()){
43 40 if (param.get(key) != null) {
... ... @@ -96,14 +93,14 @@ public class ZLMRESTfulUtils {
96 93 }
97 94  
98 95  
99   - public void sendPostForImg(String api, Map<String, Object> param, String targetPath, String fileName) {
  96 + public void sendPostForImg(IMediaServerItem mediaServerItem, String api, Map<String, Object> param, String targetPath, String fileName) {
100 97 OkHttpClient client = new OkHttpClient();
101   - String url = String.format("http://%s:%s/index/api/%s", mediaConfig.getIp(), mediaConfig.getHttpPort(), api);
  98 + String url = String.format("http://%s:%s/index/api/%s", mediaServerItem.getIp(), mediaServerItem.getHttpPort(), api);
102 99 JSONObject responseJSON = null;
103 100 logger.debug(url);
104 101  
105 102 FormBody.Builder builder = new FormBody.Builder();
106   - builder.add("secret",mediaConfig.getSecret());
  103 + builder.add("secret",mediaServerItem.getSecret());
107 104 if (param != null && param.keySet().size() > 0) {
108 105 for (String key : param.keySet()){
109 106 if (param.get(key) != null) {
... ... @@ -142,39 +139,39 @@ public class ZLMRESTfulUtils {
142 139 }
143 140  
144 141  
145   - public JSONObject getMediaList(String app, String stream, String schema, RequestCallback callback){
  142 + public JSONObject getMediaList(IMediaServerItem mediaServerItem,String app, String stream, String schema, RequestCallback callback){
146 143 Map<String, Object> param = new HashMap<>();
147 144 if (app != null) param.put("app",app);
148 145 if (stream != null) param.put("stream",stream);
149 146 if (schema != null) param.put("schema",schema);
150 147 param.put("vhost","__defaultVhost__");
151   - return sendPost("getMediaList",param, callback);
  148 + return sendPost(mediaServerItem, "getMediaList",param, callback);
152 149 }
153 150  
154   - public JSONObject getMediaList(String app, String stream){
155   - return getMediaList(app, stream,null, null);
  151 + public JSONObject getMediaList(IMediaServerItem mediaServerItem,String app, String stream){
  152 + return getMediaList(mediaServerItem, app, stream,null, null);
156 153 }
157 154  
158   - public JSONObject getMediaList(RequestCallback callback){
159   - return sendPost("getMediaList",null, callback);
  155 + public JSONObject getMediaList(IMediaServerItem mediaServerItem,RequestCallback callback){
  156 + return sendPost(mediaServerItem, "getMediaList",null, callback);
160 157 }
161 158  
162   - public JSONObject getMediaInfo(String app, String schema, String stream){
  159 + public JSONObject getMediaInfo(IMediaServerItem mediaServerItem,String app, String schema, String stream){
163 160 Map<String, Object> param = new HashMap<>();
164 161 param.put("app",app);
165 162 param.put("schema",schema);
166 163 param.put("stream",stream);
167 164 param.put("vhost","__defaultVhost__");
168   - return sendPost("getMediaInfo",param, null);
  165 + return sendPost(mediaServerItem, "getMediaInfo",param, null);
169 166 }
170 167  
171   - public JSONObject getRtpInfo(String stream_id){
  168 + public JSONObject getRtpInfo(IMediaServerItem mediaServerItem,String stream_id){
172 169 Map<String, Object> param = new HashMap<>();
173 170 param.put("stream_id",stream_id);
174   - return sendPost("getRtpInfo",param, null);
  171 + return sendPost(mediaServerItem, "getRtpInfo",param, null);
175 172 }
176 173  
177   - public JSONObject addFFmpegSource(String src_url, String dst_url, String timeout_ms,
  174 + public JSONObject addFFmpegSource(IMediaServerItem mediaServerItem,String src_url, String dst_url, String timeout_ms,
178 175 boolean enable_hls, boolean enable_mp4, String ffmpeg_cmd_key){
179 176 logger.info(src_url);
180 177 logger.info(dst_url);
... ... @@ -185,44 +182,44 @@ public class ZLMRESTfulUtils {
185 182 param.put("enable_hls", enable_hls);
186 183 param.put("enable_mp4", enable_mp4);
187 184 param.put("ffmpeg_cmd_key", ffmpeg_cmd_key);
188   - return sendPost("addFFmpegSource",param, null);
  185 + return sendPost(mediaServerItem, "addFFmpegSource",param, null);
189 186 }
190 187  
191   - public JSONObject delFFmpegSource(String key){
  188 + public JSONObject delFFmpegSource(IMediaServerItem mediaServerItem,String key){
192 189 Map<String, Object> param = new HashMap<>();
193 190 param.put("key", key);
194   - return sendPost("delFFmpegSource",param, null);
  191 + return sendPost(mediaServerItem, "delFFmpegSource",param, null);
195 192 }
196 193  
197   - public JSONObject getMediaServerConfig(){
198   - return sendPost("getServerConfig",null, null);
  194 + public JSONObject getMediaServerConfig(IMediaServerItem mediaServerItem){
  195 + return sendPost(mediaServerItem, "getServerConfig",null, null);
199 196 }
200 197  
201   - public JSONObject setServerConfig(Map<String, Object> param){
202   - return sendPost("setServerConfig",param, null);
  198 + public JSONObject setServerConfig(IMediaServerItem mediaServerItem, Map<String, Object> param){
  199 + return sendPost(mediaServerItem,"setServerConfig",param, null);
203 200 }
204 201  
205   - public JSONObject openRtpServer(Map<String, Object> param){
206   - return sendPost("openRtpServer",param, null);
  202 + public JSONObject openRtpServer(IMediaServerItem mediaServerItem,Map<String, Object> param){
  203 + return sendPost(mediaServerItem, "openRtpServer",param, null);
207 204 }
208 205  
209   - public JSONObject closeRtpServer(Map<String, Object> param) {
210   - return sendPost("closeRtpServer",param, null);
  206 + public JSONObject closeRtpServer(IMediaServerItem mediaServerItem,Map<String, Object> param) {
  207 + return sendPost(mediaServerItem, "closeRtpServer",param, null);
211 208 }
212 209  
213   - public JSONObject listRtpServer() {
214   - return sendPost("listRtpServer",null, null);
  210 + public JSONObject listRtpServer(IMediaServerItem mediaServerItem) {
  211 + return sendPost(mediaServerItem, "listRtpServer",null, null);
215 212 }
216 213  
217   - public JSONObject startSendRtp(Map<String, Object> param) {
218   - return sendPost("startSendRtp",param, null);
  214 + public JSONObject startSendRtp(IMediaServerItem mediaServerItem,Map<String, Object> param) {
  215 + return sendPost(mediaServerItem, "startSendRtp",param, null);
219 216 }
220 217  
221   - public JSONObject stopSendRtp(Map<String, Object> param) {
222   - return sendPost("stopSendRtp",param, null);
  218 + public JSONObject stopSendRtp(IMediaServerItem mediaServerItem,Map<String, Object> param) {
  219 + return sendPost(mediaServerItem, "stopSendRtp",param, null);
223 220 }
224 221  
225   - public JSONObject addStreamProxy(String app, String stream, String url, boolean enable_hls, boolean enable_mp4, String rtp_type) {
  222 + public JSONObject addStreamProxy(IMediaServerItem mediaServerItem,String app, String stream, String url, boolean enable_hls, boolean enable_mp4, String rtp_type) {
226 223 Map<String, Object> param = new HashMap<>();
227 224 param.put("vhost", "__defaultVhost__");
228 225 param.put("app", app);
... ... @@ -231,33 +228,33 @@ public class ZLMRESTfulUtils {
231 228 param.put("enable_hls", enable_hls?1:0);
232 229 param.put("enable_mp4", enable_mp4?1:0);
233 230 param.put("rtp_type", rtp_type);
234   - return sendPost("addStreamProxy",param, null);
  231 + return sendPost(mediaServerItem, "addStreamProxy",param, null);
235 232 }
236 233  
237   - public JSONObject closeStreams(String app, String stream) {
  234 + public JSONObject closeStreams(IMediaServerItem mediaServerItem,String app, String stream) {
238 235 Map<String, Object> param = new HashMap<>();
239 236 param.put("vhost", "__defaultVhost__");
240 237 param.put("app", app);
241 238 param.put("stream", stream);
242 239 param.put("force", 1);
243   - return sendPost("close_streams",param, null);
  240 + return sendPost(mediaServerItem, "close_streams",param, null);
244 241 }
245 242  
246   - public JSONObject getAllSession() {
247   - return sendPost("getAllSession",null, null);
  243 + public JSONObject getAllSession(IMediaServerItem mediaServerItem) {
  244 + return sendPost(mediaServerItem, "getAllSession",null, null);
248 245 }
249 246  
250   - public void kickSessions(String localPortSStr) {
  247 + public void kickSessions(IMediaServerItem mediaServerItem, String localPortSStr) {
251 248 Map<String, Object> param = new HashMap<>();
252 249 param.put("local_port", localPortSStr);
253   - sendPost("kick_sessions",param, null);
  250 + sendPost(mediaServerItem, "kick_sessions",param, null);
254 251 }
255 252  
256   - public void getSnap(String flvUrl, int timeout_sec, int expire_sec, String targetPath, String fileName) {
  253 + public void getSnap(IMediaServerItem mediaServerItem, String flvUrl, int timeout_sec, int expire_sec, String targetPath, String fileName) {
257 254 Map<String, Object> param = new HashMap<>();
258 255 param.put("url", flvUrl);
259 256 param.put("timeout_sec", timeout_sec);
260 257 param.put("expire_sec", expire_sec);
261   - sendPostForImg("getSnap",param, targetPath, fileName);
  258 + sendPostForImg(mediaServerItem, "getSnap",param, targetPath, fileName);
262 259 }
263 260 }
... ...
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRTPServerFactory.java
... ... @@ -5,6 +5,8 @@ import com.alibaba.fastjson.JSONObject;
5 5 import com.genersoft.iot.vmp.conf.MediaConfig;
6 6 import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
7 7 import com.genersoft.iot.vmp.gb28181.session.SsrcUtil;
  8 +import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
  9 +import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
8 10 import org.slf4j.Logger;
9 11 import org.slf4j.LoggerFactory;
10 12 import org.springframework.beans.factory.annotation.Autowired;
... ... @@ -30,10 +32,10 @@ public class ZLMRTPServerFactory {
30 32  
31 33 private Map<String, Integer> currentStreams = null;
32 34  
33   - public int createRTPServer(String streamId) {
  35 + public int createRTPServer(IMediaServerItem mediaServerItem, String streamId) {
34 36 if (currentStreams == null) {
35 37 currentStreams = new HashMap<>();
36   - JSONObject jsonObject = zlmresTfulUtils.listRtpServer();
  38 + JSONObject jsonObject = zlmresTfulUtils.listRtpServer(mediaServerItem);
37 39 if (jsonObject != null) {
38 40 JSONArray data = jsonObject.getJSONArray("data");
39 41 if (data != null) {
... ... @@ -48,7 +50,7 @@ public class ZLMRTPServerFactory {
48 50 if (currentStreams.get(streamId) != null) {
49 51 Map<String, Object> closeRtpServerParam = new HashMap<>();
50 52 closeRtpServerParam.put("stream_id", streamId);
51   - zlmresTfulUtils.closeRtpServer(closeRtpServerParam);
  53 + zlmresTfulUtils.closeRtpServer(mediaServerItem, closeRtpServerParam);
52 54 currentStreams.remove(streamId);
53 55 }
54 56  
... ... @@ -58,7 +60,7 @@ public class ZLMRTPServerFactory {
58 60 param.put("port", newPort);
59 61 param.put("enable_tcp", 1);
60 62 param.put("stream_id", streamId);
61   - JSONObject jsonObject = zlmresTfulUtils.openRtpServer(param);
  63 + JSONObject jsonObject = zlmresTfulUtils.openRtpServer(mediaServerItem, param);
62 64  
63 65 if (jsonObject != null) {
64 66 switch (jsonObject.getInteger("code")){
... ... @@ -68,11 +70,11 @@ public class ZLMRTPServerFactory {
68 70 case -300: // id已经存在, 可能已经在其他端口推流
69 71 Map<String, Object> closeRtpServerParam = new HashMap<>();
70 72 closeRtpServerParam.put("stream_id", streamId);
71   - zlmresTfulUtils.closeRtpServer(closeRtpServerParam);
  73 + zlmresTfulUtils.closeRtpServer(mediaServerItem, closeRtpServerParam);
72 74 result = newPort;
73 75 break;
74 76 case -400: // 端口占用
75   - result= createRTPServer(streamId);
  77 + result= createRTPServer(mediaServerItem, streamId);
76 78 break;
77 79 default:
78 80 logger.error("创建RTP Server 失败 {}: " + jsonObject.getString("msg"), newPort);
... ... @@ -85,20 +87,22 @@ public class ZLMRTPServerFactory {
85 87 return result;
86 88 }
87 89  
88   - public boolean closeRTPServer(String streamId) {
  90 + public boolean closeRTPServer(IMediaServerItem serverItem, String streamId) {
89 91 boolean result = false;
90   - Map<String, Object> param = new HashMap<>();
91   - param.put("stream_id", streamId);
92   - JSONObject jsonObject = zlmresTfulUtils.closeRtpServer(param);
93   - if (jsonObject != null ) {
94   - if (jsonObject.getInteger("code") == 0) {
95   - result = jsonObject.getInteger("hit") == 1;
  92 + if (serverItem !=null){
  93 + Map<String, Object> param = new HashMap<>();
  94 + param.put("stream_id", streamId);
  95 + JSONObject jsonObject = zlmresTfulUtils.closeRtpServer(serverItem, param);
  96 + if (jsonObject != null ) {
  97 + if (jsonObject.getInteger("code") == 0) {
  98 + result = jsonObject.getInteger("hit") == 1;
  99 + }else {
  100 + logger.error("关闭RTP Server 失败: " + jsonObject.getString("msg"));
  101 + }
96 102 }else {
97   - logger.error("关闭RTP Server 失败: " + jsonObject.getString("msg"));
  103 + // 检查ZLM状态
  104 + logger.error("关闭RTP Server 失败: 请检查ZLM服务");
98 105 }
99   - }else {
100   - // 检查ZLM状态
101   - logger.error("关闭RTP Server 失败: 请检查ZLM服务");
102 106 }
103 107 return result;
104 108 }
... ... @@ -131,11 +135,11 @@ public class ZLMRTPServerFactory {
131 135 * @param tcp 是否为tcp
132 136 * @return SendRtpItem
133 137 */
134   - public SendRtpItem createSendRtpItem(String ip, int port, String ssrc, String platformId, String deviceId, String channelId, boolean tcp){
  138 + public SendRtpItem createSendRtpItem(IMediaServerItem serverItem, String ip, int port, String ssrc, String platformId, String deviceId, String channelId, boolean tcp){
135 139 String playSsrc = SsrcUtil.getPlaySsrc();
136   - int localPort = createRTPServer(SsrcUtil.getPlaySsrc());
  140 + int localPort = createRTPServer(serverItem, SsrcUtil.getPlaySsrc());
137 141 if (localPort != -1) {
138   - closeRTPServer(playSsrc);
  142 + closeRTPServer(serverItem, playSsrc);
139 143 }else {
140 144 logger.error("没有可用的端口");
141 145 return null;
... ... @@ -150,6 +154,7 @@ public class ZLMRTPServerFactory {
150 154 sendRtpItem.setTcp(tcp);
151 155 sendRtpItem.setApp("rtp");
152 156 sendRtpItem.setLocalPort(localPort);
  157 + sendRtpItem.setMediaServerId(serverItem.getId());
153 158 return sendRtpItem;
154 159 }
155 160  
... ... @@ -163,11 +168,11 @@ public class ZLMRTPServerFactory {
163 168 * @param tcp 是否为tcp
164 169 * @return SendRtpItem
165 170 */
166   - public SendRtpItem createSendRtpItem(String ip, int port, String ssrc, String platformId, String app, String stream, String channelId, boolean tcp){
  171 + public SendRtpItem createSendRtpItem(IMediaServerItem serverItem, String ip, int port, String ssrc, String platformId, String app, String stream, String channelId, boolean tcp){
167 172 String playSsrc = SsrcUtil.getPlaySsrc();
168   - int localPort = createRTPServer(SsrcUtil.getPlaySsrc());
  173 + int localPort = createRTPServer(serverItem, SsrcUtil.getPlaySsrc());
169 174 if (localPort != -1) {
170   - closeRTPServer(playSsrc);
  175 + closeRTPServer(serverItem, playSsrc);
171 176 }else {
172 177 logger.error("没有可用的端口");
173 178 return null;
... ... @@ -182,21 +187,21 @@ public class ZLMRTPServerFactory {
182 187 sendRtpItem.setChannelId(channelId);
183 188 sendRtpItem.setTcp(tcp);
184 189 sendRtpItem.setLocalPort(localPort);
  190 + sendRtpItem.setMediaServerId(serverItem.getId());
185 191 return sendRtpItem;
186 192 }
187 193  
188 194 /**
189 195 * 调用zlm RESTful API —— startSendRtp
190 196 */
191   - public Boolean startSendRtpStream(Map<String, Object>param) {
  197 + public Boolean startSendRtpStream(IMediaServerItem mediaServerItem, Map<String, Object>param) {
192 198 Boolean result = false;
193   - JSONObject jsonObject = zlmresTfulUtils.startSendRtp(param);
194   - logger.info(jsonObject.toJSONString());
  199 + JSONObject jsonObject = zlmresTfulUtils.startSendRtp(mediaServerItem, param);
195 200 if (jsonObject == null) {
196 201 logger.error("RTP推流失败: 请检查ZLM服务");
197 202 } else if (jsonObject.getInteger("code") == 0) {
198 203 result= true;
199   - logger.info("RTP推流请求成功,本地推流端口:" + jsonObject.getString("local_port"));
  204 + logger.info("RTP推流[ {}/{} ]请求成功,本地推流端口:{}" ,param.get("app"), param.get("stream"), jsonObject.getString("local_port"));
200 205 } else {
201 206 logger.error("RTP推流失败: " + jsonObject.getString("msg"));
202 207 }
... ... @@ -206,16 +211,16 @@ public class ZLMRTPServerFactory {
206 211 /**
207 212 * 查询待转推的流是否就绪
208 213 */
209   - public Boolean isRtpReady(String streamId) {
210   - JSONObject mediaInfo = zlmresTfulUtils.getMediaInfo("rtp", "rtmp", streamId);
  214 + public Boolean isRtpReady(MediaServerItem mediaServerItem, String streamId) {
  215 + JSONObject mediaInfo = zlmresTfulUtils.getMediaInfo(mediaServerItem,"rtp", "rtmp", streamId);
211 216 return (mediaInfo.getInteger("code") == 0 && mediaInfo.getBoolean("online"));
212 217 }
213 218  
214 219 /**
215 220 * 查询待转推的流是否就绪
216 221 */
217   - public Boolean isStreamReady(String app, String streamId) {
218   - JSONObject mediaInfo = zlmresTfulUtils.getMediaInfo(app, "rtmp", streamId);
  222 + public Boolean isStreamReady(IMediaServerItem mediaServerItem, String app, String streamId) {
  223 + JSONObject mediaInfo = zlmresTfulUtils.getMediaInfo(mediaServerItem, app, "rtmp", streamId);
219 224 return (mediaInfo.getInteger("code") == 0 && mediaInfo.getBoolean("online"));
220 225 }
221 226  
... ... @@ -224,18 +229,17 @@ public class ZLMRTPServerFactory {
224 229 * @param streamId
225 230 * @return
226 231 */
227   - public int totalReaderCount(String app, String streamId) {
228   - JSONObject mediaInfo = zlmresTfulUtils.getMediaInfo(app, "rtmp", streamId);
  232 + public int totalReaderCount(IMediaServerItem mediaServerItem, String app, String streamId) {
  233 + JSONObject mediaInfo = zlmresTfulUtils.getMediaInfo(mediaServerItem, app, "rtmp", streamId);
229 234 return mediaInfo.getInteger("totalReaderCount");
230 235 }
231 236  
232 237 /**
233 238 * 调用zlm RESTful API —— stopSendRtp
234 239 */
235   - public Boolean stopSendRtpStream(Map<String, Object>param) {
  240 + public Boolean stopSendRtpStream(IMediaServerItem mediaServerItem,Map<String, Object>param) {
236 241 Boolean result = false;
237   - JSONObject jsonObject = zlmresTfulUtils.stopSendRtp(param);
238   - logger.info(jsonObject.toJSONString());
  242 + JSONObject jsonObject = zlmresTfulUtils.stopSendRtp(mediaServerItem, param);
239 243 if (jsonObject == null) {
240 244 logger.error("停止RTP推流失败: 请检查ZLM服务");
241 245 } else if (jsonObject.getInteger("code") == 0) {
... ...
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRunner.java
... ... @@ -4,7 +4,10 @@ import com.alibaba.fastjson.JSON;
4 4 import com.alibaba.fastjson.JSONArray;
5 5 import com.alibaba.fastjson.JSONObject;
6 6 import com.genersoft.iot.vmp.conf.MediaConfig;
  7 +import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
  8 +import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
7 9 import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem;
  10 +import com.genersoft.iot.vmp.service.IMediaServerService;
8 11 import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
9 12 import com.genersoft.iot.vmp.service.IStreamProxyService;
10 13 import org.slf4j.Logger;
... ... @@ -14,10 +17,10 @@ import org.springframework.beans.factory.annotation.Value;
14 17 import org.springframework.boot.CommandLineRunner;
15 18 import org.springframework.core.annotation.Order;
16 19 import org.springframework.stereotype.Component;
  20 +import org.springframework.util.StringUtils;
17 21  
18   -import java.util.HashMap;
19   -import java.util.List;
20   -import java.util.Map;
  22 +import javax.print.attribute.standard.Media;
  23 +import java.util.*;
21 24  
22 25 @Component
23 26 @Order(value=1)
... ... @@ -25,140 +28,131 @@ public class ZLMRunner implements CommandLineRunner {
25 28  
26 29 private final static Logger logger = LoggerFactory.getLogger(ZLMRunner.class);
27 30  
28   - @Autowired
29   - private IVideoManagerStorager storager;
30   -
31   - @Autowired
32   - private MediaConfig mediaConfig;
33   -
34   - @Value("${server.port}")
35   - private String serverPort;
36   -
37   - @Value("${server.ssl.enabled:false}")
38   - private boolean sslEnabled;
39   -
40   - private boolean startGetMedia = false;
  31 + private Map<String, Boolean> startGetMedia;
41 32  
42 33 @Autowired
43 34 private ZLMRESTfulUtils zlmresTfulUtils;
44 35  
45 36 @Autowired
46   - private ZLMMediaListManager zlmMediaListManager;
  37 + private ZLMHttpHookSubscribe hookSubscribe;
47 38  
48 39 @Autowired
49   - private ZLMHttpHookSubscribe hookSubscribe;
  40 + private IStreamProxyService streamProxyService;
50 41  
51 42 @Autowired
52   - private ZLMServerManger zlmServerManger;
  43 + private IMediaServerService mediaServerService;
53 44  
54 45 @Autowired
55   - private IStreamProxyService streamProxyService;
  46 + private MediaConfig mediaConfig;
56 47  
57 48 @Override
58 49 public void run(String... strings) throws Exception {
59   - // 订阅 zlm启动事件
60   - hookSubscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_server_started,null,(response)->{
61   - ZLMServerConfig ZLMServerConfig = JSONObject.toJavaObject(response, ZLMServerConfig.class);
62   - zLmRunning(ZLMServerConfig);
  50 + IMediaServerItem presetMediaServer = mediaServerService.getOneByHostAndPort(
  51 + mediaConfig.getIp(), mediaConfig.getHttpPort());
  52 + if (presetMediaServer != null) {
  53 + mediaConfig.setId(presetMediaServer.getId());
  54 + mediaServerService.update(mediaConfig);
  55 + }
  56 +
  57 + // 订阅 zlm启动事件, 新的zlm也会从这里进入系统
  58 + hookSubscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_server_started,null,
  59 + (IMediaServerItem mediaServerItem, JSONObject response)->{
  60 + ZLMServerConfig zlmServerConfig = JSONObject.toJavaObject(response, ZLMServerConfig.class);
  61 + if (zlmServerConfig !=null ) {
  62 + startGetMedia.remove(zlmServerConfig.getGeneralMediaServerId());
  63 + mediaServerService.handLeZLMServerConfig(zlmServerConfig);
  64 +// zLmRunning(zlmServerConfig);
  65 + }
63 66 });
64 67  
65 68 // 获取zlm信息
66   - logger.info("等待zlm接入...");
67   - startGetMedia = true;
68   - ZLMServerConfig ZLMServerConfig = getMediaServerConfig();
  69 + logger.info("等待默认zlm接入...");
69 70  
70   - if (ZLMServerConfig != null) {
71   - zLmRunning(ZLMServerConfig);
  71 + // 获取所有的zlm, 并开启主动连接
  72 + List<IMediaServerItem> all = mediaServerService.getAll();
  73 + if (presetMediaServer == null) {
  74 + all.add(mediaConfig.getMediaSerItem());
  75 + }
  76 + for (IMediaServerItem mediaServerItem : all) {
  77 + if (startGetMedia == null) startGetMedia = new HashMap<>();
  78 + startGetMedia.put(mediaServerItem.getId(), true);
  79 + new Thread(() -> {
  80 + ZLMServerConfig zlmServerConfig = getMediaServerConfig(mediaServerItem);
  81 + if (zlmServerConfig != null) {
  82 + startGetMedia.remove(mediaServerItem.getId());
  83 + mediaServerService.handLeZLMServerConfig(zlmServerConfig);
  84 + }
  85 + }).start();
72 86 }
  87 + Timer timer = new Timer();
  88 + // 1分钟后未连接到则不再去主动连接
  89 + timer.schedule(new TimerTask() {
  90 + @Override
  91 + public void run() {
  92 + if (startGetMedia != null) {
  93 + Set<String> allZlmId = startGetMedia.keySet();
  94 + for (String id : allZlmId) {
  95 + logger.error("[ {} ]]主动连接失败,不再主动连接", id);
  96 + startGetMedia.put(id, false);
  97 + }
  98 + }
  99 + }
  100 + }, 60 * 1000 * 2);
73 101 }
74 102  
75   - public ZLMServerConfig getMediaServerConfig() {
76   - if (!startGetMedia) return null;
77   - JSONObject responseJSON = zlmresTfulUtils.getMediaServerConfig();
  103 + public ZLMServerConfig getMediaServerConfig(IMediaServerItem mediaServerItem) {
  104 + if ( startGetMedia.get(mediaServerItem.getId()) == null || !startGetMedia.get(mediaServerItem.getId())) return null;
  105 + JSONObject responseJSON = zlmresTfulUtils.getMediaServerConfig(mediaServerItem);
78 106 ZLMServerConfig ZLMServerConfig = null;
79 107 if (responseJSON != null) {
80 108 JSONArray data = responseJSON.getJSONArray("data");
81 109 if (data != null && data.size() > 0) {
82 110 ZLMServerConfig = JSON.parseObject(JSON.toJSONString(data.get(0)), ZLMServerConfig.class);
83   -
  111 + ZLMServerConfig.setIp(mediaServerItem.getIp());
84 112 }
85 113 } else {
86   - logger.error("getMediaServerConfig失败, 1s后重试");
  114 + logger.error("[ {} ]-[ {}:{} ]主动连接失败失败, 2s后重试",
  115 + mediaServerItem.getId(), mediaServerItem.getIp(), mediaServerItem.getHttpPort());
87 116 try {
88   - Thread.sleep(1000);
  117 + Thread.sleep(2000);
89 118 } catch (InterruptedException e) {
90 119 e.printStackTrace();
91 120 }
92   - ZLMServerConfig = getMediaServerConfig();
  121 + ZLMServerConfig = getMediaServerConfig(mediaServerItem);
93 122 }
94 123 return ZLMServerConfig;
95   - }
96 124  
97   - private void saveZLMConfig() {
98   - logger.info("设置zlm...");
99   - String protocol = sslEnabled ? "https" : "http";
100   - String hookPrex = String.format("%s://%s:%s/index/hook", protocol, mediaConfig.getHookIp(), serverPort);
101   - String recordHookPrex = null;
102   - if (mediaConfig.getRecordAssistPort() != 0) {
103   - recordHookPrex = String.format("http://127.0.0.1:%s/api/record", mediaConfig.getRecordAssistPort());
104   - }
105   - Map<String, Object> param = new HashMap<>();
106   - param.put("api.secret",mediaConfig.getSecret()); // -profile:v Baseline
107   - 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");
108   - param.put("hook.enable","1");
109   - param.put("hook.on_flow_report","");
110   - param.put("hook.on_play",String.format("%s/on_play", hookPrex));
111   - param.put("hook.on_http_access","");
112   - param.put("hook.on_publish", String.format("%s/on_publish", hookPrex));
113   - param.put("hook.on_record_mp4",recordHookPrex != null? String.format("%s/on_record_mp4", recordHookPrex): "");
114   - param.put("hook.on_record_ts","");
115   - param.put("hook.on_rtsp_auth","");
116   - param.put("hook.on_rtsp_realm","");
117   - param.put("hook.on_server_started",String.format("%s/on_server_started", hookPrex));
118   - param.put("hook.on_shell_login",String.format("%s/on_shell_login", hookPrex));
119   - param.put("hook.on_stream_changed",String.format("%s/on_stream_changed", hookPrex));
120   - param.put("hook.on_stream_none_reader",String.format("%s/on_stream_none_reader", hookPrex));
121   - param.put("hook.on_stream_not_found",String.format("%s/on_stream_not_found", hookPrex));
122   - param.put("hook.timeoutSec","20");
123   - param.put("general.streamNoneReaderDelayMS",mediaConfig.getStreamNoneReaderDelayMS());
124   -
125   - JSONObject responseJSON = zlmresTfulUtils.setServerConfig(param);
126   -
127   - if (responseJSON != null && responseJSON.getInteger("code") == 0) {
128   - logger.info("设置zlm成功");
129   - }else {
130   - logger.info("设置zlm失败");
131   - }
132 125 }
133 126  
134 127 /**
135 128 * zlm 连接成功或者zlm重启后
136 129 */
137   - private void zLmRunning(ZLMServerConfig zlmServerConfig){
138   - logger.info( "[ id: " + zlmServerConfig.getGeneralMediaServerId() + "] zlm接入成功...");
139   - // 关闭循环获取zlm配置
140   - startGetMedia = false;
141   - if (mediaConfig.isAutoConfig()) saveZLMConfig();
142   - zlmServerManger.updateServerCatch(zlmServerConfig);
143   -
144   - // 清空所有session
145   -// zlmMediaListManager.clearAllSessions();
146   -
147   - // 更新流列表
148   - zlmMediaListManager.updateMediaList();
149   - // 恢复流代理
150   - List<StreamProxyItem> streamProxyListForEnable = storager.getStreamProxyListForEnable(true);
151   - for (StreamProxyItem streamProxyDto : streamProxyListForEnable) {
152   - logger.info("恢复流代理," + streamProxyDto.getApp() + "/" + streamProxyDto.getStream());
153   - JSONObject jsonObject = streamProxyService.addStreamProxyToZlm(streamProxyDto);
154   - if (jsonObject == null) {
155   - // 设置为未启用
156   - logger.info("恢复流代理失败,请检查流地址后重新启用" + streamProxyDto.getApp() + "/" + streamProxyDto.getStream());
157   - streamProxyService.stop(streamProxyDto.getApp(), streamProxyDto.getStream());
158   - }else if (jsonObject.getInteger("code") != 0){ // TODO 将错误信息存入数据库, 前端展示
159   - logger.info("恢复流代理失败:" + streamProxyDto.getApp() + "/" + streamProxyDto.getStream() + "[ " + JSONObject.toJSONString(jsonObject) + " ]");
160   - streamProxyService.stop(streamProxyDto.getApp(), streamProxyDto.getStream());
161   - }
162   - }
163   - }
  130 +// private void zLmRunning(ZLMServerConfig zlmServerConfig){
  131 +// logger.info( "[ id: " + zlmServerConfig.getGeneralMediaServerId() + "] zlm接入成功...");
  132 +// // 关闭循环获取zlm配置
  133 +// startGetMedia = false;
  134 +// MediaServerItem mediaServerItem = new MediaServerItem(zlmServerConfig, sipIp);
  135 +// storager.updateMediaServer(mediaServerItem);
  136 +//
  137 +// if (mediaServerItem.isAutoConfig()) setZLMConfig(mediaServerItem);
  138 +// zlmServerManger.updateServerCatchFromHook(zlmServerConfig);
  139 +//
  140 +// // 清空所有session
  141 +//// zlmMediaListManager.clearAllSessions();
  142 +//
  143 +// // 更新流列表
  144 +// zlmMediaListManager.updateMediaList(mediaServerItem);
  145 +// // 恢复流代理, 只查找这个这个流媒体
  146 +// List<StreamProxyItem> streamProxyListForEnable = storager.getStreamProxyListForEnableInMediaServer(
  147 +// mediaServerItem.getId(), true);
  148 +// for (StreamProxyItem streamProxyDto : streamProxyListForEnable) {
  149 +// logger.info("恢复流代理," + streamProxyDto.getApp() + "/" + streamProxyDto.getStream());
  150 +// JSONObject jsonObject = streamProxyService.addStreamProxyToZlm(streamProxyDto);
  151 +// if (jsonObject == null) {
  152 +// // 设置为未启用
  153 +// logger.info("恢复流代理失败,请检查流地址后重新启用" + streamProxyDto.getApp() + "/" + streamProxyDto.getStream());
  154 +// streamProxyService.stop(streamProxyDto.getApp(), streamProxyDto.getStream());
  155 +// }
  156 +// }
  157 +// }
164 158 }
... ...
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMServerConfig.java
... ... @@ -34,12 +34,15 @@ public class ZLMServerConfig {
34 34 @JSONField(name = "general.streamNoneReaderDelayMS")
35 35 private String generalStreamNoneReaderDelayMS;
36 36  
  37 + @JSONField(name = "ip")
37 38 private String ip;
38 39  
39 40 private String sdpIp;
40 41  
41 42 private String streamIp;
42 43  
  44 + private String hookIp;
  45 +
43 46 private String updateTime;
44 47  
45 48 private String createTime;
... ... @@ -66,7 +69,7 @@ public class ZLMServerConfig {
66 69 private String hookEnable;
67 70  
68 71 @JSONField(name = "hook.on_flow_report")
69   - private Integer hookOnFlowReport;
  72 + private String hookOnFlowReport;
70 73  
71 74 @JSONField(name = "hook.on_http_access")
72 75 private String hookOnHttpAccess;
... ... @@ -117,7 +120,7 @@ public class ZLMServerConfig {
117 120 private String httpNotFound;
118 121  
119 122 @JSONField(name = "http.port")
120   - private Integer httpPort;
  123 + private int httpPort;
121 124  
122 125 @JSONField(name = "http.rootPath")
123 126 private String httpRootPath;
... ... @@ -126,7 +129,7 @@ public class ZLMServerConfig {
126 129 private String httpSendBufSize;
127 130  
128 131 @JSONField(name = "http.sslport")
129   - private Integer httpSSLport;
  132 + private int httpSSLport;
130 133  
131 134 @JSONField(name = "multicast.addrMax")
132 135 private String multicastAddrMax;
... ... @@ -159,10 +162,10 @@ public class ZLMServerConfig {
159 162 private String rtmpModifyStamp;
160 163  
161 164 @JSONField(name = "rtmp.port")
162   - private Integer rtmpPort;
  165 + private int rtmpPort;
163 166  
164 167 @JSONField(name = "rtmp.sslport")
165   - private Integer rtmpSslPort;
  168 + private int rtmpSslPort;
166 169  
167 170 @JSONField(name = "rtp.audioMtuSize")
168 171 private String rtpAudioMtuSize;
... ... @@ -186,7 +189,7 @@ public class ZLMServerConfig {
186 189 private String rtpProxyDumpDir;
187 190  
188 191 @JSONField(name = "rtp_proxy.port")
189   - private Integer rtpProxyPort;
  192 + private int rtpProxyPort;
190 193  
191 194 @JSONField(name = "rtp_proxy.timeoutSec")
192 195 private String rtpProxyTimeoutSec;
... ... @@ -201,10 +204,10 @@ public class ZLMServerConfig {
201 204 private String rtspKeepAliveSecond;
202 205  
203 206 @JSONField(name = "rtsp.port")
204   - private Integer rtspPort;
  207 + private int rtspPort;
205 208  
206 209 @JSONField(name = "rtsp.sslport")
207   - private Integer rtspSSlport;
  210 + private int rtspSSlport;
208 211  
209 212 @JSONField(name = "shell.maxReqSize")
210 213 private String shellMaxReqSize;
... ... @@ -212,6 +215,15 @@ public class ZLMServerConfig {
212 215 @JSONField(name = "shell.shell")
213 216 private String shellPhell;
214 217  
  218 +
  219 + public String getHookIp() {
  220 + return hookIp;
  221 + }
  222 +
  223 + public void setHookIp(String hookIp) {
  224 + this.hookIp = hookIp;
  225 + }
  226 +
215 227 public String getApiDebug() {
216 228 return apiDebug;
217 229 }
... ... @@ -388,11 +400,11 @@ public class ZLMServerConfig {
388 400 this.hookEnable = hookEnable;
389 401 }
390 402  
391   - public Integer getHookOnFlowReport() {
  403 + public String getHookOnFlowReport() {
392 404 return hookOnFlowReport;
393 405 }
394 406  
395   - public void setHookOnFlowReport(Integer hookOnFlowReport) {
  407 + public void setHookOnFlowReport(String hookOnFlowReport) {
396 408 this.hookOnFlowReport = hookOnFlowReport;
397 409 }
398 410  
... ... @@ -524,11 +536,11 @@ public class ZLMServerConfig {
524 536 this.httpNotFound = httpNotFound;
525 537 }
526 538  
527   - public Integer getHttpPort() {
  539 + public int getHttpPort() {
528 540 return httpPort;
529 541 }
530 542  
531   - public void setHttpPort(Integer httpPort) {
  543 + public void setHttpPort(int httpPort) {
532 544 this.httpPort = httpPort;
533 545 }
534 546  
... ... @@ -548,11 +560,11 @@ public class ZLMServerConfig {
548 560 this.httpSendBufSize = httpSendBufSize;
549 561 }
550 562  
551   - public Integer getHttpSSLport() {
  563 + public int getHttpSSLport() {
552 564 return httpSSLport;
553 565 }
554 566  
555   - public void setHttpSSLport(Integer httpSSLport) {
  567 + public void setHttpSSLport(int httpSSLport) {
556 568 this.httpSSLport = httpSSLport;
557 569 }
558 570  
... ... @@ -636,19 +648,19 @@ public class ZLMServerConfig {
636 648 this.rtmpModifyStamp = rtmpModifyStamp;
637 649 }
638 650  
639   - public Integer getRtmpPort() {
  651 + public int getRtmpPort() {
640 652 return rtmpPort;
641 653 }
642 654  
643   - public void setRtmpPort(Integer rtmpPort) {
  655 + public void setRtmpPort(int rtmpPort) {
644 656 this.rtmpPort = rtmpPort;
645 657 }
646 658  
647   - public Integer getRtmpSslPort() {
  659 + public int getRtmpSslPort() {
648 660 return rtmpSslPort;
649 661 }
650 662  
651   - public void setRtmpSslPort(Integer rtmpSslPort) {
  663 + public void setRtmpSslPort(int rtmpSslPort) {
652 664 this.rtmpSslPort = rtmpSslPort;
653 665 }
654 666  
... ... @@ -708,11 +720,11 @@ public class ZLMServerConfig {
708 720 this.rtpProxyDumpDir = rtpProxyDumpDir;
709 721 }
710 722  
711   - public Integer getRtpProxyPort() {
  723 + public int getRtpProxyPort() {
712 724 return rtpProxyPort;
713 725 }
714 726  
715   - public void setRtpProxyPort(Integer rtpProxyPort) {
  727 + public void setRtpProxyPort(int rtpProxyPort) {
716 728 this.rtpProxyPort = rtpProxyPort;
717 729 }
718 730  
... ... @@ -748,19 +760,19 @@ public class ZLMServerConfig {
748 760 this.rtspKeepAliveSecond = rtspKeepAliveSecond;
749 761 }
750 762  
751   - public Integer getRtspPort() {
  763 + public int getRtspPort() {
752 764 return rtspPort;
753 765 }
754 766  
755   - public void setRtspPort(Integer rtspPort) {
  767 + public void setRtspPort(int rtspPort) {
756 768 this.rtspPort = rtspPort;
757 769 }
758 770  
759   - public Integer getRtspSSlport() {
  771 + public int getRtspSSlport() {
760 772 return rtspSSlport;
761 773 }
762 774  
763   - public void setRtspSSlport(Integer rtspSSlport) {
  775 + public void setRtspSSlport(int rtspSSlport) {
764 776 this.rtspSSlport = rtspSSlport;
765 777 }
766 778  
... ...
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMServerManger.java deleted 100644 → 0
1   -package com.genersoft.iot.vmp.media.zlm;
2   -
3   -import com.genersoft.iot.vmp.conf.MediaConfig;
4   -import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
5   -import org.springframework.beans.factory.annotation.Autowired;
6   -import org.springframework.stereotype.Component;
7   -import org.springframework.util.StringUtils;
8   -
9   -@Component
10   -public class ZLMServerManger {
11   -
12   - @Autowired
13   - private IRedisCatchStorage redisCatchStorage;
14   -
15   - @Autowired
16   - private MediaConfig mediaConfig;
17   -
18   - public void updateServerCatch(ZLMServerConfig zlmServerConfig) {
19   -
20   - zlmServerConfig.setIp(mediaConfig.getIp());
21   - zlmServerConfig.setStreamIp(mediaConfig.getStreamIp());
22   - zlmServerConfig.setSdpIp(mediaConfig.getSdpIp());
23   - zlmServerConfig.setHttpPort(mediaConfig.getHttpPort());
24   -
25   - if(!StringUtils.isEmpty(mediaConfig.getHttpSSlPort()))
26   - zlmServerConfig.setHttpSSLport(mediaConfig.getHttpSSlPort());
27   -
28   - if(!StringUtils.isEmpty(mediaConfig.getRtspPort()))
29   - zlmServerConfig.setRtspPort(mediaConfig.getRtspPort());
30   -
31   - if(!StringUtils.isEmpty(mediaConfig.getRtspSSLPort()))
32   - zlmServerConfig.setRtspSSlport(mediaConfig.getRtspSSLPort());
33   -
34   - if(!StringUtils.isEmpty(mediaConfig.getRtmpPort()))
35   - zlmServerConfig.setRtmpPort(mediaConfig.getRtmpPort());
36   -
37   - if(!StringUtils.isEmpty(mediaConfig.getRtmpSSlPort()))
38   - zlmServerConfig.setRtmpSslPort(mediaConfig.getRtmpSSlPort());
39   -
40   - if(!StringUtils.isEmpty(mediaConfig.getRtpProxyPort()))
41   - zlmServerConfig.setRtpProxyPort(mediaConfig.getRtpProxyPort());
42   -
43   - redisCatchStorage.updateMediaInfo(zlmServerConfig);
44   - }
45   -}
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/IMediaServerItem.java 0 → 100644
  1 +package com.genersoft.iot.vmp.media.zlm.dto;
  2 +
  3 +public interface IMediaServerItem {
  4 +
  5 + String getId();
  6 +
  7 + void setId(String id);
  8 +
  9 + String getIp();
  10 +
  11 + void setIp(String ip);
  12 +
  13 + String getHookIp();
  14 +
  15 + void setHookIp(String hookIp);
  16 +
  17 + String getSdpIp();
  18 +
  19 + void setSdpIp(String sdpIp);
  20 +
  21 + String getStreamIp();
  22 +
  23 + void setStreamIp(String streamIp);
  24 +
  25 + int getHttpPort();
  26 +
  27 + void setHttpPort(int httpPort);
  28 +
  29 + int getHttpSSlPort();
  30 +
  31 + void setHttpSSlPort(int httpSSlPort);
  32 +
  33 + int getRtmpPort();
  34 +
  35 + void setRtmpPort(int rtmpPort);
  36 +
  37 + int getRtmpSSlPort();
  38 +
  39 + void setRtmpSSlPort(int rtmpSSlPort);
  40 +
  41 + int getRtpProxyPort();
  42 +
  43 + void setRtpProxyPort(int rtpProxyPort);
  44 +
  45 + int getRtspPort();
  46 +
  47 + void setRtspPort(int rtspPort);
  48 +
  49 + int getRtspSSLPort();
  50 +
  51 + void setRtspSSLPort(int rtspSSLPort);
  52 +
  53 + boolean isAutoConfig();
  54 +
  55 + void setAutoConfig(boolean autoConfig);
  56 +
  57 + String getSecret();
  58 +
  59 + void setSecret(String secret);
  60 +
  61 + String getStreamNoneReaderDelayMS();
  62 +
  63 + void setStreamNoneReaderDelayMS(String streamNoneReaderDelayMS);
  64 +
  65 + boolean isRtpEnable();
  66 +
  67 + void setRtpEnable(boolean rtpEnable);
  68 +
  69 + String getRtpPortRange();
  70 +
  71 + void setRtpPortRange(String rtpPortRange);
  72 +
  73 + int getRecordAssistPort();
  74 +
  75 + void setRecordAssistPort(int recordAssistPort);
  76 +
  77 + boolean isDocker();
  78 +
  79 + void setDocker(boolean docker);
  80 +
  81 + String getUpdateTime();
  82 +
  83 + void setUpdateTime(String updateTime);
  84 +
  85 + String getCreateTime();
  86 +
  87 + void setCreateTime(String createTime);
  88 +
  89 + int getCount();
  90 +
  91 + void setCount(int count);
  92 +}
... ...
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/MediaItem.java
... ... @@ -78,6 +78,10 @@ public class MediaItem {
78 78 */
79 79 private String vhost;
80 80  
  81 + /**
  82 + * 是否是docker部署, docker部署不会自动更新zlm使用的端口,需要自己手动修改
  83 + */
  84 + private boolean docker;
81 85  
82 86 public static class MediaTrack {
83 87 /**
... ... @@ -364,4 +368,12 @@ public class MediaItem {
364 368 public OriginSock getOriginSock() {
365 369 return originSock;
366 370 }
  371 +
  372 + public boolean isDocker() {
  373 + return docker;
  374 + }
  375 +
  376 + public void setDocker(boolean docker) {
  377 + this.docker = docker;
  378 + }
367 379 }
... ...
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/MediaServerItem.java 0 → 100644
  1 +package com.genersoft.iot.vmp.media.zlm.dto;
  2 +
  3 +
  4 +import com.genersoft.iot.vmp.media.zlm.ZLMServerConfig;
  5 +import org.springframework.util.StringUtils;
  6 +
  7 +public class MediaServerItem implements IMediaServerItem{
  8 +
  9 + private String id;
  10 +
  11 + private String ip;
  12 +
  13 + private String hookIp;
  14 +
  15 + private String sdpIp;
  16 +
  17 + private String streamIp;
  18 +
  19 + private int httpPort;
  20 +
  21 + private int httpSSlPort;
  22 +
  23 + private int rtmpPort;
  24 +
  25 + private int rtmpSSlPort;
  26 +
  27 + private int rtpProxyPort;
  28 +
  29 + private int rtspPort;
  30 +
  31 + private int rtspSSLPort;
  32 +
  33 + private boolean autoConfig;
  34 +
  35 + private String secret;
  36 +
  37 + private String streamNoneReaderDelayMS;
  38 +
  39 + private boolean rtpEnable;
  40 +
  41 + private String rtpPortRange;
  42 +
  43 + private int recordAssistPort;
  44 +
  45 + private String createTime;
  46 +
  47 + private String updateTime;
  48 +
  49 + private boolean docker;
  50 +
  51 + private int count;
  52 +
  53 + public MediaServerItem() {
  54 + }
  55 +
  56 + public MediaServerItem(ZLMServerConfig zlmServerConfig, String sipIp) {
  57 + id = zlmServerConfig.getGeneralMediaServerId();
  58 + ip = zlmServerConfig.getIp();
  59 + hookIp = StringUtils.isEmpty(zlmServerConfig.getHookIp())? sipIp: zlmServerConfig.getHookIp();
  60 + sdpIp = StringUtils.isEmpty(zlmServerConfig.getSdpIp())? zlmServerConfig.getIp(): zlmServerConfig.getSdpIp();
  61 + streamIp = StringUtils.isEmpty(zlmServerConfig.getStreamIp())? zlmServerConfig.getIp(): zlmServerConfig.getStreamIp();
  62 + httpPort = zlmServerConfig.getHttpPort();
  63 + httpSSlPort = zlmServerConfig.getHttpSSLport();
  64 + rtmpPort = zlmServerConfig.getRtmpPort();
  65 + rtmpSSlPort = zlmServerConfig.getRtmpSslPort();
  66 + rtpProxyPort = zlmServerConfig.getRtpProxyPort();
  67 + rtspPort = zlmServerConfig.getRtspPort();
  68 + rtspSSLPort = zlmServerConfig.getRtspSSlport();
  69 + autoConfig = true; // 默认值true;
  70 + secret = zlmServerConfig.getApiSecret();
  71 + streamNoneReaderDelayMS = zlmServerConfig.getGeneralStreamNoneReaderDelayMS();
  72 + rtpEnable = false; // 默认使用单端口;直到用户自己设置开启多端口
  73 + recordAssistPort = 0; // 默认关闭
  74 +
  75 + }
  76 +
  77 + public String getId() {
  78 + return id;
  79 + }
  80 +
  81 + public void setId(String id) {
  82 + this.id = id;
  83 + }
  84 +
  85 + public String getIp() {
  86 + return ip;
  87 + }
  88 +
  89 + public void setIp(String ip) {
  90 + this.ip = ip;
  91 + }
  92 +
  93 + public String getHookIp() {
  94 + return hookIp;
  95 + }
  96 +
  97 + public void setHookIp(String hookIp) {
  98 + this.hookIp = hookIp;
  99 + }
  100 +
  101 + public String getSdpIp() {
  102 + return sdpIp;
  103 + }
  104 +
  105 + public void setSdpIp(String sdpIp) {
  106 + this.sdpIp = sdpIp;
  107 + }
  108 +
  109 + public String getStreamIp() {
  110 + return streamIp;
  111 + }
  112 +
  113 + public void setStreamIp(String streamIp) {
  114 + this.streamIp = streamIp;
  115 + }
  116 +
  117 + public int getHttpPort() {
  118 + return httpPort;
  119 + }
  120 +
  121 + public void setHttpPort(int httpPort) {
  122 + this.httpPort = httpPort;
  123 + }
  124 +
  125 + public int getHttpSSlPort() {
  126 + return httpSSlPort;
  127 + }
  128 +
  129 + public void setHttpSSlPort(int httpSSlPort) {
  130 + this.httpSSlPort = httpSSlPort;
  131 + }
  132 +
  133 + public int getRtmpPort() {
  134 + return rtmpPort;
  135 + }
  136 +
  137 + public void setRtmpPort(int rtmpPort) {
  138 + this.rtmpPort = rtmpPort;
  139 + }
  140 +
  141 + public int getRtmpSSlPort() {
  142 + return rtmpSSlPort;
  143 + }
  144 +
  145 + public void setRtmpSSlPort(int rtmpSSlPort) {
  146 + this.rtmpSSlPort = rtmpSSlPort;
  147 + }
  148 +
  149 + public int getRtpProxyPort() {
  150 + return rtpProxyPort;
  151 + }
  152 +
  153 + public void setRtpProxyPort(int rtpProxyPort) {
  154 + this.rtpProxyPort = rtpProxyPort;
  155 + }
  156 +
  157 + public int getRtspPort() {
  158 + return rtspPort;
  159 + }
  160 +
  161 + public void setRtspPort(int rtspPort) {
  162 + this.rtspPort = rtspPort;
  163 + }
  164 +
  165 + public int getRtspSSLPort() {
  166 + return rtspSSLPort;
  167 + }
  168 +
  169 + public void setRtspSSLPort(int rtspSSLPort) {
  170 + this.rtspSSLPort = rtspSSLPort;
  171 + }
  172 +
  173 + public boolean isAutoConfig() {
  174 + return autoConfig;
  175 + }
  176 +
  177 + public void setAutoConfig(boolean autoConfig) {
  178 + this.autoConfig = autoConfig;
  179 + }
  180 +
  181 + public String getSecret() {
  182 + return secret;
  183 + }
  184 +
  185 + public void setSecret(String secret) {
  186 + this.secret = secret;
  187 + }
  188 +
  189 + public String getStreamNoneReaderDelayMS() {
  190 + return streamNoneReaderDelayMS;
  191 + }
  192 +
  193 + public void setStreamNoneReaderDelayMS(String streamNoneReaderDelayMS) {
  194 + this.streamNoneReaderDelayMS = streamNoneReaderDelayMS;
  195 + }
  196 +
  197 + public boolean isRtpEnable() {
  198 + return rtpEnable;
  199 + }
  200 +
  201 + public void setRtpEnable(boolean rtpEnable) {
  202 + this.rtpEnable = rtpEnable;
  203 + }
  204 +
  205 + public String getRtpPortRange() {
  206 + return rtpPortRange;
  207 + }
  208 +
  209 + public void setRtpPortRange(String rtpPortRange) {
  210 + this.rtpPortRange = rtpPortRange;
  211 + }
  212 +
  213 + public int getRecordAssistPort() {
  214 + return recordAssistPort;
  215 + }
  216 +
  217 + public void setRecordAssistPort(int recordAssistPort) {
  218 + this.recordAssistPort = recordAssistPort;
  219 + }
  220 +
  221 + @Override
  222 + public boolean isDocker() {
  223 + return docker;
  224 + }
  225 +
  226 + @Override
  227 + public void setDocker(boolean docker) {
  228 + this.docker = docker;
  229 + }
  230 +
  231 + public String getCreateTime() {
  232 + return createTime;
  233 + }
  234 +
  235 + public void setCreateTime(String createTime) {
  236 + this.createTime = createTime;
  237 + }
  238 +
  239 + public String getUpdateTime() {
  240 + return updateTime;
  241 + }
  242 +
  243 + public void setUpdateTime(String updateTime) {
  244 + this.updateTime = updateTime;
  245 + }
  246 +
  247 + public int getCount() {
  248 + return count;
  249 + }
  250 +
  251 + public void setCount(int count) {
  252 + this.count = count;
  253 + }
  254 +}
... ...
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/StreamProxyItem.java
... ... @@ -7,6 +7,7 @@ public class StreamProxyItem extends GbStream {
7 7 private String type;
8 8 private String app;
9 9 private String stream;
  10 + private String mediaServerId;
10 11 private String url;
11 12 private String src_url;
12 13 private String dst_url;
... ... @@ -17,6 +18,7 @@ public class StreamProxyItem extends GbStream {
17 18 private boolean enable_hls;
18 19 private boolean enable_mp4;
19 20 private String platformGbId;
  21 + private String createTime;
20 22  
21 23 public String getType() {
22 24 return type;
... ... @@ -42,6 +44,16 @@ public class StreamProxyItem extends GbStream {
42 44 this.stream = stream;
43 45 }
44 46  
  47 + @Override
  48 + public String getMediaServerId() {
  49 + return mediaServerId;
  50 + }
  51 +
  52 + @Override
  53 + public void setMediaServerId(String mediaServerId) {
  54 + this.mediaServerId = mediaServerId;
  55 + }
  56 +
45 57 public String getUrl() {
46 58 return url;
47 59 }
... ... @@ -122,4 +134,12 @@ public class StreamProxyItem extends GbStream {
122 134 public void setPlatformGbId(String platformGbId) {
123 135 this.platformGbId = platformGbId;
124 136 }
  137 +
  138 + public String getCreateTime() {
  139 + return createTime;
  140 + }
  141 +
  142 + public void setCreateTime(String createTime) {
  143 + this.createTime = createTime;
  144 + }
125 145 }
... ...
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/StreamPushItem.java
... ... @@ -76,6 +76,11 @@ public class StreamPushItem extends GbStream implements Comparable&lt;StreamPushIte
76 76 */
77 77 private String vhost;
78 78  
  79 + /**
  80 + * 使用的流媒体ID
  81 + */
  82 + private String mediaServerId;
  83 +
79 84 public String getVhost() {
80 85 return vhost;
81 86 }
... ... @@ -202,5 +207,14 @@ public class StreamPushItem extends GbStream implements Comparable&lt;StreamPushIte
202 207 }
203 208  
204 209  
  210 + @Override
  211 + public String getMediaServerId() {
  212 + return mediaServerId;
  213 + }
  214 +
  215 + @Override
  216 + public void setMediaServerId(String mediaServerId) {
  217 + this.mediaServerId = mediaServerId;
  218 + }
205 219 }
206 220  
... ...
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/ZLMRunInfo.java 0 → 100644
  1 +package com.genersoft.iot.vmp.media.zlm.dto;
  2 +
  3 +/**
  4 + * 记录zlm运行中一些参数
  5 + */
  6 +public class ZLMRunInfo {
  7 +
  8 + /**
  9 + * zlm当前流数量
  10 + */
  11 + private int mediaCount;
  12 +
  13 + /**
  14 + * 在线状态
  15 + */
  16 + private boolean online;
  17 +
  18 + public int getMediaCount() {
  19 + return mediaCount;
  20 + }
  21 +
  22 + public void setMediaCount(int mediaCount) {
  23 + this.mediaCount = mediaCount;
  24 + }
  25 +
  26 + public boolean isOnline() {
  27 + return online;
  28 + }
  29 +
  30 + public void setOnline(boolean online) {
  31 + this.online = online;
  32 + }
  33 +}
... ...
src/main/java/com/genersoft/iot/vmp/service/IMediaServerService.java 0 → 100644
  1 +package com.genersoft.iot.vmp.service;
  2 +
  3 +import com.genersoft.iot.vmp.conf.MediaConfig;
  4 +import com.genersoft.iot.vmp.gb28181.bean.Device;
  5 +import com.genersoft.iot.vmp.media.zlm.ZLMServerConfig;
  6 +import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
  7 +import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
  8 +
  9 +import java.util.List;
  10 +
  11 +/**
  12 + * 媒体服务节点
  13 + */
  14 +public interface IMediaServerService {
  15 +
  16 + List<IMediaServerItem> getAll();
  17 +
  18 + IMediaServerItem getOne(String generalMediaServerId);
  19 +
  20 + IMediaServerItem getOneByHostAndPort(String host, int port);
  21 +
  22 + /**
  23 + * 新的节点加入
  24 + * @param zlmServerConfig
  25 + * @return
  26 + */
  27 + void handLeZLMServerConfig(ZLMServerConfig zlmServerConfig);
  28 +
  29 + void updateServerCatch(IMediaServerItem mediaServerItem, Integer count, Boolean b);
  30 +
  31 + IMediaServerItem getMediaServerForMinimumLoad();
  32 +
  33 + void setZLMConfig(IMediaServerItem mediaServerItem);
  34 +
  35 + void init();
  36 +
  37 + void closeRTPServer(Device device, String channelId);
  38 +
  39 + void update(MediaConfig mediaConfig);
  40 +
  41 + void addCount(String mediaServerId);
  42 +
  43 + void removeCount(String mediaServerId);
  44 +}
... ...
src/main/java/com/genersoft/iot/vmp/service/IMediaService.java
... ... @@ -2,6 +2,8 @@ package com.genersoft.iot.vmp.service;
2 2  
3 3 import com.alibaba.fastjson.JSONArray;
4 4 import com.genersoft.iot.vmp.common.StreamInfo;
  5 +import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
  6 +import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
5 7  
6 8 /**
7 9 * 媒体信息业务
... ... @@ -14,29 +16,30 @@ public interface IMediaService {
14 16 * @param stream
15 17 * @return
16 18 */
17   - StreamInfo getStreamInfoByAppAndStreamWithCheck(String app, String stream);
  19 + StreamInfo getStreamInfoByAppAndStreamWithCheck(String app, String stream, String mediaServerId,String addr);
  20 +
18 21  
19 22 /**
20   - * 根据应用名和流ID获取播放地址, 只是地址拼接
  23 + * 根据应用名和流ID获取播放地址, 通过zlm接口检查是否存在, 返回的ip使用远程访问ip,适用与zlm与wvp在一台主机的情况
21 24 * @param app
22 25 * @param stream
23 26 * @return
24 27 */
25   - StreamInfo getStreamInfoByAppAndStream(String app, String stream, JSONArray tracks);
  28 + StreamInfo getStreamInfoByAppAndStreamWithCheck(String app, String stream, String mediaServerId);
26 29  
27 30 /**
28   - * 根据应用名和流ID获取播放地址, 只是地址拼接,返回的ip使用远程访问ip,适用与zlm与wvp在一台主机的情况
  31 + * 根据应用名和流ID获取播放地址, 只是地址拼接
29 32 * @param app
30 33 * @param stream
31 34 * @return
32 35 */
33   - StreamInfo getStreamInfoByAppAndStream(String app, String stream, JSONArray tracks, String addr);
  36 + StreamInfo getStreamInfoByAppAndStream(IMediaServerItem mediaServerItem, String app, String stream, JSONArray tracks);
34 37  
35 38 /**
36   - * 根据应用名和流ID获取播放地址, 通过zlm接口检查是否存在, 返回的ip使用远程访问ip,适用与zlm与wvp在一台主机的情况
  39 + * 根据应用名和流ID获取播放地址, 只是地址拼接,返回的ip使用远程访问ip,适用与zlm与wvp在一台主机的情况
37 40 * @param app
38 41 * @param stream
39 42 * @return
40 43 */
41   - StreamInfo getStreamInfoByAppAndStreamWithCheck(String app, String stream, String addr);
  44 + StreamInfo getStreamInfoByAppAndStream(IMediaServerItem mediaInfo, String app, String stream, JSONArray tracks, String addr);
42 45 }
... ...
src/main/java/com/genersoft/iot/vmp/service/IPlayService.java
1 1 package com.genersoft.iot.vmp.service;
2 2  
3 3 import com.alibaba.fastjson.JSONObject;
  4 +import com.genersoft.iot.vmp.gb28181.bean.Device;
4 5 import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
5 6 import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe;
  7 +import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
  8 +import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
6 9 import com.genersoft.iot.vmp.vmanager.gb28181.play.bean.PlayResult;
7 10  
8 11 /**
... ... @@ -10,8 +13,10 @@ import com.genersoft.iot.vmp.vmanager.gb28181.play.bean.PlayResult;
10 13 */
11 14 public interface IPlayService {
12 15  
13   - void onPublishHandlerForPlayBack(JSONObject resonse, String deviceId, String channelId, String uuid);
14   - void onPublishHandlerForPlay(JSONObject resonse, String deviceId, String channelId, String uuid);
  16 + void onPublishHandlerForPlayBack(IMediaServerItem mediaServerItem,JSONObject resonse, String deviceId, String channelId, String uuid);
  17 + void onPublishHandlerForPlay(IMediaServerItem mediaServerItem, JSONObject resonse, String deviceId, String channelId, String uuid);
15 18  
16   - PlayResult play(String deviceId, String channelId, ZLMHttpHookSubscribe.Event event, SipSubscribe.Event errorEvent);
  19 + PlayResult play(IMediaServerItem mediaServerItem, String deviceId, String channelId, ZLMHttpHookSubscribe.Event event, SipSubscribe.Event errorEvent);
  20 +
  21 + IMediaServerItem getNewMediaServerItem(Device device);
17 22 }
... ...
src/main/java/com/genersoft/iot/vmp/service/IStreamProxyService.java
1 1 package com.genersoft.iot.vmp.service;
2 2  
3 3 import com.alibaba.fastjson.JSONObject;
  4 +import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
  5 +import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
4 6 import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem;
5 7 import com.github.pagehelper.PageInfo;
6 8  
... ... @@ -61,5 +63,5 @@ public interface IStreamProxyService {
61 63 * 获取ffmpeg.cmd模板
62 64 * @return
63 65 */
64   - JSONObject getFFmpegCMDs();
  66 + JSONObject getFFmpegCMDs(IMediaServerItem mediaServerItem);
65 67 }
... ...
src/main/java/com/genersoft/iot/vmp/service/IStreamPushService.java
1 1 package com.genersoft.iot.vmp.service;
2 2  
3 3 import com.genersoft.iot.vmp.gb28181.bean.GbStream;
  4 +import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
4 5 import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem;
5 6 import com.github.pagehelper.PageInfo;
6 7  
... ... @@ -8,7 +9,7 @@ import java.util.List;
8 9  
9 10 public interface IStreamPushService {
10 11  
11   - List<StreamPushItem> handleJSON(String json);
  12 + List<StreamPushItem> handleJSON(String json, IMediaServerItem mediaServerItem);
12 13  
13 14 /**
14 15 * 将应用名和流ID加入国标关联
... ...
src/main/java/com/genersoft/iot/vmp/service/impl/MediaServerServiceImpl.java 0 → 100644
  1 +package com.genersoft.iot.vmp.service.impl;
  2 +
  3 +import com.alibaba.fastjson.JSON;
  4 +import com.alibaba.fastjson.JSONArray;
  5 +import com.alibaba.fastjson.JSONObject;
  6 +import com.genersoft.iot.vmp.common.StreamInfo;
  7 +import com.genersoft.iot.vmp.conf.MediaConfig;
  8 +import com.genersoft.iot.vmp.conf.ProxyServletConfig;
  9 +import com.genersoft.iot.vmp.gb28181.bean.Device;
  10 +import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
  11 +import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
  12 +import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
  13 +import com.genersoft.iot.vmp.media.zlm.ZLMServerConfig;
  14 +import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
  15 +import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
  16 +import com.genersoft.iot.vmp.media.zlm.dto.ZLMRunInfo;
  17 +import com.genersoft.iot.vmp.service.IMediaServerService;
  18 +import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
  19 +import com.genersoft.iot.vmp.storager.dao.MediaServerMapper;
  20 +import org.mitre.dsmiley.httpproxy.ProxyServlet;
  21 +import org.slf4j.Logger;
  22 +import org.slf4j.LoggerFactory;
  23 +import org.springframework.beans.factory.annotation.Autowired;
  24 +import org.springframework.beans.factory.annotation.Value;
  25 +import org.springframework.stereotype.Service;
  26 +
  27 +import java.text.SimpleDateFormat;
  28 +import java.util.*;
  29 +
  30 +/**
  31 + * 媒体服务器节点管理
  32 + */
  33 +@Service
  34 +public class MediaServerServiceImpl implements IMediaServerService {
  35 +
  36 + private final static Logger logger = LoggerFactory.getLogger(MediaServerServiceImpl.class);
  37 +
  38 + private Map<String, IMediaServerItem> zlmServers = new HashMap<>(); // 所有数据库的zlm的缓存
  39 + private Map<String, Integer> zlmServerStatus = new LinkedHashMap<>(); // 所有上线的zlm的缓存以及负载
  40 +
  41 + @Value("${sip.ip}")
  42 + private String sipIp;
  43 +
  44 + @Value("${server.ssl.enabled:false}")
  45 + private boolean sslEnabled;
  46 +
  47 + @Value("${server.port}")
  48 + private String serverPort;
  49 +
  50 + @Autowired
  51 + private MediaConfig mediaConfig;
  52 +
  53 + @Autowired
  54 + private ZLMRESTfulUtils zlmresTfulUtils;
  55 +
  56 + @Autowired
  57 + private MediaServerMapper mediaServerMapper;
  58 +
  59 +
  60 + @Autowired
  61 + private IRedisCatchStorage redisCatchStorage;
  62 +
  63 + @Autowired
  64 + private VideoStreamSessionManager streamSession;
  65 +
  66 + @Autowired
  67 + private ZLMRTPServerFactory zlmrtpServerFactory;
  68 +
  69 + private SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
  70 +
  71 + /**
  72 + * 初始化
  73 + */
  74 + @Override
  75 + public void init() {
  76 + zlmServers.clear();
  77 + zlmServerStatus.clear();
  78 + List<MediaServerItem> mediaServerItemList = mediaServerMapper.queryAll();
  79 + for (IMediaServerItem mediaServerItem : mediaServerItemList) {
  80 + zlmServers.put(mediaServerItem.getId(), mediaServerItem);
  81 + }
  82 + }
  83 +
  84 + @Override
  85 + public void closeRTPServer(Device device, String channelId) {
  86 + StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(device.getDeviceId(), channelId);
  87 + IMediaServerItem mediaServerItem = null;
  88 + if (streamInfo != null) {
  89 + mediaServerItem = this.getOne (streamInfo.getMediaServerId());
  90 + }
  91 + String streamId = String.format("gb_play_%s_%s", device.getDeviceId(), channelId);
  92 + zlmrtpServerFactory.closeRTPServer(mediaServerItem, streamId);
  93 + streamSession.remove(device.getDeviceId(), channelId);
  94 + }
  95 +
  96 + @Override
  97 + public void update(MediaConfig mediaConfig) {
  98 +
  99 + }
  100 +
  101 + @Override
  102 + public List<IMediaServerItem> getAll() {
  103 + if (zlmServers.size() == 0) {
  104 + init();
  105 + }
  106 + List<IMediaServerItem> result = new ArrayList<>();
  107 + for (String id : zlmServers.keySet()) {
  108 + IMediaServerItem mediaServerItem = zlmServers.get(id);
  109 + mediaServerItem.setCount(zlmServerStatus.get(id) == null ? 0 : zlmServerStatus.get(id));
  110 + result.add(mediaServerItem);
  111 + }
  112 + return result;
  113 +
  114 +
  115 +// return mediaServerMapper.queryAll();
  116 + }
  117 +
  118 + /**
  119 + * 获取单个zlm服务器
  120 + * @param mediaServerId 服务id
  121 + * @return MediaServerItem
  122 + */
  123 + @Override
  124 + public IMediaServerItem getOne(String mediaServerId) {
  125 + if (mediaServerId ==null) return null;
  126 + IMediaServerItem mediaServerItem = zlmServers.get(mediaServerId);
  127 + if (mediaServerItem != null) {
  128 + mediaServerItem.setCount(zlmServerStatus.get(mediaServerId) == null ? 0 : zlmServerStatus.get(mediaServerId));
  129 + return mediaServerItem;
  130 + }else {
  131 + IMediaServerItem item = mediaServerMapper.queryOne(mediaServerId);
  132 + if (item != null) {
  133 + zlmServers.put(item.getId(), item);
  134 + }
  135 + return item;
  136 + }
  137 + }
  138 +
  139 + @Override
  140 + public IMediaServerItem getOneByHostAndPort(String host, int port) {
  141 + return mediaServerMapper.queryOneByHostAndPort(host, port);
  142 + }
  143 +
  144 + /**
  145 + * 处理zlm上线
  146 + * @param zlmServerConfig zlm上线携带的参数
  147 + */
  148 + @Override
  149 + public void handLeZLMServerConfig(ZLMServerConfig zlmServerConfig) {
  150 + logger.info("[ {} ]-[ {}:{} ]已连接",
  151 + zlmServerConfig.getGeneralMediaServerId(), zlmServerConfig.getIp(), zlmServerConfig.getHttpPort());
  152 +
  153 + IMediaServerItem serverItem = getOne(zlmServerConfig.getGeneralMediaServerId());
  154 + String now = this.format.format(new Date(System.currentTimeMillis()));
  155 + if (serverItem != null) {
  156 + serverItem.setSecret(zlmServerConfig.getApiSecret());
  157 + serverItem.setIp(zlmServerConfig.getIp());
  158 + // 如果是配置文件中的zlm。 也就是默认zlm。 一切以配置文件内容为准
  159 + // docker部署不会使用zlm配置的端口号;
  160 + // 直接编译部署的使用配置文件的端口号,如果zlm修改配改了配置,wvp自动修改
  161 +
  162 + if (serverItem.getId().equals(mediaConfig.getId())
  163 + || (serverItem.getIp().equals(mediaConfig.getIp()) && serverItem.getHttpPort() == mediaConfig.getHttpPort())) {
  164 + // 配置文件的zlm
  165 + mediaConfig.setId(zlmServerConfig.getGeneralMediaServerId());
  166 + mediaConfig.setUpdateTime(now);
  167 + if (mediaConfig.getHttpPort() == 0) mediaConfig.setHttpPort(zlmServerConfig.getHttpPort());
  168 + if (mediaConfig.getHttpSSlPort() == 0) mediaConfig.setHttpSSlPort(zlmServerConfig.getHttpSSLport());
  169 + if (mediaConfig.getRtmpPort() == 0) mediaConfig.setRtmpPort(zlmServerConfig.getRtmpPort());
  170 + if (mediaConfig.getRtmpSSlPort() == 0) mediaConfig.setRtmpSSlPort(zlmServerConfig.getRtmpSslPort());
  171 + if (mediaConfig.getRtspPort() == 0) mediaConfig.setRtspPort(zlmServerConfig.getRtspPort());
  172 + if (mediaConfig.getRtspSSLPort() == 0) mediaConfig.setRtspSSLPort(zlmServerConfig.getRtspSSlport());
  173 + if (mediaConfig.getRtpProxyPort() == 0) mediaConfig.setRtpProxyPort(zlmServerConfig.getRtpProxyPort());
  174 + mediaServerMapper.update(mediaConfig);
  175 + serverItem = mediaConfig.getMediaSerItem();
  176 + setZLMConfig(mediaConfig);
  177 + }else {
  178 + if (!serverItem.isDocker()) {
  179 + serverItem.setHttpPort(zlmServerConfig.getHttpPort());
  180 + serverItem.setHttpSSlPort(zlmServerConfig.getHttpSSLport());
  181 + serverItem.setRtmpPort(zlmServerConfig.getRtmpPort());
  182 + serverItem.setRtmpSSlPort(zlmServerConfig.getRtmpSslPort());
  183 + serverItem.setRtpProxyPort(zlmServerConfig.getRtpProxyPort());
  184 + serverItem.setRtspPort(zlmServerConfig.getRtspPort());
  185 +
  186 + }
  187 + serverItem.setUpdateTime(now);
  188 + mediaServerMapper.update(serverItem);
  189 + setZLMConfig(serverItem);
  190 + }
  191 + }else {
  192 + if (zlmServerConfig.getGeneralMediaServerId().equals(mediaConfig.getId())
  193 + || (zlmServerConfig.getIp().equals(mediaConfig.getIp()) && zlmServerConfig.getHttpPort() == mediaConfig.getHttpPort())) {
  194 + mediaConfig.setId(zlmServerConfig.getGeneralMediaServerId());
  195 + mediaConfig.setCreateTime(now);
  196 + mediaConfig.setUpdateTime(now);
  197 + serverItem = mediaConfig;
  198 + mediaServerMapper.add(mediaConfig);
  199 + }else {
  200 + // 一个新的zlm接入wvp
  201 + serverItem = new MediaServerItem(zlmServerConfig, sipIp);
  202 + serverItem.setCreateTime(now);
  203 + serverItem.setUpdateTime(now);
  204 + mediaServerMapper.add(serverItem);
  205 + }
  206 + }
  207 + // 更新缓存
  208 + if (zlmServerStatus.get(serverItem.getId()) == null) {
  209 + zlmServers.put(serverItem.getId(), serverItem);
  210 + zlmServerStatus.put(serverItem.getId(),0);
  211 + }
  212 + // 查询服务流数量
  213 + IMediaServerItem finalServerItem = serverItem;
  214 + zlmresTfulUtils.getMediaList(serverItem, null, null, "rtmp",(mediaList ->{
  215 + Integer code = mediaList.getInteger("code");
  216 + if (code == 0) {
  217 + JSONArray data = mediaList.getJSONArray("data");
  218 + if (data != null) {
  219 + zlmServerStatus.put(finalServerItem.getId(),data.size());
  220 + }else {
  221 + zlmServerStatus.put(finalServerItem.getId(),0);
  222 + }
  223 +
  224 + }
  225 + }));
  226 +
  227 + }
  228 +
  229 + /**
  230 + * 更新缓存
  231 + * @param mediaServerItem zlm服务
  232 + * @param count 在线数
  233 + * @param online 在线状态
  234 + */
  235 + @Override
  236 + public void updateServerCatch(IMediaServerItem mediaServerItem, Integer count, Boolean online) {
  237 + if (mediaServerItem != null) {
  238 + zlmServers.put(mediaServerItem.getId(), mediaServerItem);
  239 + Collection<Integer> values = zlmServerStatus.values();
  240 + if (online != null && count != null) {
  241 + zlmServerStatus.put(mediaServerItem.getId(), count);
  242 + }
  243 + }
  244 + }
  245 +
  246 + @Override
  247 + public void addCount(String mediaServerId) {
  248 + if (zlmServerStatus.get(mediaServerId) != null) {
  249 + zlmServerStatus.put(mediaServerId, zlmServerStatus.get(mediaServerId) + 1);
  250 + }
  251 + }
  252 +
  253 + @Override
  254 + public void removeCount(String mediaServerId) {
  255 + if (zlmServerStatus.get(mediaServerId) != null) {
  256 + zlmServerStatus.put(mediaServerId, zlmServerStatus.get(mediaServerId) - 1);
  257 + }
  258 + }
  259 +
  260 + /**
  261 + * 获取负载最低的节点
  262 + * @return MediaServerItem
  263 + */
  264 + @Override
  265 + public IMediaServerItem getMediaServerForMinimumLoad() {
  266 + int mediaCount = -1;
  267 + String key = null;
  268 + System.out.println(JSON.toJSONString(zlmServerStatus));
  269 + if (zlmServerStatus.size() == 1) {
  270 + Map.Entry entry = zlmServerStatus.entrySet().iterator().next();
  271 + key= (String) entry.getKey();
  272 + }else {
  273 + for (String id : zlmServerStatus.keySet()) {
  274 + if (key == null) {
  275 + key = id;
  276 + mediaCount = zlmServerStatus.get(id);
  277 + }
  278 + if (zlmServerStatus.get(id) == 0) {
  279 + key = id;
  280 + break;
  281 + }else if (mediaCount >= zlmServerStatus.get(id)){
  282 + mediaCount = zlmServerStatus.get(id);
  283 + key = id;
  284 + }
  285 + }
  286 + }
  287 +
  288 + if (key == null) {
  289 + logger.info("获取负载最低的节点时无在线节点");
  290 + return null;
  291 + }else{
  292 + return zlmServers.get(key);
  293 + }
  294 + }
  295 +
  296 + /**
  297 + * 对zlm服务器进行基础配置
  298 + * @param mediaServerItem 服务ID
  299 + */
  300 + @Override
  301 + public void setZLMConfig(IMediaServerItem mediaServerItem) {
  302 + logger.info("[ {} ]-[ {}:{} ]设置zlm",
  303 + mediaServerItem.getId(), mediaServerItem.getIp(), mediaServerItem.getHttpPort());
  304 + String protocol = sslEnabled ? "https" : "http";
  305 + String hookPrex = String.format("%s://%s:%s/index/hook", protocol, mediaServerItem.getHookIp(), serverPort);
  306 + String recordHookPrex = null;
  307 + if (mediaServerItem.getRecordAssistPort() != 0) {
  308 + recordHookPrex = String.format("http://127.0.0.1:%s/api/record", mediaServerItem.getRecordAssistPort());
  309 + }
  310 + Map<String, Object> param = new HashMap<>();
  311 + param.put("api.secret",mediaServerItem.getSecret()); // -profile:v Baseline
  312 + param.put("ffmpeg.cmd","%s -fflags nobuffer -i %s -c:a aac -strict -2 -ar 44100 -ab 48k -c:v libx264 -f flv %s");
  313 + param.put("hook.enable","1");
  314 + param.put("hook.on_flow_report","");
  315 + param.put("hook.on_play",String.format("%s/on_play", hookPrex));
  316 + param.put("hook.on_http_access","");
  317 + param.put("hook.on_publish", String.format("%s/on_publish", hookPrex));
  318 + param.put("hook.on_record_mp4",recordHookPrex != null? String.format("%s/on_record_mp4", recordHookPrex): "");
  319 + param.put("hook.on_record_ts","");
  320 + param.put("hook.on_rtsp_auth","");
  321 + param.put("hook.on_rtsp_realm","");
  322 + param.put("hook.on_server_started",String.format("%s/on_server_started", hookPrex));
  323 + param.put("hook.on_shell_login",String.format("%s/on_shell_login", hookPrex));
  324 + param.put("hook.on_stream_changed",String.format("%s/on_stream_changed", hookPrex));
  325 + param.put("hook.on_stream_none_reader",String.format("%s/on_stream_none_reader", hookPrex));
  326 + param.put("hook.on_stream_not_found",String.format("%s/on_stream_not_found", hookPrex));
  327 + param.put("hook.timeoutSec","20");
  328 + param.put("general.streamNoneReaderDelayMS",mediaServerItem.getStreamNoneReaderDelayMS());
  329 +
  330 + JSONObject responseJSON = zlmresTfulUtils.setServerConfig(mediaServerItem, param);
  331 +
  332 + if (responseJSON != null && responseJSON.getInteger("code") == 0) {
  333 + logger.info("[ {} ]-[ {}:{} ]设置zlm成功",
  334 + mediaServerItem.getId(), mediaServerItem.getIp(), mediaServerItem.getHttpPort());
  335 + }else {
  336 + logger.info("[ {} ]-[ {}:{} ]设置zlm失败" + responseJSON.getString("msg"),
  337 + mediaServerItem.getId(), mediaServerItem.getIp(), mediaServerItem.getHttpPort());
  338 + }
  339 + }
  340 +}
... ...
src/main/java/com/genersoft/iot/vmp/service/impl/MediaServiceImpl.java
... ... @@ -6,6 +6,9 @@ import com.alibaba.fastjson.JSONObject;
6 6 import com.genersoft.iot.vmp.common.StreamInfo;
7 7 import com.genersoft.iot.vmp.media.zlm.ZLMServerConfig;
8 8 import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
  9 +import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
  10 +import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
  11 +import com.genersoft.iot.vmp.service.IMediaServerService;
9 12 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
10 13 import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
11 14 import com.genersoft.iot.vmp.service.IMediaService;
... ... @@ -22,29 +25,52 @@ public class MediaServiceImpl implements IMediaService {
22 25 private IVideoManagerStorager storager;
23 26  
24 27 @Autowired
  28 + private IMediaServerService mediaServerService;
  29 +
  30 + @Autowired
25 31 private ZLMRESTfulUtils zlmresTfulUtils;
26 32  
27 33  
28 34  
29 35 @Override
30   - public StreamInfo getStreamInfoByAppAndStream(String app, String stream, JSONArray tracks) {
31   - return getStreamInfoByAppAndStream(app, stream, tracks, null);
  36 + public StreamInfo getStreamInfoByAppAndStream(IMediaServerItem mediaInfo, String app, String stream, JSONArray tracks) {
  37 + return getStreamInfoByAppAndStream(mediaInfo, app, stream, tracks, null);
  38 + }
  39 +
  40 + @Override
  41 + public StreamInfo getStreamInfoByAppAndStreamWithCheck(String app, String stream, String mediaServerId, String addr) {
  42 + StreamInfo streamInfo = null;
  43 + IMediaServerItem mediaInfo = mediaServerService.getOne(mediaServerId);
  44 + if (mediaInfo == null) {
  45 + return streamInfo;
  46 + }
  47 + JSONObject mediaList = zlmresTfulUtils.getMediaList(mediaInfo, app, stream);
  48 + if (mediaList != null) {
  49 + if (mediaList.getInteger("code") == 0) {
  50 + JSONArray data = mediaList.getJSONArray("data");
  51 + if (data == null) return null;
  52 + JSONObject mediaJSON = JSON.parseObject(JSON.toJSONString(data.get(0)), JSONObject.class);
  53 + JSONArray tracks = mediaJSON.getJSONArray("tracks");
  54 + streamInfo = getStreamInfoByAppAndStream(mediaInfo, app, stream, tracks);
  55 + }
  56 + }
  57 + return streamInfo;
32 58 }
33 59  
34 60 @Override
35   - public StreamInfo getStreamInfoByAppAndStreamWithCheck(String app, String stream) {
36   - return getStreamInfoByAppAndStreamWithCheck(app, stream, null);
  61 + public StreamInfo getStreamInfoByAppAndStreamWithCheck(String app, String stream, String mediaServerId) {
  62 + return getStreamInfoByAppAndStreamWithCheck(app, stream, mediaServerId, null);
37 63 }
38 64  
39 65 @Override
40   - public StreamInfo getStreamInfoByAppAndStream(String app, String stream, JSONArray tracks, String addr) {
41   - ZLMServerConfig mediaInfo = redisCatchStorage.getMediaInfo();
  66 + public StreamInfo getStreamInfoByAppAndStream(IMediaServerItem mediaInfo, String app, String stream, JSONArray tracks, String addr) {
42 67 StreamInfo streamInfoResult = new StreamInfo();
43 68 streamInfoResult.setStreamId(stream);
44 69 streamInfoResult.setApp(app);
45 70 if (addr == null) {
46 71 addr = mediaInfo.getStreamIp();
47 72 }
  73 + streamInfoResult.setMediaServerId(mediaInfo.getId());
48 74 streamInfoResult.setRtmp(String.format("rtmp://%s:%s/%s/%s", addr, mediaInfo.getRtmpPort(), app, stream));
49 75 streamInfoResult.setRtsp(String.format("rtsp://%s:%s/%s/%s", addr, mediaInfo.getRtspPort(), app, stream));
50 76 streamInfoResult.setFlv(String.format("http://%s:%s/%s/%s.flv", addr, mediaInfo.getHttpPort(), app, stream));
... ... @@ -60,19 +86,4 @@ public class MediaServiceImpl implements IMediaService {
60 86 return streamInfoResult;
61 87 }
62 88  
63   - @Override
64   - public StreamInfo getStreamInfoByAppAndStreamWithCheck(String app, String stream, String addr) {
65   - StreamInfo streamInfo = null;
66   - JSONObject mediaList = zlmresTfulUtils.getMediaList(app, stream);
67   - if (mediaList != null) {
68   - if (mediaList.getInteger("code") == 0) {
69   - JSONArray data = mediaList.getJSONArray("data");
70   - if (data == null) return null;
71   - JSONObject mediaJSON = JSON.parseObject(JSON.toJSONString(data.get(0)), JSONObject.class);
72   - JSONArray tracks = mediaJSON.getJSONArray("tracks");
73   - streamInfo = getStreamInfoByAppAndStream(app, stream, tracks, addr);
74   - }
75   - }
76   - return streamInfo;
77   - }
78 89 }
... ...
src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java
... ... @@ -14,6 +14,9 @@ import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
14 14 import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
15 15 import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe;
16 16 import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
  17 +import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
  18 +import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
  19 +import com.genersoft.iot.vmp.service.IMediaServerService;
17 20 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
18 21 import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
19 22 import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
... ... @@ -60,6 +63,9 @@ public class PlayServiceImpl implements IPlayService {
60 63 private IMediaService mediaService;
61 64  
62 65 @Autowired
  66 + private IMediaServerService mediaServerService;
  67 +
  68 + @Autowired
63 69 private VideoStreamSessionManager streamSession;
64 70  
65 71 @Autowired
... ... @@ -67,8 +73,18 @@ public class PlayServiceImpl implements IPlayService {
67 73  
68 74  
69 75 @Override
70   - public PlayResult play(String deviceId, String channelId, ZLMHttpHookSubscribe.Event hookEvent, SipSubscribe.Event errorEvent) {
  76 + public PlayResult play(IMediaServerItem mediaServerItem, String deviceId, String channelId, ZLMHttpHookSubscribe.Event hookEvent, SipSubscribe.Event errorEvent) {
71 77 PlayResult playResult = new PlayResult();
  78 + if (mediaServerItem == null) {
  79 + RequestMessage msg = new RequestMessage();
  80 + msg.setId(DeferredResultHolder.CALLBACK_CMD_PlAY + playResult.getUuid());
  81 + WVPResult wvpResult = new WVPResult();
  82 + wvpResult.setCode(-1);
  83 + wvpResult.setMsg("未找到可用的zlm");
  84 + msg.setData(wvpResult);
  85 + resultHolder.invokeResult(msg);
  86 + return playResult;
  87 + }
72 88 Device device = storager.queryVideoDevice(deviceId);
73 89 StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(deviceId, channelId);
74 90 playResult.setDevice(device);
... ... @@ -82,7 +98,7 @@ public class PlayServiceImpl implements IPlayService {
82 98 result.onTimeout(()->{
83 99 logger.warn(String.format("设备点播超时,deviceId:%s ,channelId:%s", deviceId, channelId));
84 100 // 释放rtpserver
85   - cmder.closeRTPServer(playResult.getDevice(), channelId);
  101 + mediaServerService.closeRTPServer(playResult.getDevice(), channelId);
86 102 RequestMessage msg = new RequestMessage();
87 103 msg.setId(DeferredResultHolder.CALLBACK_CMD_PlAY + playResult.getUuid());
88 104 WVPResult wvpResult = new WVPResult();
... ... @@ -115,9 +131,10 @@ public class PlayServiceImpl implements IPlayService {
115 131 WVPResult wvpResult = (WVPResult)responseEntity.getBody();
116 132 if (wvpResult.getCode() == 0) {
117 133 StreamInfo streamInfoForSuccess = (StreamInfo)wvpResult.getData();
  134 + IMediaServerItem mediaInfo = mediaServerService.getOne(streamInfoForSuccess.getMediaServerId());
118 135 String streamUrl = streamInfoForSuccess.getFmp4();
119 136 // 请求截图
120   - zlmresTfulUtils.getSnap(streamUrl, 15, 1, path, fileName);
  137 + zlmresTfulUtils.getSnap(mediaInfo, streamUrl, 15, 1, path, fileName);
121 138 }
122 139 }
123 140 } catch (FileNotFoundException e) {
... ... @@ -126,17 +143,17 @@ public class PlayServiceImpl implements IPlayService {
126 143 });
127 144 if (streamInfo == null) {
128 145 // 发送点播消息
129   - cmder.playStreamCmd(device, channelId, (JSONObject response) -> {
  146 + cmder.playStreamCmd(mediaServerItem, device, channelId, (IMediaServerItem mediaServerItemInUse, JSONObject response) -> {
130 147 logger.info("收到订阅消息: " + response.toJSONString());
131   - onPublishHandlerForPlay(response, deviceId, channelId, uuid.toString());
  148 + onPublishHandlerForPlay(mediaServerItemInUse, response, deviceId, channelId, uuid.toString());
132 149 if (hookEvent != null) {
133   - hookEvent.response(response);
  150 + hookEvent.response(mediaServerItem, response);
134 151 }
135   - }, event -> {
  152 + }, (event) -> {
136 153 RequestMessage msg = new RequestMessage();
137 154 msg.setId(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid);
138 155 Response response = event.getResponse();
139   - cmder.closeRTPServer(playResult.getDevice(), channelId);
  156 + mediaServerService.closeRTPServer(playResult.getDevice(), channelId);
140 157 WVPResult wvpResult = new WVPResult();
141 158 wvpResult.setCode(-1);
142 159 wvpResult.setMsg(String.format("点播失败, 错误码: %s, %s", response.getStatusCode(), response.getReasonPhrase()));
... ... @@ -158,7 +175,10 @@ public class PlayServiceImpl implements IPlayService {
158 175 resultHolder.invokeResult(msg);
159 176 return playResult;
160 177 }
161   - JSONObject rtpInfo = zlmresTfulUtils.getRtpInfo(streamId);
  178 + String mediaServerId = streamInfo.getMediaServerId();
  179 + IMediaServerItem mediaInfo = mediaServerService.getOne(mediaServerId);
  180 +
  181 + JSONObject rtpInfo = zlmresTfulUtils.getRtpInfo(mediaInfo, streamId);
162 182 if (rtpInfo != null && rtpInfo.getBoolean("exist")) {
163 183 RequestMessage msg = new RequestMessage();
164 184 msg.setId(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid);
... ... @@ -171,16 +191,16 @@ public class PlayServiceImpl implements IPlayService {
171 191  
172 192 resultHolder.invokeResult(msg);
173 193 if (hookEvent != null) {
174   - hookEvent.response(JSONObject.parseObject(JSON.toJSONString(streamInfo)));
  194 + hookEvent.response(mediaServerItem, JSONObject.parseObject(JSON.toJSONString(streamInfo)));
175 195 }
176 196 } else {
177 197 redisCatchStorage.stopPlay(streamInfo);
178 198 storager.stopPlay(streamInfo.getDeviceID(), streamInfo.getChannelId());
179   - cmder.playStreamCmd(device, channelId, (JSONObject response) -> {
  199 + cmder.playStreamCmd(mediaServerItem, device, channelId, (IMediaServerItem mediaServerItemInuse, JSONObject response) -> {
180 200 logger.info("收到订阅消息: " + response.toJSONString());
181   - onPublishHandlerForPlay(response, deviceId, channelId, uuid.toString());
182   - }, event -> {
183   - cmder.closeRTPServer(playResult.getDevice(), channelId);
  201 + onPublishHandlerForPlay(mediaServerItemInuse, response, deviceId, channelId, uuid.toString());
  202 + }, (event) -> {
  203 + mediaServerService.closeRTPServer(playResult.getDevice(), channelId);
184 204 RequestMessage msg = new RequestMessage();
185 205 msg.setId(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid);
186 206 Response response = event.getResponse();
... ... @@ -198,10 +218,10 @@ public class PlayServiceImpl implements IPlayService {
198 218 }
199 219  
200 220 @Override
201   - public void onPublishHandlerForPlay(JSONObject resonse, String deviceId, String channelId, String uuid) {
  221 + public void onPublishHandlerForPlay(IMediaServerItem mediaServerItem, JSONObject resonse, String deviceId, String channelId, String uuid) {
202 222 RequestMessage msg = new RequestMessage();
203 223 msg.setId(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid);
204   - StreamInfo streamInfo = onPublishHandler(resonse, deviceId, channelId, uuid);
  224 + StreamInfo streamInfo = onPublishHandler(mediaServerItem, resonse, deviceId, channelId, uuid);
205 225 if (streamInfo != null) {
206 226 DeviceChannel deviceChannel = storager.queryChannel(deviceId, channelId);
207 227 if (deviceChannel != null) {
... ... @@ -234,10 +254,26 @@ public class PlayServiceImpl implements IPlayService {
234 254 }
235 255  
236 256 @Override
237   - public void onPublishHandlerForPlayBack(JSONObject resonse, String deviceId, String channelId, String uuid) {
  257 + public IMediaServerItem getNewMediaServerItem(Device device) {
  258 + if (device == null) return null;
  259 + String mediaServerId = device.getMediaServerId();
  260 + IMediaServerItem mediaServerItem = null;
  261 + if (mediaServerId == null) {
  262 + mediaServerItem = mediaServerService.getMediaServerForMinimumLoad();
  263 + }else {
  264 + mediaServerItem = mediaServerService.getOne(mediaServerId);
  265 + }
  266 + if (mediaServerItem == null) {
  267 + logger.warn("点播时未找到可使用的ZLM...");
  268 + }
  269 + return mediaServerItem;
  270 + }
  271 +
  272 + @Override
  273 + public void onPublishHandlerForPlayBack(IMediaServerItem mediaServerItem, JSONObject resonse, String deviceId, String channelId, String uuid) {
238 274 RequestMessage msg = new RequestMessage();
239 275 msg.setId(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid);
240   - StreamInfo streamInfo = onPublishHandler(resonse, deviceId, channelId, uuid);
  276 + StreamInfo streamInfo = onPublishHandler(mediaServerItem, resonse, deviceId, channelId, uuid);
241 277 if (streamInfo != null) {
242 278 redisCatchStorage.startPlayback(streamInfo);
243 279 msg.setData(JSON.toJSONString(streamInfo));
... ... @@ -249,10 +285,10 @@ public class PlayServiceImpl implements IPlayService {
249 285 }
250 286 }
251 287  
252   - public StreamInfo onPublishHandler(JSONObject resonse, String deviceId, String channelId, String uuid) {
  288 + public StreamInfo onPublishHandler(IMediaServerItem mediaServerItem, JSONObject resonse, String deviceId, String channelId, String uuid) {
253 289 String streamId = resonse.getString("stream");
254 290 JSONArray tracks = resonse.getJSONArray("tracks");
255   - StreamInfo streamInfo = mediaService.getStreamInfoByAppAndStream("rtp", streamId, tracks);
  291 + StreamInfo streamInfo = mediaService.getStreamInfoByAppAndStream(mediaServerItem,"rtp", streamId, tracks);
256 292 streamInfo.setDeviceID(deviceId);
257 293 streamInfo.setChannelId(channelId);
258 294 return streamInfo;
... ...
src/main/java/com/genersoft/iot/vmp/service/impl/StreamProxyServiceImpl.java
... ... @@ -2,10 +2,12 @@ package com.genersoft.iot.vmp.service.impl;
2 2  
3 3 import com.alibaba.fastjson.JSONObject;
4 4 import com.genersoft.iot.vmp.gb28181.bean.GbStream;
5   -import com.genersoft.iot.vmp.media.zlm.ZLMServerConfig;
6 5 import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
  6 +import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
  7 +import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
7 8 import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem;
8 9 import com.genersoft.iot.vmp.service.IGbStreamService;
  10 +import com.genersoft.iot.vmp.service.IMediaServerService;
9 11 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
10 12 import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
11 13 import com.genersoft.iot.vmp.storager.dao.GbStreamMapper;
... ... @@ -13,6 +15,8 @@ import com.genersoft.iot.vmp.storager.dao.PlatformGbStreamMapper;
13 15 import com.genersoft.iot.vmp.storager.dao.StreamProxyMapper;
14 16 import com.genersoft.iot.vmp.service.IStreamProxyService;
15 17 import com.github.pagehelper.PageInfo;
  18 +import org.slf4j.Logger;
  19 +import org.slf4j.LoggerFactory;
16 20 import org.springframework.beans.factory.annotation.Autowired;
17 21 import org.springframework.stereotype.Service;
18 22  
... ... @@ -25,6 +29,8 @@ import java.util.List;
25 29 @Service
26 30 public class StreamProxyServiceImpl implements IStreamProxyService {
27 31  
  32 + private final static Logger logger = LoggerFactory.getLogger(StreamProxyServiceImpl.class);
  33 +
28 34 @Autowired
29 35 private IVideoManagerStorager videoManagerStorager;
30 36  
... ... @@ -32,7 +38,7 @@ public class StreamProxyServiceImpl implements IStreamProxyService {
32 38 private IRedisCatchStorage redisCatchStorage;
33 39  
34 40 @Autowired
35   - private ZLMRESTfulUtils zlmresTfulUtils;
  41 + private ZLMRESTfulUtils zlmresTfulUtils;;
36 42  
37 43 @Autowired
38 44 private StreamProxyMapper streamProxyMapper;
... ... @@ -46,15 +52,28 @@ public class StreamProxyServiceImpl implements IStreamProxyService {
46 52 @Autowired
47 53 private IGbStreamService gbStreamService;
48 54  
  55 + @Autowired
  56 + private IMediaServerService mediaServerService;
  57 +
49 58  
50 59 @Override
51 60 public String save(StreamProxyItem param) {
52   - ZLMServerConfig mediaInfo = redisCatchStorage.getMediaInfo();
  61 + IMediaServerItem mediaInfo;
  62 + if ("auto".equals(param.getMediaServerId())){
  63 + mediaInfo = mediaServerService.getMediaServerForMinimumLoad();
  64 + }else {
  65 + mediaInfo = mediaServerService.getOne(param.getMediaServerId());
  66 + }
  67 + if (mediaInfo == null) {
  68 + logger.warn("保存代理未找到在线的ZLM...");
  69 + return "保存失败";
  70 + }
53 71 String dstUrl = String.format("rtmp://%s:%s/%s/%s", "127.0.0.1", mediaInfo.getRtmpPort(), param.getApp(),
54 72 param.getStream() );
55 73 param.setDst_url(dstUrl);
56 74 StringBuffer result = new StringBuffer();
57 75 boolean streamLive = false;
  76 + param.setMediaServerId(mediaInfo.getId());
58 77 // 更新
59 78 if (videoManagerStorager.queryStreamProxy(param.getApp(), param.getStream()) != null) {
60 79 if (videoManagerStorager.updateStreamProxy(param)) {
... ... @@ -81,6 +100,8 @@ public class StreamProxyServiceImpl implements IStreamProxyService {
81 100 videoManagerStorager.updateStreamProxy(param);
82 101 }
83 102 }
  103 + }else {
  104 + result.append("保存失败");
84 105 }
85 106  
86 107 }
... ... @@ -99,11 +120,18 @@ public class StreamProxyServiceImpl implements IStreamProxyService {
99 120 @Override
100 121 public JSONObject addStreamProxyToZlm(StreamProxyItem param) {
101 122 JSONObject result = null;
  123 + IMediaServerItem mediaServerItem = null;
  124 + if (param.getMediaServerId() == null) {
  125 + logger.warn("添加代理时MediaServerId 为null");
  126 + return null;
  127 + }else {
  128 + mediaServerItem = mediaServerService.getOne(param.getMediaServerId());
  129 + }
102 130 if ("default".equals(param.getType())){
103   - result = zlmresTfulUtils.addStreamProxy(param.getApp(), param.getStream(), param.getUrl(),
  131 + result = zlmresTfulUtils.addStreamProxy(mediaServerItem, param.getApp(), param.getStream(), param.getUrl(),
104 132 param.isEnable_hls(), param.isEnable_mp4(), param.getRtp_type());
105 133 }else if ("ffmpeg".equals(param.getType())) {
106   - result = zlmresTfulUtils.addFFmpegSource(param.getSrc_url(), param.getDst_url(),
  134 + result = zlmresTfulUtils.addFFmpegSource(mediaServerItem, param.getSrc_url(), param.getDst_url(),
107 135 param.getTimeout_ms() + "", param.isEnable_hls(), param.isEnable_mp4(),
108 136 param.getFfmpeg_cmd_key());
109 137 }
... ... @@ -112,8 +140,9 @@ public class StreamProxyServiceImpl implements IStreamProxyService {
112 140  
113 141 @Override
114 142 public JSONObject removeStreamProxyFromZlm(StreamProxyItem param) {
115   - JSONObject result = zlmresTfulUtils.closeStreams(param.getApp(), param.getStream());
116   -
  143 + if (param ==null) return null;
  144 + IMediaServerItem mediaServerItem = mediaServerService.getOne(param.getMediaServerId());
  145 + JSONObject result = zlmresTfulUtils.closeStreams(mediaServerItem, param.getApp(), param.getStream());
117 146 return result;
118 147 }
119 148  
... ... @@ -124,17 +153,18 @@ public class StreamProxyServiceImpl implements IStreamProxyService {
124 153  
125 154 @Override
126 155 public void del(String app, String stream) {
127   - StreamProxyItem streamProxyItem = new StreamProxyItem();
128   - streamProxyItem.setApp(app);
129   - streamProxyItem.setStream(stream);
130   - JSONObject jsonObject = removeStreamProxyFromZlm(streamProxyItem);
131   - if (jsonObject.getInteger("code") == 0) {
  156 + StreamProxyItem streamProxyItem = videoManagerStorager.queryStreamProxy(app, stream);
  157 + if (streamProxyItem != null) {
132 158 videoManagerStorager.deleteStreamProxy(app, stream);
133   - // 如果关联了国标那么移除关联
134   - gbStreamMapper.del(app, stream);
135   - platformGbStreamMapper.delByAppAndStream(app, stream);
136   - // TODO 如果关联的推流, 那么状态设置为离线
  159 + JSONObject jsonObject = removeStreamProxyFromZlm(streamProxyItem);
  160 + if (jsonObject != null && jsonObject.getInteger("code") == 0) {
  161 + // 如果关联了国标那么移除关联
  162 + gbStreamMapper.del(app, stream);
  163 + platformGbStreamMapper.delByAppAndStream(app, stream);
  164 + // TODO 如果关联的推流, 那么状态设置为离线
  165 + }
137 166 }
  167 +
138 168 }
139 169  
140 170 @Override
... ... @@ -168,9 +198,9 @@ public class StreamProxyServiceImpl implements IStreamProxyService {
168 198 }
169 199  
170 200 @Override
171   - public JSONObject getFFmpegCMDs() {
  201 + public JSONObject getFFmpegCMDs(IMediaServerItem mediaServerItem) {
172 202 JSONObject result = new JSONObject();
173   - JSONObject mediaServerConfigResuly = zlmresTfulUtils.getMediaServerConfig();
  203 + JSONObject mediaServerConfigResuly = zlmresTfulUtils.getMediaServerConfig(mediaServerItem);
174 204 if (mediaServerConfigResuly != null && mediaServerConfigResuly.getInteger("code") == 0
175 205 && mediaServerConfigResuly.getJSONArray("data").size() > 0){
176 206 JSONObject mediaServerConfig = mediaServerConfigResuly.getJSONArray("data").getJSONObject(0);
... ...
src/main/java/com/genersoft/iot/vmp/service/impl/StreamPushServiceImpl.java
... ... @@ -5,9 +5,13 @@ import com.alibaba.fastjson.JSONObject;
5 5 import com.alibaba.fastjson.TypeReference;
6 6 import com.genersoft.iot.vmp.gb28181.bean.GbStream;
7 7 import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
  8 +import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
8 9 import com.genersoft.iot.vmp.media.zlm.dto.MediaItem;
  10 +import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
9 11 import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem;
  12 +import com.genersoft.iot.vmp.service.IMediaServerService;
10 13 import com.genersoft.iot.vmp.service.IStreamPushService;
  14 +import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
11 15 import com.genersoft.iot.vmp.storager.dao.GbStreamMapper;
12 16 import com.genersoft.iot.vmp.storager.dao.StreamPushMapper;
13 17 import com.github.pagehelper.PageHelper;
... ... @@ -32,8 +36,14 @@ public class StreamPushServiceImpl implements IStreamPushService {
32 36 @Autowired
33 37 private ZLMRESTfulUtils zlmresTfulUtils;
34 38  
  39 + @Autowired
  40 + private IRedisCatchStorage redisCatchStorage;
  41 +
  42 + @Autowired
  43 + private IMediaServerService mediaServerService;
  44 +
35 45 @Override
36   - public List<StreamPushItem> handleJSON(String jsonData) {
  46 + public List<StreamPushItem> handleJSON(String jsonData, IMediaServerItem mediaServerItem) {
37 47 if (jsonData == null) return null;
38 48  
39 49 Map<String, StreamPushItem> result = new HashMap<>();
... ... @@ -50,6 +60,7 @@ public class StreamPushServiceImpl implements IStreamPushService {
50 60 if (streamPushItem == null) {
51 61 streamPushItem = new StreamPushItem();
52 62 streamPushItem.setApp(item.getApp());
  63 + streamPushItem.setMediaServerId(mediaServerItem.getId());
53 64 streamPushItem.setStream(item.getStream());
54 65 streamPushItem.setAliveSecond(item.getAliveSecond());
55 66 streamPushItem.setCreateStamp(item.getCreateStamp());
... ... @@ -87,7 +98,8 @@ public class StreamPushServiceImpl implements IStreamPushService {
87 98 @Override
88 99 public boolean removeFromGB(GbStream stream) {
89 100 int del = gbStreamMapper.del(stream.getApp(), stream.getStream());
90   - JSONObject mediaList = zlmresTfulUtils.getMediaList(stream.getApp(), stream.getStream());
  101 + IMediaServerItem mediaInfo = mediaServerService.getOne(stream.getMediaServerId());
  102 + JSONObject mediaList = zlmresTfulUtils.getMediaList(mediaInfo, stream.getApp(), stream.getStream());
91 103 if (mediaList == null) {
92 104 streamPushMapper.del(stream.getApp(), stream.getStream());
93 105 }
... ...
src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java
... ... @@ -2,10 +2,11 @@ package com.genersoft.iot.vmp.storager;
2 2  
3 3 import com.alibaba.fastjson.JSONObject;
4 4 import com.genersoft.iot.vmp.common.StreamInfo;
5   -import com.genersoft.iot.vmp.media.zlm.ZLMServerConfig;
6 5 import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
7 6 import com.genersoft.iot.vmp.gb28181.bean.ParentPlatformCatch;
8 7 import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
  8 +import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
  9 +import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
9 10  
10 11 import java.util.List;
11 12 import java.util.Map;
... ... @@ -40,19 +41,6 @@ public interface IRedisCatchStorage {
40 41  
41 42 StreamInfo queryPlayByDevice(String deviceId, String channelId);
42 43  
43   - /**
44   - * 更新流媒体信息
45   - * @param ZLMServerConfig
46   - * @return
47   - */
48   - boolean updateMediaInfo(ZLMServerConfig ZLMServerConfig);
49   -
50   - /**
51   - * 获取流媒体信息
52   - * @return
53   - */
54   - ZLMServerConfig getMediaInfo();
55   -
56 44 Map<String, StreamInfo> queryPlayByDeviceId(String deviceId);
57 45  
58 46 boolean startPlayback(StreamInfo stream);
... ... @@ -115,6 +103,13 @@ public interface IRedisCatchStorage {
115 103 void clearCatchByDeviceId(String deviceId);
116 104  
117 105 /**
  106 + * 获取mediaServer节点
  107 + * @param mediaServerId
  108 + * @return
  109 + */
  110 +// MediaServerItem getMediaInfo(String mediaServerId);
  111 +
  112 + /**
118 113 * 设置所有设备离线
119 114 */
120 115 void outlineForAll();
... ...
src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorager.java
... ... @@ -3,6 +3,8 @@ package com.genersoft.iot.vmp.storager;
3 3 import java.util.List;
4 4  
5 5 import com.genersoft.iot.vmp.gb28181.bean.*;
  6 +import com.genersoft.iot.vmp.media.zlm.ZLMServerConfig;
  7 +import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
6 8 import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem;
7 9 import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem;
8 10 import com.genersoft.iot.vmp.vmanager.gb28181.platform.bean.ChannelReduce;
... ... @@ -365,4 +367,12 @@ public interface IVideoManagerStorager {
365 367 * @param online
366 368 */
367 369 void updateParentPlatformStatus(String platformGbID, boolean online);
  370 +
  371 + /**
  372 + * 更新媒体节点
  373 + * @param mediaServerItem
  374 + */
  375 + void updateMediaServer(MediaServerItem mediaServerItem);
  376 +
  377 + List<StreamProxyItem> getStreamProxyListForEnableInMediaServer(String id, boolean b);
368 378 }
... ...
src/main/java/com/genersoft/iot/vmp/storager/dao/GbStreamMapper.java
... ... @@ -12,9 +12,10 @@ import java.util.List;
12 12 public interface GbStreamMapper {
13 13  
14 14 @Insert("INSERT INTO gb_stream (app, stream, gbId, name, " +
15   - "longitude, latitude, streamType, status) VALUES" +
  15 + "longitude, latitude, streamType, mediaServerId, status) VALUES" +
16 16 "('${app}', '${stream}', '${gbId}', '${name}', " +
17   - "'${longitude}', '${latitude}', '${streamType}', ${status})")
  17 + "'${longitude}', '${latitude}', '${streamType}', " +
  18 + "'${mediaServerId}', ${status})")
18 19 int add(GbStream gbStream);
19 20  
20 21 @Update("UPDATE gb_stream " +
... ... @@ -25,6 +26,7 @@ public interface GbStreamMapper {
25 26 "streamType=#{streamType}," +
26 27 "longitude=#{longitude}, " +
27 28 "latitude=#{latitude}," +
  29 + "mediaServerId=#{mediaServerId}," +
28 30 "status=${status} " +
29 31 "WHERE app=#{app} AND stream=#{stream} AND gbId=#{gbId}")
30 32 int update(GbStream gbStream);
... ... @@ -52,4 +54,7 @@ public interface GbStreamMapper {
52 54 "SET status=${status} " +
53 55 "WHERE app=#{app} AND stream=#{stream}")
54 56 void setStatus(String app, String stream, boolean status);
  57 +
  58 + @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} ")
  59 + List<GbStream> selectAllByMediaServerId(String mediaServerId);
55 60 }
... ...
src/main/java/com/genersoft/iot/vmp/storager/dao/MediaServerMapper.java 0 → 100644
  1 +package com.genersoft.iot.vmp.storager.dao;
  2 +
  3 +import com.genersoft.iot.vmp.conf.MediaConfig;
  4 +import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
  5 +import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
  6 +import org.apache.ibatis.annotations.Insert;
  7 +import org.apache.ibatis.annotations.Mapper;
  8 +import org.apache.ibatis.annotations.Select;
  9 +import org.apache.ibatis.annotations.Update;
  10 +import org.springframework.stereotype.Repository;
  11 +
  12 +import java.util.List;
  13 +
  14 +
  15 +@Mapper
  16 +@Repository
  17 +public interface MediaServerMapper {
  18 +
  19 + @Insert("INSERT INTO media_server (" +
  20 + "id, " +
  21 + "ip, " +
  22 + "hookIp, " +
  23 + "sdpIp, " +
  24 + "streamIp, " +
  25 + "httpPort, " +
  26 + "httpSSlPort, " +
  27 + "rtmpPort, " +
  28 + "rtmpSSlPort, " +
  29 + "rtpProxyPort, " +
  30 + "rtspPort, " +
  31 + "rtspSSLPort, " +
  32 + "autoConfig, " +
  33 + "secret, " +
  34 + "streamNoneReaderDelayMS, " +
  35 + "rtpEnable, " +
  36 + "rtpPortRange, " +
  37 + "recordAssistPort, " +
  38 + "createTime, " +
  39 + "updateTime" +
  40 + ") VALUES " +
  41 + "(" +
  42 + "'${id}', " +
  43 + "'${ip}', " +
  44 + "'${hookIp}', " +
  45 + "'${sdpIp}', " +
  46 + "'${streamIp}', " +
  47 + "${httpPort}, " +
  48 + "${httpSSlPort}, " +
  49 + "${rtmpPort}, " +
  50 + "${rtmpSSlPort}, " +
  51 + "${rtpProxyPort}, " +
  52 + "${rtspPort}, " +
  53 + "${rtspSSLPort}, " +
  54 + "${autoConfig}, " +
  55 + "'${secret}', " +
  56 + "${streamNoneReaderDelayMS}, " +
  57 + "${rtpEnable}, " +
  58 + "'${rtpPortRange}', " +
  59 + "${recordAssistPort}, " +
  60 + "'${createTime}', " +
  61 + "'${updateTime}')")
  62 + int add(IMediaServerItem mediaServerItem);
  63 +
  64 + @Update(value = {" <script>" +
  65 + "UPDATE media_server " +
  66 + "SET updateTime='${updateTime}'" +
  67 + "<if test=\"ip != null\">, ip='${ip}'</if>" +
  68 + "<if test=\"hookIp != null\">, hookIp='${hookIp}'</if>" +
  69 + "<if test=\"sdpIp != null\">, sdpIp='${sdpIp}'</if>" +
  70 + "<if test=\"streamIp != null\">, streamIp='${streamIp}'</if>" +
  71 + "<if test=\"httpPort != null\">, httpPort=${httpPort}</if>" +
  72 + "<if test=\"httpSSlPort != null\">, httpSSlPort=${httpSSlPort}</if>" +
  73 + "<if test=\"rtmpPort != null\">, rtmpPort=${rtmpPort}</if>" +
  74 + "<if test=\"rtmpSSlPort != null\">, rtmpSSlPort=${rtmpSSlPort}</if>" +
  75 + "<if test=\"rtpProxyPort != null\">, rtpProxyPort=${rtpProxyPort}</if>" +
  76 + "<if test=\"rtspPort != null\">, rtspPort=${rtspPort}</if>" +
  77 + "<if test=\"rtspSSLPort != null\">, rtspSSLPort=${rtspSSLPort}</if>" +
  78 + "<if test=\"autoConfig != null\">, autoConfig=${autoConfig}</if>" +
  79 + "<if test=\"streamNoneReaderDelayMS != null\">, streamNoneReaderDelayMS=${streamNoneReaderDelayMS}</if>" +
  80 + "<if test=\"rtpEnable != null\">, rtpEnable=${rtpEnable}</if>" +
  81 + "<if test=\"rtpPortRange != null\">, rtpPortRange='${rtpPortRange}'</if>" +
  82 + "<if test=\"secret != null\">, secret='${secret}'</if>" +
  83 + "<if test=\"recordAssistPort != null\">, recordAssistPort=${recordAssistPort}</if>" +
  84 + "WHERE id='${id}'"+
  85 + " </script>"})
  86 + int update(IMediaServerItem mediaServerItem);
  87 +
  88 + @Select("SELECT * FROM media_server WHERE id='${id}'")
  89 + MediaServerItem queryOne(String id);
  90 +
  91 + @Select("SELECT * FROM media_server")
  92 + List<MediaServerItem> queryAll();
  93 +
  94 + @Select("DELETE FROM media_server WHERE id='${id}'")
  95 + int delOne(String secret);
  96 +
  97 + @Select("SELECT * FROM media_server WHERE ip='${host}' and httpPort=${port}")
  98 + MediaServerItem queryOneByHostAndPort(String host, int port);
  99 +}
... ...
src/main/java/com/genersoft/iot/vmp/storager/dao/StreamProxyMapper.java
... ... @@ -10,10 +10,10 @@ import java.util.List;
10 10 @Repository
11 11 public interface StreamProxyMapper {
12 12  
13   - @Insert("INSERT INTO stream_proxy (type, app, stream, url, src_url, dst_url, " +
14   - "timeout_ms, ffmpeg_cmd_key, rtp_type, enable_hls, enable_mp4, enable) VALUES" +
15   - "('${type}','${app}', '${stream}', '${url}', '${src_url}', '${dst_url}', " +
16   - "'${timeout_ms}', '${ffmpeg_cmd_key}', '${rtp_type}', ${enable_hls}, ${enable_mp4}, ${enable} )")
  13 + @Insert("INSERT INTO stream_proxy (type, app, stream,mediaServerId, url, src_url, dst_url, " +
  14 + "timeout_ms, ffmpeg_cmd_key, rtp_type, enable_hls, enable_mp4, enable, createTime) VALUES" +
  15 + "('${type}','${app}', '${stream}', '${mediaServerId}','${url}', '${src_url}', '${dst_url}', " +
  16 + "'${timeout_ms}', '${ffmpeg_cmd_key}', '${rtp_type}', ${enable_hls}, ${enable_mp4}, ${enable}, '${createTime}' )")
17 17 int add(StreamProxyItem streamProxyDto);
18 18  
19 19 @Update("UPDATE stream_proxy " +
... ... @@ -21,6 +21,7 @@ public interface StreamProxyMapper {
21 21 "app=#{app}," +
22 22 "stream=#{stream}," +
23 23 "url=#{url}, " +
  24 + "mediaServerId=#{mediaServerId}, " +
24 25 "src_url=#{src_url}," +
25 26 "dst_url=#{dst_url}, " +
26 27 "timeout_ms=#{timeout_ms}, " +
... ... @@ -35,12 +36,17 @@ public interface StreamProxyMapper {
35 36 @Delete("DELETE FROM stream_proxy WHERE app=#{app} AND stream=#{stream}")
36 37 int del(String app, String stream);
37 38  
38   - @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")
  39 + @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")
39 40 List<StreamProxyItem> selectAll();
40 41  
41   - @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}")
  42 + @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")
42 43 List<StreamProxyItem> selectForEnable(boolean enable);
43 44  
44   - @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}")
  45 + @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")
45 46 StreamProxyItem selectOne(String app, String stream);
  47 +
  48 + @Select("SELECT st.*, pgs.gbId, pgs.name, pgs.longitude, pgs.latitude FROM stream_proxy st " +
  49 + "LEFT JOIN gb_stream pgs on st.app = pgs.app AND st.stream = pgs.stream " +
  50 + "WHERE st.enable=${enable} and st.mediaServerId = '${id}' order by st.createTime desc")
  51 + List<StreamProxyItem> selectForEnableInMediaServer(String id, boolean enable);
46 52 }
... ...
src/main/java/com/genersoft/iot/vmp/storager/dao/StreamPushMapper.java
... ... @@ -11,14 +11,15 @@ import java.util.List;
11 11 public interface StreamPushMapper {
12 12  
13 13 @Insert("INSERT INTO stream_push (app, stream, totalReaderCount, originType, originTypeStr, " +
14   - "createStamp, aliveSecond) VALUES" +
  14 + "createStamp, aliveSecond, mediaServerId) VALUES" +
15 15 "('${app}', '${stream}', '${totalReaderCount}', '${originType}', '${originTypeStr}', " +
16   - "'${createStamp}', '${aliveSecond}' )")
  16 + "'${createStamp}', '${aliveSecond}', '${mediaServerId}' )")
17 17 int add(StreamPushItem streamPushItem);
18 18  
19 19 @Update("UPDATE stream_push " +
20 20 "SET app=#{app}," +
21 21 "stream=#{stream}," +
  22 + "mediaServerId=#{mediaServerId}," +
22 23 "totalReaderCount=#{totalReaderCount}, " +
23 24 "originType=#{originType}," +
24 25 "originTypeStr=#{originTypeStr}, " +
... ... @@ -41,10 +42,10 @@ public interface StreamPushMapper {
41 42  
42 43 @Insert("<script>" +
43 44 "INSERT INTO stream_push (app, stream, totalReaderCount, originType, originTypeStr, " +
44   - "createStamp, aliveSecond) " +
  45 + "createStamp, aliveSecond, mediaServerId) " +
45 46 "VALUES <foreach collection='streamPushItems' item='item' index='index' >" +
46 47 "( '${item.app}', '${item.stream}', '${item.totalReaderCount}', '${item.originType}', " +
47   - "'${item.originTypeStr}','${item.createStamp}', '${item.aliveSecond}' )" +
  48 + "'${item.originTypeStr}','${item.createStamp}', '${item.aliveSecond}', '${item.mediaServerId}' )" +
48 49 " </foreach>" +
49 50 "</script>")
50 51 void addAll(List<StreamPushItem> streamPushItems);
... ...
src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java
... ... @@ -5,6 +5,8 @@ import com.genersoft.iot.vmp.common.StreamInfo;
5 5 import com.genersoft.iot.vmp.common.VideoManagerConstants;
6 6 import com.genersoft.iot.vmp.media.zlm.ZLMServerConfig;
7 7 import com.genersoft.iot.vmp.gb28181.bean.*;
  8 +import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
  9 +import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
8 10 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
9 11 import com.genersoft.iot.vmp.storager.dao.DeviceChannelMapper;
10 12 import com.genersoft.iot.vmp.utils.redis.RedisUtil;
... ... @@ -87,26 +89,6 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage {
87 89 return (StreamInfo)redis.get(playLeys.get(0).toString());
88 90 }
89 91  
90   - /**
91   - * 更新流媒体信息
92   - * @param ZLMServerConfig
93   - * @return
94   - */
95   - @Override
96   - public boolean updateMediaInfo(ZLMServerConfig ZLMServerConfig) {
97   - ZLMServerConfig.setUpdateTime(format.format(new Date(System.currentTimeMillis())));
98   - return redis.set(VideoManagerConstants.MEDIA_SERVER_PREFIX, ZLMServerConfig);
99   - }
100   -
101   - /**
102   - * 获取流媒体信息
103   - * @return
104   - */
105   - @Override
106   - public ZLMServerConfig getMediaInfo() {
107   - return (ZLMServerConfig)redis.get(VideoManagerConstants.MEDIA_SERVER_PREFIX);
108   - }
109   -
110 92 @Override
111 93 public Map<String, StreamInfo> queryPlayByDeviceId(String deviceId) {
112 94 Map<String, StreamInfo> streamInfos = new HashMap<>();
... ... @@ -297,7 +279,7 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage {
297 279  
298 280 @Override
299 281 public void outlineForAll() {
300   - List<Object> onlineDevices = redis.scan(String.format("%S*", VideoManagerConstants.KEEPLIVEKEY_PREFIX));
  282 + List<Object> onlineDevices = redis.scan(VideoManagerConstants.KEEPLIVEKEY_PREFIX + "*" );
301 283 for (int i = 0; i < onlineDevices.size(); i++) {
302 284 String key = (String) onlineDevices.get(i);
303 285 redis.del(key);
... ... @@ -308,4 +290,5 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage {
308 290 public void updateWVPInfo(JSONObject jsonObject) {
309 291  
310 292 }
  293 +
311 294 }
... ...
src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStoragerImpl.java
... ... @@ -5,6 +5,7 @@ import java.util.*;
5 5  
6 6 import com.genersoft.iot.vmp.gb28181.bean.*;
7 7 import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
  8 +import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
8 9 import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem;
9 10 import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem;
10 11 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
... ... @@ -70,6 +71,9 @@ public class VideoManagerStoragerImpl implements IVideoManagerStorager {
70 71 @Autowired
71 72 private VideoStreamSessionManager streamSession;
72 73  
  74 + @Autowired
  75 + private MediaServerMapper mediaServerMapper;
  76 +
73 77 private SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
74 78  
75 79  
... ... @@ -459,6 +463,8 @@ public class VideoManagerStoragerImpl implements IVideoManagerStorager {
459 463 boolean result = false;
460 464 streamProxyItem.setStreamType("proxy");
461 465 streamProxyItem.setStatus(true);
  466 + String now = this.format.format(new Date(System.currentTimeMillis()));
  467 + streamProxyItem.setCreateTime(now);
462 468 try {
463 469 if (gbStreamMapper.add(streamProxyItem)<0 || streamProxyMapper.add(streamProxyItem) < 0) {
464 470 //事务回滚
... ... @@ -467,6 +473,7 @@ public class VideoManagerStoragerImpl implements IVideoManagerStorager {
467 473 result = true;
468 474 dataSourceTransactionManager.commit(transactionStatus); //手动提交
469 475 }catch (Exception e) {
  476 + logger.error("向数据库添加流代理失败:", e);
470 477 dataSourceTransactionManager.rollback(transactionStatus);
471 478 }
472 479 return result;
... ... @@ -599,4 +606,21 @@ public class VideoManagerStoragerImpl implements IVideoManagerStorager {
599 606 public void updateParentPlatformStatus(String platformGbID, boolean online) {
600 607 platformMapper.updateParentPlatformStatus(platformGbID, online);
601 608 }
  609 +
  610 + @Override
  611 + public void updateMediaServer(MediaServerItem mediaServerItem) {
  612 + String now = this.format.format(new Date(System.currentTimeMillis()));
  613 + mediaServerItem.setUpdateTime(now);
  614 + if (mediaServerMapper.queryOne(mediaServerItem.getId()) != null) {
  615 + mediaServerMapper.update(mediaServerItem);
  616 + }else {
  617 + mediaServerItem.setCreateTime(now);
  618 + mediaServerMapper.add(mediaServerItem);
  619 + }
  620 + }
  621 +
  622 + @Override
  623 + public List<StreamProxyItem> getStreamProxyListForEnableInMediaServer(String id, boolean enable) {
  624 + return streamProxyMapper.selectForEnableInMediaServer(id, enable);
  625 + }
602 626 }
... ...
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceConfig.java
... ... @@ -25,6 +25,7 @@ import org.slf4j.Logger;
25 25 import org.slf4j.LoggerFactory;
26 26 import org.springframework.beans.factory.annotation.Autowired;
27 27 import org.springframework.http.ResponseEntity;
  28 +import org.springframework.util.StringUtils;
28 29 import org.springframework.web.bind.annotation.*;
29 30 import org.springframework.web.context.request.async.DeferredResult;
30 31  
... ... @@ -78,7 +79,7 @@ public class DeviceConfig {
78 79 cmder.deviceBasicConfigCmd(device, channelId, name, expiration, heartBeatInterval, heartBeatCount, event -> {
79 80 Response response = event.getResponse();
80 81 RequestMessage msg = new RequestMessage();
81   - msg.setId(DeferredResultHolder.CALLBACK_CMD_DEVICECONFIG + (XmlUtil.isEmpty(channelId) ? deviceId : channelId));
  82 + msg.setId(DeferredResultHolder.CALLBACK_CMD_DEVICECONFIG + (StringUtils.isEmpty(channelId) ? deviceId : channelId));
82 83 msg.setData(String.format("设备配置操作失败,错误码: %s, %s", response.getStatusCode(), response.getReasonPhrase()));
83 84 resultHolder.invokeResult(msg);
84 85 });
... ... @@ -87,7 +88,7 @@ public class DeviceConfig {
87 88 logger.warn(String.format("设备配置操作超时, 设备未返回应答指令"));
88 89 // 释放rtpserver
89 90 RequestMessage msg = new RequestMessage();
90   - msg.setId(DeferredResultHolder.CALLBACK_CMD_DEVICECONFIG + (XmlUtil.isEmpty(channelId) ? deviceId : channelId));
  91 + msg.setId(DeferredResultHolder.CALLBACK_CMD_DEVICECONFIG + (StringUtils.isEmpty(channelId) ? deviceId : channelId));
91 92 JSONObject json = new JSONObject();
92 93 json.put("DeviceID", deviceId);
93 94 json.put("Status", "Timeout");
... ... @@ -95,7 +96,7 @@ public class DeviceConfig {
95 96 msg.setData(json); //("看守位控制操作超时, 设备未返回应答指令");
96 97 resultHolder.invokeResult(msg);
97 98 });
98   - resultHolder.put(DeferredResultHolder.CALLBACK_CMD_DEVICECONFIG + (XmlUtil.isEmpty(channelId) ? deviceId : channelId), result);
  99 + resultHolder.put(DeferredResultHolder.CALLBACK_CMD_DEVICECONFIG + (StringUtils.isEmpty(channelId) ? deviceId : channelId), result);
99 100 return result;
100 101 }
101 102  
... ... @@ -123,7 +124,7 @@ public class DeviceConfig {
123 124 cmder.deviceConfigQuery(device, channelId, configType, event -> {
124 125 Response response = event.getResponse();
125 126 RequestMessage msg = new RequestMessage();
126   - msg.setId(DeferredResultHolder.CALLBACK_CMD_CONFIGDOWNLOAD + (XmlUtil.isEmpty(channelId) ? deviceId : channelId));
  127 + msg.setId(DeferredResultHolder.CALLBACK_CMD_CONFIGDOWNLOAD + (StringUtils.isEmpty(channelId) ? deviceId : channelId));
127 128 msg.setData(String.format("获取设备配置失败,错误码: %s, %s", response.getStatusCode(), response.getReasonPhrase()));
128 129 resultHolder.invokeResult(msg);
129 130 });
... ... @@ -132,11 +133,11 @@ public class DeviceConfig {
132 133 logger.warn(String.format("获取设备配置超时"));
133 134 // 释放rtpserver
134 135 RequestMessage msg = new RequestMessage();
135   - msg.setId(DeferredResultHolder.CALLBACK_CMD_CONFIGDOWNLOAD + (XmlUtil.isEmpty(channelId) ? deviceId : channelId));
  136 + msg.setId(DeferredResultHolder.CALLBACK_CMD_CONFIGDOWNLOAD + (StringUtils.isEmpty(channelId) ? deviceId : channelId));
136 137 msg.setData("Timeout. Device did not response to this command.");
137 138 resultHolder.invokeResult(msg);
138 139 });
139   - resultHolder.put(DeferredResultHolder.CALLBACK_CMD_CONFIGDOWNLOAD + (XmlUtil.isEmpty(channelId) ? deviceId : channelId), result);
  140 + resultHolder.put(DeferredResultHolder.CALLBACK_CMD_CONFIGDOWNLOAD + (StringUtils.isEmpty(channelId) ? deviceId : channelId), result);
140 141 return result;
141 142 }
142 143  
... ...
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceControl.java
... ... @@ -26,6 +26,7 @@ import org.slf4j.LoggerFactory;
26 26 import org.springframework.beans.factory.annotation.Autowired;
27 27 import org.springframework.http.HttpStatus;
28 28 import org.springframework.http.ResponseEntity;
  29 +import org.springframework.util.StringUtils;
29 30 import org.springframework.web.bind.annotation.*;
30 31 import org.springframework.web.context.request.async.DeferredResult;
31 32  
... ... @@ -97,7 +98,7 @@ public class DeviceControl {
97 98 cmder.recordCmd(device, channelId, recordCmdStr, event -> {
98 99 Response response = event.getResponse();
99 100 RequestMessage msg = new RequestMessage();
100   - msg.setId(DeferredResultHolder.CALLBACK_CMD_DEVICECONTROL + (XmlUtil.isEmpty(channelId) ? deviceId : channelId));
  101 + msg.setId(DeferredResultHolder.CALLBACK_CMD_DEVICECONTROL + (StringUtils.isEmpty(channelId) ? deviceId : channelId));
101 102 msg.setData(String.format("开始/停止录像操作失败,错误码: %s, %s", response.getStatusCode(), response.getReasonPhrase()));
102 103 resultHolder.invokeResult(msg);
103 104 });
... ... @@ -106,11 +107,11 @@ public class DeviceControl {
106 107 logger.warn(String.format("开始/停止录像操作超时, 设备未返回应答指令"));
107 108 // 释放rtpserver
108 109 RequestMessage msg = new RequestMessage();
109   - msg.setId(DeferredResultHolder.CALLBACK_CMD_DEVICECONTROL + (XmlUtil.isEmpty(channelId) ? deviceId : channelId));
  110 + msg.setId(DeferredResultHolder.CALLBACK_CMD_DEVICECONTROL + (StringUtils.isEmpty(channelId) ? deviceId : channelId));
110 111 msg.setData("Timeout. Device did not response to this command.");
111 112 resultHolder.invokeResult(msg);
112 113 });
113   - resultHolder.put(DeferredResultHolder.CALLBACK_CMD_DEVICECONTROL + (XmlUtil.isEmpty(channelId) ? deviceId : channelId), result);
  114 + resultHolder.put(DeferredResultHolder.CALLBACK_CMD_DEVICECONTROL + (StringUtils.isEmpty(channelId) ? deviceId : channelId), result);
114 115 return result;
115 116 }
116 117  
... ... @@ -254,7 +255,7 @@ public class DeviceControl {
254 255 cmder.homePositionCmd(device, channelId, enabled, resetTime, presetIndex, event -> {
255 256 Response response = event.getResponse();
256 257 RequestMessage msg = new RequestMessage();
257   - msg.setId(DeferredResultHolder.CALLBACK_CMD_DEVICECONTROL + (XmlUtil.isEmpty(channelId) ? deviceId : channelId));
  258 + msg.setId(DeferredResultHolder.CALLBACK_CMD_DEVICECONTROL + (StringUtils.isEmpty(channelId) ? deviceId : channelId));
258 259 msg.setData(String.format("看守位控制操作失败,错误码: %s, %s", response.getStatusCode(), response.getReasonPhrase()));
259 260 resultHolder.invokeResult(msg);
260 261 });
... ... @@ -263,7 +264,7 @@ public class DeviceControl {
263 264 logger.warn(String.format("看守位控制操作超时, 设备未返回应答指令"));
264 265 // 释放rtpserver
265 266 RequestMessage msg = new RequestMessage();
266   - msg.setId(DeferredResultHolder.CALLBACK_CMD_DEVICECONTROL + (XmlUtil.isEmpty(channelId) ? deviceId : channelId));
  267 + msg.setId(DeferredResultHolder.CALLBACK_CMD_DEVICECONTROL + (StringUtils.isEmpty(channelId) ? deviceId : channelId));
267 268 JSONObject json = new JSONObject();
268 269 json.put("DeviceID", deviceId);
269 270 json.put("Status", "Timeout");
... ... @@ -271,7 +272,7 @@ public class DeviceControl {
271 272 msg.setData(json); //("看守位控制操作超时, 设备未返回应答指令");
272 273 resultHolder.invokeResult(msg);
273 274 });
274   - resultHolder.put(DeferredResultHolder.CALLBACK_CMD_DEVICECONTROL + (XmlUtil.isEmpty(channelId) ? deviceId : channelId), result);
  275 + resultHolder.put(DeferredResultHolder.CALLBACK_CMD_DEVICECONTROL + (StringUtils.isEmpty(channelId) ? deviceId : channelId), result);
275 276 return result;
276 277 }
277 278 }
... ...
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/media/MediaController.java
... ... @@ -43,11 +43,13 @@ public class MediaController {
43 43 @ApiImplicitParams({
44 44 @ApiImplicitParam(name = "app", value = "应用名", dataTypeClass = String.class),
45 45 @ApiImplicitParam(name = "stream", value = "流id", dataTypeClass = String.class),
  46 + @ApiImplicitParam(name = "mediaServerId", value = "媒体服务器id", dataTypeClass = String.class),
46 47 })
47 48 @GetMapping(value = "/stream_info_by_app_and_stream")
48 49 @ResponseBody
49   - public StreamInfo getStreamInfoByAppAndStream(String app, String stream){
50   - return mediaService.getStreamInfoByAppAndStreamWithCheck(app, stream);
  50 + public StreamInfo getStreamInfoByAppAndStream(@RequestParam String app, @RequestParam String stream, @RequestParam String mediaServerId){
  51 +
  52 + return mediaService.getStreamInfoByAppAndStreamWithCheck(app, stream,mediaServerId);
51 53 }
52 54  
53 55  
... ...
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/play/PlayController.java
... ... @@ -8,6 +8,9 @@ import com.genersoft.iot.vmp.gb28181.bean.Device;
8 8 import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
9 9 import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
10 10 import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
  11 +import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
  12 +import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
  13 +import com.genersoft.iot.vmp.service.IMediaServerService;
11 14 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
12 15 import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
13 16 import com.genersoft.iot.vmp.vmanager.gb28181.play.bean.PlayResult;
... ... @@ -72,6 +75,9 @@ public class PlayController {
72 75 @Autowired
73 76 private IMediaService mediaService;
74 77  
  78 + @Autowired
  79 + private IMediaServerService mediaServerService;
  80 +
75 81 @ApiOperation("开始点播")
76 82 @ApiImplicitParams({
77 83 @ApiImplicitParam(name = "deviceId", value = "设备ID", dataTypeClass = String.class),
... ... @@ -81,8 +87,10 @@ public class PlayController {
81 87 public DeferredResult<ResponseEntity<String>> play(@PathVariable String deviceId,
82 88 @PathVariable String channelId) {
83 89  
84   - PlayResult playResult = playService.play(deviceId, channelId, null, null);
85   -
  90 + // 获取可用的zlm
  91 + Device device = storager.queryVideoDevice(deviceId);
  92 + IMediaServerItem newMediaServerItem = playService.getNewMediaServerItem(device);
  93 + PlayResult playResult = playService.play(newMediaServerItem, deviceId, channelId, null, null);
86 94  
87 95 return playResult.getResult();
88 96 }
... ... @@ -102,8 +110,8 @@ public class PlayController {
102 110  
103 111 // 录像查询以channelId作为deviceId查询
104 112 resultHolder.put(DeferredResultHolder.CALLBACK_CMD_STOP + uuid, result);
105   -
106   - cmder.streamByeCmd(deviceId, channelId, event -> {
  113 + Device device = storager.queryVideoDevice(deviceId);
  114 + cmder.streamByeCmd(deviceId, channelId, (event) -> {
107 115 StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(deviceId, channelId);
108 116 if (streamInfo == null) {
109 117 RequestMessage msg = new RequestMessage();
... ... @@ -120,6 +128,7 @@ public class PlayController {
120 128 msg.setData(String.format("success"));
121 129 resultHolder.invokeResult(msg);
122 130 }
  131 + mediaServerService.closeRTPServer(device, channelId);
123 132 });
124 133  
125 134 if (deviceId != null || channelId != null) {
... ... @@ -165,16 +174,16 @@ public class PlayController {
165 174 logger.warn("视频转码API调用失败!, 视频流已经停止!");
166 175 return new ResponseEntity<String>("未找到视频流信息, 视频流可能已经停止", HttpStatus.OK);
167 176 }
168   - JSONObject rtpInfo = zlmresTfulUtils.getRtpInfo(streamId);
  177 + IMediaServerItem mediaInfo = mediaServerService.getOne(streamInfo.getMediaServerId());
  178 + JSONObject rtpInfo = zlmresTfulUtils.getRtpInfo(mediaInfo, streamId);
169 179 if (!rtpInfo.getBoolean("exist")) {
170 180 logger.warn("视频转码API调用失败!, 视频流已停止推流!");
171 181 return new ResponseEntity<String>("推流信息在流媒体中不存在, 视频流可能已停止推流", HttpStatus.OK);
172 182 } else {
173   - ZLMServerConfig mediaInfo = redisCatchStorage.getMediaInfo();
174 183 String dstUrl = String.format("rtmp://%s:%s/convert/%s", "127.0.0.1", mediaInfo.getRtmpPort(),
175 184 streamId );
176 185 String srcUrl = String.format("rtsp://%s:%s/rtp/%s", "127.0.0.1", mediaInfo.getRtspPort(), streamId);
177   - JSONObject jsonObject = zlmresTfulUtils.addFFmpegSource(srcUrl, dstUrl, "1000000", true, false, null);
  186 + JSONObject jsonObject = zlmresTfulUtils.addFFmpegSource(mediaInfo, srcUrl, dstUrl, "1000000", true, false, null);
178 187 logger.info(jsonObject.toJSONString());
179 188 JSONObject result = new JSONObject();
180 189 if (jsonObject != null && jsonObject.getInteger("code") == 0) {
... ... @@ -182,7 +191,7 @@ public class PlayController {
182 191 JSONObject data = jsonObject.getJSONObject("data");
183 192 if (data != null) {
184 193 result.put("key", data.getString("key"));
185   - StreamInfo streamInfoResult = mediaService.getStreamInfoByAppAndStreamWithCheck("convert", streamId);
  194 + StreamInfo streamInfoResult = mediaService.getStreamInfoByAppAndStreamWithCheck("convert", streamId, mediaInfo.getId());
186 195 result.put("data", streamInfoResult);
187 196 }
188 197 }else {
... ... @@ -203,25 +212,38 @@ public class PlayController {
203 212 @ApiImplicitParam(name = "key", value = "视频流key", dataTypeClass = String.class),
204 213 })
205 214 @PostMapping("/convertStop/{key}")
206   - public ResponseEntity<String> playConvertStop(@PathVariable String key) {
207   -
208   - JSONObject jsonObject = zlmresTfulUtils.delFFmpegSource(key);
209   - logger.info(jsonObject.toJSONString());
  215 + public ResponseEntity<String> playConvertStop(@PathVariable String key, String mediaServerId) {
210 216 JSONObject result = new JSONObject();
211   - if (jsonObject != null && jsonObject.getInteger("code") == 0) {
  217 + if (mediaServerId == null) {
  218 + result.put("code", 400);
  219 + result.put("msg", "mediaServerId is null");
  220 + return new ResponseEntity<String>( result.toJSONString(), HttpStatus.BAD_REQUEST);
  221 + }
  222 + IMediaServerItem mediaInfo = mediaServerService.getOne(mediaServerId);
  223 + if (mediaInfo == null) {
212 224 result.put("code", 0);
213   - JSONObject data = jsonObject.getJSONObject("data");
214   - if (data != null && data.getBoolean("flag")) {
215   - result.put("code", "0");
216   - result.put("msg", "success");
217   - }else {
  225 + result.put("msg", "使用的流媒体已经停止运行");
  226 + return new ResponseEntity<String>( result.toJSONString(), HttpStatus.OK);
  227 + }else {
  228 + JSONObject jsonObject = zlmresTfulUtils.delFFmpegSource(mediaInfo, key);
  229 + logger.info(jsonObject.toJSONString());
  230 + if (jsonObject != null && jsonObject.getInteger("code") == 0) {
  231 + result.put("code", 0);
  232 + JSONObject data = jsonObject.getJSONObject("data");
  233 + if (data != null && data.getBoolean("flag")) {
  234 + result.put("code", "0");
  235 + result.put("msg", "success");
  236 + }else {
218 237  
  238 + }
  239 + }else {
  240 + result.put("code", 1);
  241 + result.put("msg", "delFFmpegSource fail");
219 242 }
220   - }else {
221   - result.put("code", 1);
222   - result.put("msg", "delFFmpegSource fail");
  243 + return new ResponseEntity<String>( result.toJSONString(), HttpStatus.OK);
223 244 }
224   - return new ResponseEntity<String>( result.toJSONString(), HttpStatus.OK);
  245 +
  246 +
225 247 }
226 248  
227 249 @ApiOperation("语音广播命令")
... ... @@ -249,7 +271,7 @@ public class PlayController {
249 271 resultHolder.invokeResult(msg);
250 272 return result;
251 273 }
252   - cmder.audioBroadcastCmd(device, event -> {
  274 + cmder.audioBroadcastCmd(device, (event) -> {
253 275 Response response = event.getResponse();
254 276 RequestMessage msg = new RequestMessage();
255 277 msg.setId(DeferredResultHolder.CALLBACK_CMD_BROADCAST + deviceId);
... ...
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/playback/PlaybackController.java
... ... @@ -4,6 +4,8 @@ import com.genersoft.iot.vmp.common.StreamInfo;
4 4 import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
5 5 import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
6 6 //import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
  7 +import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
  8 +import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
7 9 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
8 10 import com.genersoft.iot.vmp.service.IPlayService;
9 11 import io.swagger.annotations.Api;
... ... @@ -87,9 +89,18 @@ public class PlaybackController {
87 89 cmder.streamByeCmd(deviceId, channelId);
88 90 }
89 91 resultHolder.put(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid, result);
90   - cmder.playbackStreamCmd(device, channelId, startTime, endTime, (JSONObject response) -> {
  92 + IMediaServerItem newMediaServerItem = playService.getNewMediaServerItem(device);
  93 + if (newMediaServerItem == null) {
  94 + logger.warn(String.format("设备回放超时,deviceId:%s ,channelId:%s", deviceId, channelId));
  95 + RequestMessage msg = new RequestMessage();
  96 + msg.setId(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid);
  97 + msg.setData("Timeout");
  98 + resultHolder.invokeResult(msg);
  99 + return result;
  100 + }
  101 + cmder.playbackStreamCmd(newMediaServerItem, device, channelId, startTime, endTime, (IMediaServerItem mediaServerItem, JSONObject response) -> {
91 102 logger.info("收到订阅消息: " + response.toJSONString());
92   - playService.onPublishHandlerForPlayBack(response, deviceId, channelId, uuid.toString());
  103 + playService.onPublishHandlerForPlayBack(mediaServerItem, response, deviceId, channelId, uuid.toString());
93 104 }, event -> {
94 105 Response response = event.getResponse();
95 106 RequestMessage msg = new RequestMessage();
... ...
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/ptz/PtzController.java
... ... @@ -9,6 +9,7 @@ import org.slf4j.LoggerFactory;
9 9 import org.springframework.beans.factory.annotation.Autowired;
10 10 import org.springframework.http.HttpStatus;
11 11 import org.springframework.http.ResponseEntity;
  12 +import org.springframework.util.StringUtils;
12 13 import org.springframework.web.bind.annotation.*;
13 14 import org.springframework.web.context.request.async.DeferredResult;
14 15  
... ... @@ -104,7 +105,7 @@ public class PtzController {
104 105 cmder.presetQuery(device, channelId, event -> {
105 106 Response response = event.getResponse();
106 107 RequestMessage msg = new RequestMessage();
107   - msg.setId(DeferredResultHolder.CALLBACK_CMD_PRESETQUERY + (XmlUtil.isEmpty(channelId) ? deviceId : channelId));
  108 + msg.setId(DeferredResultHolder.CALLBACK_CMD_PRESETQUERY + (StringUtils.isEmpty(channelId) ? deviceId : channelId));
108 109 msg.setData(String.format("获取设备预置位失败,错误码: %s, %s", response.getStatusCode(), response.getReasonPhrase()));
109 110 resultHolder.invokeResult(msg);
110 111 });
... ... @@ -113,11 +114,11 @@ public class PtzController {
113 114 logger.warn(String.format("获取设备预置位超时"));
114 115 // 释放rtpserver
115 116 RequestMessage msg = new RequestMessage();
116   - msg.setId(DeferredResultHolder.CALLBACK_CMD_PRESETQUERY + (XmlUtil.isEmpty(channelId) ? deviceId : channelId));
  117 + msg.setId(DeferredResultHolder.CALLBACK_CMD_PRESETQUERY + (StringUtils.isEmpty(channelId) ? deviceId : channelId));
117 118 msg.setData("获取设备预置位超时");
118 119 resultHolder.invokeResult(msg);
119 120 });
120   - resultHolder.put(DeferredResultHolder.CALLBACK_CMD_PRESETQUERY + (XmlUtil.isEmpty(channelId) ? deviceId : channelId), result);
  121 + resultHolder.put(DeferredResultHolder.CALLBACK_CMD_PRESETQUERY + (StringUtils.isEmpty(channelId) ? deviceId : channelId), result);
121 122 return result;
122 123 }
123 124 }
... ...
src/main/java/com/genersoft/iot/vmp/vmanager/record/RecoderProxyController.java
... ... @@ -2,6 +2,9 @@ package com.genersoft.iot.vmp.vmanager.record;
2 2  
3 3 import com.genersoft.iot.vmp.conf.MediaConfig;
4 4 import com.genersoft.iot.vmp.media.zlm.ZLMServerConfig;
  5 +import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
  6 +import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
  7 +import com.genersoft.iot.vmp.service.IMediaServerService;
5 8 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
6 9 import org.springframework.beans.factory.annotation.Autowired;
7 10 import org.springframework.http.HttpStatus;
... ... @@ -27,6 +30,8 @@ public class RecoderProxyController {
27 30  
28 31 @Autowired
29 32 private IRedisCatchStorage redisCatchStorage;
  33 + @Autowired
  34 + private IMediaServerService mediaServerService;
30 35  
31 36 @Autowired
32 37 private MediaConfig mediaConfig;
... ... @@ -48,7 +53,11 @@ public class RecoderProxyController {
48 53 return null;
49 54 }
50 55 // 后续改为根据Id获取对应的ZLM
51   - ZLMServerConfig mediaInfo = redisCatchStorage.getMediaInfo();
  56 + IMediaServerItem mediaInfo = mediaServerService.getOne(mediaId);
  57 + if (mediaInfo == null) {
  58 + response.setStatus(HttpStatus.NOT_FOUND.value());
  59 + return null;
  60 + }
52 61 String requestURI = String.format("http://%s:%s%s?%s",
53 62 mediaInfo.getSdpIp(),
54 63 mediaConfig.getRecordAssistPort(),
... ...
src/main/java/com/genersoft/iot/vmp/vmanager/server/ServerController.java
... ... @@ -2,8 +2,11 @@ package com.genersoft.iot.vmp.vmanager.server;
2 2  
3 3 import com.genersoft.iot.vmp.VManageBootstrap;
4 4 import com.genersoft.iot.vmp.media.zlm.ZLMServerConfig;
  5 +import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
  6 +import com.genersoft.iot.vmp.service.IMediaServerService;
5 7 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
6 8 import com.genersoft.iot.vmp.utils.SpringBeanFactory;
  9 +import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
7 10 import gov.nist.javax.sip.SipStackImpl;
8 11 import io.swagger.annotations.Api;
9 12 import io.swagger.annotations.ApiOperation;
... ... @@ -16,6 +19,7 @@ import javax.sip.ObjectInUseException;
16 19 import javax.sip.SipProvider;
17 20 import java.util.ArrayList;
18 21 import java.util.Iterator;
  22 +import java.util.List;
19 23  
20 24 @SuppressWarnings("rawtypes")
21 25 @Api(tags = "服务控制")
... ... @@ -28,17 +32,28 @@ public class ServerController {
28 32 private ConfigurableApplicationContext context;
29 33  
30 34 @Autowired
31   - private IRedisCatchStorage redisCatchStorage;
  35 + private IMediaServerService mediaServerService;
32 36  
33 37  
34 38 @ApiOperation("流媒体服务列表")
35 39 @GetMapping(value = "/media_server/list")
36 40 @ResponseBody
37   - public Object getMediaServerList(){
38   - // TODO 为后续多个zlm支持准备
39   - ZLMServerConfig mediaInfo = redisCatchStorage.getMediaInfo();
40   - ArrayList<ZLMServerConfig> result = new ArrayList<>();
41   - result.add(mediaInfo);
  41 + public WVPResult<List<IMediaServerItem>> getMediaServerList(){
  42 + WVPResult<List<IMediaServerItem>> result = new WVPResult<>();
  43 + result.setCode(0);
  44 + result.setMsg("success");
  45 + result.setData(mediaServerService.getAll());
  46 + return result;
  47 + }
  48 +
  49 + @ApiOperation("获取流媒体服务")
  50 + @GetMapping(value = "/media_server/one/{id}")
  51 + @ResponseBody
  52 + public WVPResult<IMediaServerItem> getMediaServer(@PathVariable String id){
  53 + WVPResult<IMediaServerItem> result = new WVPResult<>();
  54 + result.setCode(0);
  55 + result.setMsg("success");
  56 + result.setData(mediaServerService.getOne(id));
42 57 return result;
43 58 }
44 59  
... ...
src/main/java/com/genersoft/iot/vmp/vmanager/streamProxy/StreamProxyController.java
1 1 package com.genersoft.iot.vmp.vmanager.streamProxy;
2 2  
3 3 import com.alibaba.fastjson.JSONObject;
  4 +import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
  5 +import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
4 6 import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem;
  7 +import com.genersoft.iot.vmp.service.IMediaServerService;
5 8 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
6 9 import com.genersoft.iot.vmp.service.IStreamProxyService;
7 10 import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
8 11 import com.github.pagehelper.PageInfo;
  12 +import io.netty.util.internal.StringUtil;
9 13 import io.swagger.annotations.Api;
10 14 import io.swagger.annotations.ApiImplicitParam;
11 15 import io.swagger.annotations.ApiImplicitParams;
... ... @@ -14,6 +18,7 @@ import org.slf4j.Logger;
14 18 import org.slf4j.LoggerFactory;
15 19 import org.springframework.beans.factory.annotation.Autowired;
16 20 import org.springframework.stereotype.Controller;
  21 +import org.springframework.util.StringUtils;
17 22 import org.springframework.web.bind.annotation.*;
18 23  
19 24 @SuppressWarnings("rawtypes")
... ... @@ -31,6 +36,10 @@ public class StreamProxyController {
31 36 @Autowired
32 37 private IRedisCatchStorage redisCatchStorage;
33 38  
  39 +
  40 + @Autowired
  41 + private IMediaServerService mediaServerService;
  42 +
34 43 @Autowired
35 44 private IStreamProxyService streamProxyService;
36 45  
... ... @@ -60,6 +69,7 @@ public class StreamProxyController {
60 69 @ResponseBody
61 70 public WVPResult save(@RequestBody StreamProxyItem param){
62 71 logger.info("添加代理: " + JSONObject.toJSONString(param));
  72 + if (StringUtils.isEmpty(param.getMediaServerId())) param.setMediaServerId("auto");
63 73 String msg = streamProxyService.save(param);
64 74 WVPResult<Object> result = new WVPResult<>();
65 75 result.setCode(0);
... ... @@ -69,10 +79,15 @@ public class StreamProxyController {
69 79  
70 80 @ApiOperation("获取ffmpeg.cmd模板")
71 81 @GetMapping(value = "/ffmpeg_cmd/list")
  82 + @ApiImplicitParams({
  83 + @ApiImplicitParam(name = "mediaServerId", value = "流媒体ID", dataTypeClass = String.class),
  84 + })
72 85 @ResponseBody
73   - public WVPResult getFFmpegCMDs(){
74   - logger.debug("获取ffmpeg.cmd模板:" );
75   - JSONObject data = streamProxyService.getFFmpegCMDs();
  86 + public WVPResult getFFmpegCMDs(@RequestParam String mediaServerId){
  87 + logger.debug("获取节点[ {} ]ffmpeg.cmd模板", mediaServerId );
  88 +
  89 + IMediaServerItem mediaServerItem = mediaServerService.getOne(mediaServerId);
  90 + JSONObject data = streamProxyService.getFFmpegCMDs(mediaServerItem);
76 91 WVPResult<JSONObject> result = new WVPResult<>();
77 92 result.setCode(0);
78 93 result.setMsg("success");
... ... @@ -82,12 +97,12 @@ public class StreamProxyController {
82 97  
83 98 @ApiOperation("移除代理")
84 99 @ApiImplicitParams({
85   - @ApiImplicitParam(name = "app", value = "应用名", dataTypeClass = String.class),
86   - @ApiImplicitParam(name = "stream", value = "流ID", dataTypeClass = String.class),
  100 + @ApiImplicitParam(name = "app", value = "应用名", required = true, dataTypeClass = String.class),
  101 + @ApiImplicitParam(name = "stream", value = "流ID", required = true, dataTypeClass = String.class),
87 102 })
88 103 @DeleteMapping(value = "/del")
89 104 @ResponseBody
90   - public WVPResult del(String app, String stream){
  105 + public WVPResult del(@RequestParam String app, @RequestParam String stream){
91 106 logger.info("移除代理: " + app + "/" + stream);
92 107 WVPResult<Object> result = new WVPResult<>();
93 108 if (app == null || stream == null) {
... ...
src/main/java/com/genersoft/iot/vmp/web/ApiControlController.java
... ... @@ -10,7 +10,7 @@ import org.springframework.beans.factory.annotation.Autowired;
10 10 import org.springframework.web.bind.annotation.*;
11 11  
12 12 /**
13   - * 兼容LiveGBS的API:设备控制
  13 + * API兼容:设备控制
14 14 */
15 15 @CrossOrigin
16 16 @RestController
... ...
src/main/java/com/genersoft/iot/vmp/web/ApiController.java
... ... @@ -11,7 +11,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
11 11 import org.springframework.web.bind.annotation.ResponseBody;
12 12  
13 13 /**
14   - * 兼容LiveGBS的API:系统接口
  14 + * API兼容:系统接口
15 15 */
16 16 @Controller
17 17 @CrossOrigin
... ...
src/main/java/com/genersoft/iot/vmp/web/ApiDeviceController.java
... ... @@ -14,7 +14,7 @@ import org.springframework.web.bind.annotation.*;
14 14 import java.util.List;
15 15  
16 16 /**
17   - * 兼容LiveGBS的API:设备信息
  17 + * API兼容:设备信息
18 18 */
19 19 @SuppressWarnings("unchecked")
20 20 @CrossOrigin
... ...
src/main/java/com/genersoft/iot/vmp/web/ApiStreamController.java
... ... @@ -17,7 +17,7 @@ import org.springframework.web.bind.annotation.*;
17 17 import org.springframework.web.context.request.async.DeferredResult;
18 18  
19 19 /**
20   - * 兼容LiveGBS的API:实时直播
  20 + * API兼容:实时直播
21 21 */
22 22 @SuppressWarnings(value = {"rawtypes", "unchecked"})
23 23 @CrossOrigin
... ...
src/main/resources/all-application.yml
... ... @@ -70,9 +70,13 @@ sip:
70 70 keepalive-timeout: 180
71 71 # [可选] 国标级联注册失败,再次发起注册的时间间隔。 默认60秒
72 72 register-time-interval: 60
  73 + # TODO [可选] 收到心跳后自动上线, 重启服务后会将所有设备置为离线,默认false,等待注册后上线。设置为true则收到心跳设置为上线。
  74 + # keepalliveToOnline: false
73 75  
74 76 #zlm 默认服务器配置
75 77 media:
  78 + # [可选] zlm服务器唯一id,用于触发hook时区别是哪台服务器,general.mediaServerId
  79 + id:
76 80 # [必须修改] zlm服务器的内网IP
77 81 ip: 192.168.0.100
78 82 # [可选] 返回流地址时的ip,置空使用 media.ip
... ...
src/main/resources/wvp.sqlite
No preview for this file type
web_src/src/components/CloudRecord.vue
... ... @@ -7,22 +7,23 @@
7 7 <el-main>
8 8 <div style="background-color: #FFFFFF; margin-bottom: 1rem; position: relative; padding: 0.5rem; text-align: left;">
9 9 <span style="font-size: 1rem; font-weight: bold;">云端录像</span>
10   - <div style="position: absolute; right: 1rem; top: 0.3rem;">
11   - <el-button v-if="!recordDetail" icon="el-icon-refresh-right" circle size="mini" :loading="loading" @click="getRecordList()"></el-button>
12   - <el-button v-if="recordDetail" icon="el-icon-arrow-left" circle size="mini" @click="backToList()"></el-button>
13   - </div>
14   - </div>
15   - <div v-if="!recordDetail">
16   - <div style="background-color: #FFFFFF; margin-bottom: 1rem; position: relative; padding: 0.5rem; text-align: left;font-size: 14px;">
  10 + <div style="position: absolute; right: 5rem; top: 0.3rem;">
17 11 节点选择: <el-select size="mini" @change="chooseMediaChange" style="width: 16rem; margin-right: 1rem;" v-model="mediaServer" placeholder="请选择" default-first-option>
18 12 <el-option
19 13 v-for="item in mediaServerList"
20   - :key="item.generalMediaServerId"
21   - :label="item.generalMediaServerId + '( ' + item.wanIp + ' )'"
  14 + :key="item.id"
  15 + :label="item.id + '( ' + item.streamIp + ' )'"
22 16 :value="item">
23 17 </el-option>
24 18 </el-select>
25 19 </div>
  20 + <div style="position: absolute; right: 1rem; top: 0.3rem;">
  21 + <el-button v-if="!recordDetail" icon="el-icon-refresh-right" circle size="mini" :loading="loading" @click="getRecordList()"></el-button>
  22 + <el-button v-if="recordDetail" icon="el-icon-arrow-left" circle size="mini" @click="backToList()"></el-button>
  23 + </div>
  24 + </div>
  25 + <div v-if="!recordDetail">
  26 +
26 27 <!--设备列表-->
27 28 <el-table :data="recordList" border style="width: 100%" :height="winHeight">
28 29 <el-table-column prop="app" label="应用名" align="center">
... ... @@ -60,6 +61,7 @@
60 61 <script>
61 62 import uiHeader from './UiHeader.vue'
62 63 import cloudRecordDetail from './CloudRecordDetail.vue'
  64 + import MediaServer from './service/MediaServer'
63 65 export default {
64 66 name: 'app',
65 67 components: {
... ... @@ -78,6 +80,7 @@
78 80 count:15,
79 81 total:0,
80 82 loading: false,
  83 + mediaServerObj : new MediaServer(),
81 84 recordDetail: false
82 85  
83 86 };
... ... @@ -107,20 +110,13 @@
107 110 },
108 111 getMediaServerList: function (){
109 112 let that = this;
110   - this.$axios({
111   - method: 'get',
112   - url:`/api/server/media_server/list`,
113   - }).then(function (res) {
114   - console.log(res)
115   - that.mediaServerList = res.data;
  113 + that.mediaServerObj.getMediaServerList((data)=>{
  114 + that.mediaServerList = data;
116 115 if (that.mediaServerList.length > 0) {
117 116 that.mediaServer = that.mediaServerList[0]
118 117 that.getRecordList();
119 118 }
120   -
121   - }).catch(function (error) {
122   - console.log(error);
123   - });
  119 + })
124 120 },
125 121 getRecordList: function (){
126 122 let that = this;
... ...
web_src/src/components/PushVideoList.vue
... ... @@ -17,6 +17,8 @@
17 17 </el-table-column>
18 18 <el-table-column prop="gbId" label="国标编码" width="150" align="center">
19 19 </el-table-column>
  20 + <el-table-column prop="mediaServerId" label="流媒体" width="150" align="center">
  21 + </el-table-column>
20 22 <el-table-column label="开始时间" align="center" >
21 23 <template slot-scope="scope">
22 24 <el-button-group>
... ... @@ -29,7 +31,7 @@
29 31 {{(scope.row.status == false && scope.row.gbId == null) || scope.row.status ?'是':'否'}}
30 32 </template>
31 33 </el-table-column>
32   -
  34 +
33 35 <el-table-column label="操作" width="360" align="center" fixed="right">
34 36 <template slot-scope="scope">
35 37 <el-button-group>
... ... @@ -125,7 +127,7 @@
125 127 that.getDeviceListLoading = false;
126 128 });
127 129 },
128   -
  130 +
129 131 playPuhsh: function(row){
130 132 let that = this;
131 133 this.getListLoading = true;
... ... @@ -134,7 +136,8 @@
134 136 url:`/api/media/stream_info_by_app_and_stream`,
135 137 params: {
136 138 app: row.app,
137   - stream: row.stream
  139 + stream: row.stream,
  140 + mediaServerId: row.mediaServerId
138 141 }
139 142 }).then(function (res) {
140 143 that.getListLoading = false;
... ...
web_src/src/components/StreamProxyList.vue
... ... @@ -32,6 +32,15 @@
32 32 </div>
33 33 </template>
34 34 </el-table-column>
  35 + <el-table-column prop="mediaServerId" label="流媒体" width="150" align="center"></el-table-column>
  36 + <el-table-column label="类型" width="100" align="center">
  37 + <template slot-scope="scope">
  38 + <div slot="reference" class="name-wrapper">
  39 + <el-tag size="medium">{{scope.row.type}}</el-tag>
  40 + </div>
  41 + </template>
  42 + </el-table-column>
  43 +
35 44 <el-table-column prop="gbId" label="国标编码" width="180" align="center" show-overflow-tooltip/>
36 45 <el-table-column label="启用" width="120" align="center">
37 46 <template slot-scope="scope">
... ... @@ -147,8 +156,6 @@
147 156 count: that.count
148 157 }
149 158 }).then(function (res) {
150   - console.log(res);
151   - console.log(res.data.list);
152 159 that.total = res.data.total;
153 160 that.streamProxyList = res.data.list;
154 161 that.getListLoading = false;
... ... @@ -170,7 +177,6 @@
170 177 this.getListLoading = false;
171 178 if (res.data.code == 0 ){
172 179 if (res.data.data.length > 0) {
173   - console.log(res.data.data)
174 180 this.$refs.onvifEdit.openDialog(res.data.data, (url)=>{
175 181 if (url != null) {
176 182 this.$refs.onvifEdit.close();
... ... @@ -200,7 +206,8 @@
200 206 url:`/api/media/stream_info_by_app_and_stream`,
201 207 params: {
202 208 app: row.app,
203   - stream: row.stream
  209 + stream: row.stream,
  210 + mediaServerId: row.mediaServerId
204 211 }
205 212 }).then(function (res) {
206 213 that.getListLoading = false;
... ...
web_src/src/components/control.vue
... ... @@ -7,6 +7,17 @@
7 7 <el-main>
8 8 <div style="background-color: #FFFFFF; margin-bottom: 1rem; position: relative; padding: 0.5rem; text-align: left;">
9 9 <span style="font-size: 1rem; font-weight: bold;">控制台</span>
  10 + <div style="position: absolute; right: 17rem; top: 0.3rem;">
  11 + 节点选择: <el-select size="mini" @change="chooseMediaChange" style="width: 16rem; margin-right: 1rem;" v-model="mediaServerChoose" placeholder="请选择" default-first-option>
  12 + <el-option
  13 + v-for="item in mediaServerList"
  14 + :key="item.id"
  15 + :label="item.id + '( ' + item.streamIp + ' )'"
  16 + :value="item.id">
  17 + </el-option>
  18 + </el-select>
  19 + <span >{{loadCount}}</span>
  20 + </div>
10 21 <div style="position: absolute; right: 1rem; top: 0.3rem;">
11 22 <el-popover placement="bottom" width="750" height="300" trigger="click">
12 23 <div style="height: 600px;overflow:auto;">
... ... @@ -53,6 +64,7 @@
53 64  
54 65 <script>
55 66 import uiHeader from './UiHeader.vue'
  67 +import MediaServer from './service/MediaServer'
56 68  
57 69 import echarts from 'echarts';
58 70 export default {
... ... @@ -87,68 +99,101 @@ export default {
87 99 chartInterval: 0, //更新图表统计图定时任务标识
88 100 allSessionData: [],
89 101 visible: false,
90   - serverConfig: {}
  102 + serverConfig: {},
  103 + mediaServer : new MediaServer(),
  104 + mediaServerChoose : null,
  105 + loadCount : 0,
  106 + mediaServerList : []
91 107 };
92 108 },
93 109 mounted() {
94   - this.getAllSession();
  110 +
95 111 this.initTable();
96 112 this.updateData();
97 113 this.chartInterval = setInterval(this.updateData, 3000);
  114 + this.mediaServer.getMediaServerList((data)=>{
  115 + this.mediaServerList = data.data;
  116 + if (this.mediaServerList && this.mediaServerList.length > 0) {
  117 + this.mediaServerChoose = this.mediaServerList[0].id
  118 + this.loadCount = this.mediaServerList[0].count;
  119 + this.getThreadsLoad();
  120 + this.getAllSession();
  121 + }
  122 + })
98 123 },
99 124 destroyed() {
100 125 clearInterval(this.chartInterval); //释放定时任务
101 126 },
102 127 methods: {
  128 + chooseMediaChange: function (val) {
  129 + this.loadCount = 0
  130 + this.initTable()
  131 + this.updateData();
  132 + },
103 133 updateData: function () {
104 134 this.getThreadsLoad();
  135 + this.getLoadCount();
  136 + this.getAllSession();
105 137 },
106 138 /**
107 139 * 获取线程状态
108 140 */
109 141 getThreadsLoad: function () {
110 142 let that = this;
111   - this.$axios({
  143 + if (that.mediaServerChoose != null) {
  144 + this.$axios({
112 145 method: 'get',
113   - url: '/zlm/index/api/getThreadsLoad'
114   - }).then(function (res) {
  146 + url: '/zlm/' + that.mediaServerChoose +'/index/api/getThreadsLoad'
  147 + }).then(function (res) {
115 148 if (res.data.code == 0) {
116   - that.tableOption.xAxis.data.push(new Date().toLocaleTimeString('chinese', {
117   - hour12: false
118   - }));
119   - that.table1Option.xAxis.data.push(new Date().toLocaleTimeString('chinese', {
120   - hour12: false
121   - }));
  149 + that.tableOption.xAxis.data.push(new Date().toLocaleTimeString('chinese', {
  150 + hour12: false
  151 + }));
  152 + that.table1Option.xAxis.data.push(new Date().toLocaleTimeString('chinese', {
  153 + hour12: false
  154 + }));
122 155  
123   - for (var i = 0; i < res.data.data.length; i++) {
124   - if (that.tableOption.series[i] === undefined) {
125   - let data = {
126   - data: [],
127   - type: 'line'
128   - };
129   - let data1 = {
130   - data: [],
131   - type: 'line'
132   - };
133   - data.data.push(res.data.data[i].delay);
134   - data1.data.push(res.data.data[i].load);
135   - that.tableOption.series.push(data);
136   - that.table1Option.series.push(data1);
137   - } else {
138   - that.tableOption.series[i].data.push(res.data.data[i].delay);
139   - that.table1Option.series[i].data.push(res.data.data[i].load);
140   - }
  156 + for (var i = 0; i < res.data.data.length; i++) {
  157 + if (that.tableOption.series[i] === undefined) {
  158 + let data = {
  159 + data: [],
  160 + type: 'line'
  161 + };
  162 + let data1 = {
  163 + data: [],
  164 + type: 'line'
  165 + };
  166 + data.data.push(res.data.data[i].delay);
  167 + data1.data.push(res.data.data[i].load);
  168 + that.tableOption.series.push(data);
  169 + that.table1Option.series.push(data1);
  170 + } else {
  171 + that.tableOption.series[i].data.push(res.data.data[i].delay);
  172 + that.table1Option.series[i].data.push(res.data.data[i].load);
141 173 }
142   - that.tableOption.dataZoom[0].start = that.charZoomStart;
143   - that.tableOption.dataZoom[0].end = that.charZoomEnd;
144   - that.table1Option.dataZoom[0].start = that.charZoomStart;
145   - that.table1Option.dataZoom[0].end = that.charZoomEnd;
146   - //that.myChart = echarts.init(document.getElementById('ThreadsLoad'));
147   - that.myChart.setOption(that.tableOption, true);
148   - // that.myChart1 = echarts.init(document.getElementById('WorkThreadsLoad'));
149   - that.myChart1.setOption(that.table1Option, true);
  174 + }
  175 + that.tableOption.dataZoom[0].start = that.charZoomStart;
  176 + that.tableOption.dataZoom[0].end = that.charZoomEnd;
  177 + that.table1Option.dataZoom[0].start = that.charZoomStart;
  178 + that.table1Option.dataZoom[0].end = that.charZoomEnd;
  179 + //that.myChart = echarts.init(document.getElementById('ThreadsLoad'));
  180 + that.myChart.setOption(that.tableOption, true);
  181 + // that.myChart1 = echarts.init(document.getElementById('WorkThreadsLoad'));
  182 + that.myChart1.setOption(that.table1Option, true);
150 183 }
151   - });
  184 + });
  185 + }
  186 +
  187 + },
  188 + getLoadCount: function (){
  189 + let that = this;
  190 + if (that.mediaServerChoose != null) {
  191 + that.mediaServer.getMediaServer(that.mediaServerChoose, (data)=>{
  192 + if (data.code == 0) {
  193 + that.loadCount = data.data.count
  194 + }
  195 + })
  196 + }
152 197 },
153 198 initTable: function () {
154 199 let that = this;
... ... @@ -242,10 +287,9 @@ export default {
242 287 getAllSession: function () {
243 288 let that = this;
244 289 that.allSessionData = [];
245   - console.log("地址:" + '/zlm/index/api/getAllSession');
246 290 this.$axios({
247 291 method: 'get',
248   - url: '/zlm/index/api/getAllSession'
  292 + url: '/zlm/' + that.mediaServerChoose +'/index/api/getAllSession'
249 293 }).then(function (res) {
250 294 res.data.data.forEach(item => {
251 295 let data = {
... ...
web_src/src/components/dialog/StreamProxyEdit.vue
... ... @@ -39,6 +39,22 @@
39 39 <el-form-item label="超时时间:毫秒" prop="timeout_ms" v-if="proxyParam.type=='ffmpeg'">
40 40 <el-input v-model="proxyParam.timeout_ms" clearable></el-input>
41 41 </el-form-item>
  42 + <el-form-item label="节点选择" prop="rtp_type">
  43 + <el-select
  44 + v-model="proxyParam.mediaServerId"
  45 + @change="mediaServerIdChange"
  46 + style="width: 100%"
  47 + placeholder="请选择拉流节点"
  48 + >
  49 + <el-option label="自动选择" value="auto"></el-option>
  50 + <el-option
  51 + v-for="item in mediaServerList"
  52 + :key="item.id"
  53 + :label="item.id"
  54 + :value="item.id">
  55 + </el-option>
  56 + </el-select>
  57 + </el-form-item>
42 58 <el-form-item label="FFmpeg命令模板" prop="ffmpeg_cmd_key" v-if="proxyParam.type=='ffmpeg'">
43 59 <!-- <el-input v-model="proxyParam.ffmpeg_cmd_key" clearable></el-input>-->
44 60 <el-select
... ... @@ -68,6 +84,7 @@
68 84 <el-option label="组播" value="2"></el-option>
69 85 </el-select>
70 86 </el-form-item>
  87 +
71 88 <el-form-item label="国标平台">
72 89 <el-select
73 90 v-model="proxyParam.platformGbId"
... ... @@ -106,6 +123,8 @@
106 123 </template>
107 124  
108 125 <script>
  126 +import MediaServer from './../service/MediaServer'
  127 +
109 128 export default {
110 129 name: "streamProxyEdit",
111 130 props: {},
... ... @@ -134,27 +153,8 @@ export default {
134 153 isLoging: false,
135 154 dialogLoading: false,
136 155 onSubmit_text: "立即创建",
137   - platformList: [{
138   - id: 1,
139   - enable: true,
140   - name: "141",
141   - serverGBId: "34020000002000000001",
142   - serverGBDomain: "3402000000",
143   - serverIP: "192.168.1.141",
144   - serverPort: 15060,
145   - deviceGBId: "34020000002000000001",
146   - deviceIp: "192.168.1.20",
147   - devicePort: "5060",
148   - username: "34020000002000000001",
149   - password: "12345678",
150   - expires: "300",
151   - keepTimeout: "60",
152   - transport: "UDP",
153   - characterSet: "GB2312",
154   - ptz: false,
155   - rtcp: false,
156   - status: true,
157   - }],
  156 + platformList: [],
  157 + mediaServer: new MediaServer(),
158 158 proxyParam: {
159 159 name: null,
160 160 type: "default",
... ... @@ -170,7 +170,9 @@ export default {
170 170 enable_hls: true,
171 171 enable_mp4: false,
172 172 platformGbId: null,
  173 + mediaServerId: "auto",
173 174 },
  175 + mediaServerList:{},
174 176 ffmpegCmdList:{},
175 177  
176 178 rules: {
... ... @@ -193,7 +195,6 @@ export default {
193 195 }
194 196  
195 197 let that = this;
196   -
197 198 this.$axios({
198 199 method: 'get',
199 200 url:`/api/platform/query/10000/0`
... ... @@ -202,17 +203,28 @@ export default {
202 203 }).catch(function (error) {
203 204 console.log(error);
204 205 });
205   - this.$axios({
206   - method: 'get',
207   - url:`/api/proxy/ffmpeg_cmd/list`
208   - }).then(function (res) {
209   - that.ffmpegCmdList = res.data.data;
210   - }).catch(function (error) {
211   - console.log(error);
212   - });
  206 + this.mediaServer.getMediaServerList((data)=>{
  207 + this.mediaServerList = data;
  208 + })
  209 + },
  210 + mediaServerIdChange:function (){
  211 + let that = this;
  212 + if (that.proxyParam.mediaServerId !== "auto"){
  213 + that.$axios({
  214 + method: 'get',
  215 + url:`/api/proxy/ffmpeg_cmd/list`,
  216 + params: {
  217 + mediaServerId: that.proxyParam.mediaServerId
  218 + }
  219 + }).then(function (res) {
  220 + that.ffmpegCmdList = res.data.data;
  221 + }).catch(function (error) {
  222 + console.log(error);
  223 + });
  224 + }
  225 +
213 226 },
214 227 onSubmit: function () {
215   - console.log("onSubmit");
216 228 this.dialogLoading = true;
217 229 var that = this;
218 230 that.$axios({
... ... @@ -239,7 +251,6 @@ export default {
239 251 });
240 252 },
241 253 close: function () {
242   - console.log("关闭添加视频平台");
243 254 this.showDialog = false;
244 255 this.dialogLoading = false;
245 256 this.$refs.streamProxy.resetFields();
... ...
web_src/src/components/dialog/devicePlayer.vue
... ... @@ -181,6 +181,7 @@ export default {
181 181 showVideoDialog: false,
182 182 streamId: '',
183 183 app : '',
  184 + mediaServerId : '',
184 185 convertKey: '',
185 186 deviceId: '',
186 187 channelId: '',
... ... @@ -218,7 +219,7 @@ export default {
218 219 if (tab.name == "codec") {
219 220 this.$axios({
220 221 method: 'get',
221   - url: '/zlm/index/api/getMediaInfo?vhost=__defaultVhost__&schema=rtmp&app='+ this.app +'&stream='+ this.streamId
  222 + url: '/zlm/' +this.mediaServerId+ '/index/api/getMediaInfo?vhost=__defaultVhost__&schema=rtmp&app='+ this.app +'&stream='+ this.streamId
222 223 }).then(function (res) {
223 224 that.tracksLoading = false;
224 225 if (res.data.code == 0 && res.data.online) {
... ... @@ -235,12 +236,11 @@ export default {
235 236 }
236 237 },
237 238 openDialog: function (tab, deviceId, channelId, param) {
238   - console.log("openDialog")
239   - console.log(param)
240 239 this.tabActiveName = tab;
241 240 this.channelId = channelId;
242 241 this.deviceId = deviceId;
243 242 this.streamId = "";
  243 + this.mediaServerId = "";
244 244 this.app = "";
245 245 this.videoUrl = ""
246 246 if (!!this.$refs.videoPlayer) {
... ... @@ -257,8 +257,8 @@ export default {
257 257 break;
258 258 case "streamPlay":
259 259 this.tabActiveName = "media";
260   - this.showRrecord = false,
261   - this.showPtz = false,
  260 + this.showRrecord = false;
  261 + this.showPtz = false;
262 262 this.play(param.streamInfo, param.hasAudio)
263 263 break;
264 264 case "control":
... ... @@ -269,19 +269,17 @@ export default {
269 269 console.log(val)
270 270 },
271 271 play: function (streamInfo, hasAudio) {
272   -
273 272 this.hasAudio = hasAudio;
274 273 this.isLoging = false;
275 274 // this.videoUrl = streamInfo.rtc;
276 275 this.videoUrl = this.getUrlByStreamInfo(streamInfo);
277 276 this.streamId = streamInfo.streamId;
278 277 this.app = streamInfo.app;
  278 + this.mediaServerId = streamInfo.mediaServerId;
279 279 this.playFromStreamInfo(false, streamInfo)
280 280 },
281 281 getUrlByStreamInfo(streamInfo){
282 282 let baseZlmApi = process.env.NODE_ENV === 'development'?`${location.host}/debug/zlm`:`${location.host}/zlm`
283   - console.log(12121212)
284   - console.log(baseZlmApi)
285 283 // return `${baseZlmApi}/${streamInfo.app}/${streamInfo.streamId}.flv`;
286 284 // return `http://${baseZlmApi}/${streamInfo.app}/${streamInfo.streamId}.flv`;
287 285 return streamInfo.ws_flv;
... ... @@ -430,6 +428,7 @@ export default {
430 428 var streamInfo = res.data;
431 429 that.app = streamInfo.app;
432 430 that.streamId = streamInfo.streamId;
  431 + that.mediaServerId = streamInfo.mediaServerId;
433 432 that.videoUrl = that.getUrlByStreamInfo(streamInfo);
434 433 that.recordPlay = true;
435 434 });
... ...
web_src/src/components/service/MediaServer.js 0 → 100644
  1 +import axios from 'axios';
  2 +
  3 +class MediaServer{
  4 +
  5 + constructor() {
  6 + this.$axios = axios;
  7 + }
  8 +
  9 + getMediaServerList(callback){
  10 + this.$axios({
  11 + method: 'get',
  12 + url:`/api/server/media_server/list`,
  13 + }).then(function (res) {
  14 + if (typeof (callback) == "function") callback(res.data)
  15 + }).catch(function (error) {
  16 + console.log(error);
  17 + });
  18 + }
  19 +
  20 + getMediaServer(id, callback){
  21 + this.$axios({
  22 + method: 'get',
  23 + url:`/api/server/media_server/one/` + id,
  24 + }).then(function (res) {
  25 + if (typeof (callback) == "function") callback(res.data)
  26 + }).catch(function (error) {
  27 + console.log(error);
  28 + });
  29 + }
  30 +}
  31 +
  32 +export default MediaServer;
... ...