Commit 89a9ab4534f10a224f70e546db838423e84a1965
1 parent
06d78575
添加zlm集群支持
Showing
75 changed files
with
2415 additions
and
898 deletions
pom.xml
| ... | ... | @@ -196,6 +196,16 @@ |
| 196 | 196 | <version>1.12</version> |
| 197 | 197 | </dependency> |
| 198 | 198 | |
| 199 | +<!-- <!– 检测文件编码 –>--> | |
| 200 | +<!-- <!– https://mvnrepository.com/artifact/cpdetector/cpdetector –>--> | |
| 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<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<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<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<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
src/main/java/com/genersoft/iot/vmp/web/ApiController.java
src/main/java/com/genersoft/iot/vmp/web/ApiDeviceController.java
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; | ... | ... |