Commit 688e222dcccb809cf314e175db944ad25cb9bc1e

Authored by 648540858
1 parent 470be2dc

优化按需拉流配置,拉流代理支持按需拉流

sql/mysql.sql
@@ -277,7 +277,6 @@ CREATE TABLE `media_server` ( @@ -277,7 +277,6 @@ CREATE TABLE `media_server` (
277 `rtspSSLPort` int NOT NULL, 277 `rtspSSLPort` int NOT NULL,
278 `autoConfig` int NOT NULL, 278 `autoConfig` int NOT NULL,
279 `secret` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, 279 `secret` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
280 - `streamNoneReaderDelayMS` int NOT NULL,  
281 `rtpEnable` int NOT NULL, 280 `rtpEnable` int NOT NULL,
282 `rtpPortRange` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, 281 `rtpPortRange` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
283 `sendRtpPortRange` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, 282 `sendRtpPortRange` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
sql/update.sql
  1 +alter table wvp.media_server
  2 + drop column streamNoneReaderDelayMS;
  3 +
  4 +alter table stream_proxy
  5 + add enable_disable_none_reader bit(1) default null;
src/main/java/com/genersoft/iot/vmp/conf/MediaConfig.java
@@ -69,9 +69,6 @@ public class MediaConfig{ @@ -69,9 +69,6 @@ public class MediaConfig{
69 @Value("${media.secret}") 69 @Value("${media.secret}")
70 private String secret; 70 private String secret;
71 71
72 - @Value("${media.stream-none-reader-delay-ms:15000}")  
73 - private int streamNoneReaderDelayMS = 15000;  
74 -  
75 @Value("${media.rtp.enable}") 72 @Value("${media.rtp.enable}")
76 private boolean rtpEnable; 73 private boolean rtpEnable;
77 74
@@ -151,10 +148,6 @@ public class MediaConfig{ @@ -151,10 +148,6 @@ public class MediaConfig{
151 return secret; 148 return secret;
152 } 149 }
153 150
154 - public int getStreamNoneReaderDelayMS() {  
155 - return streamNoneReaderDelayMS;  
156 - }  
157 -  
158 public boolean isRtpEnable() { 151 public boolean isRtpEnable() {
159 return rtpEnable; 152 return rtpEnable;
160 } 153 }
@@ -219,7 +212,6 @@ public class MediaConfig{ @@ -219,7 +212,6 @@ public class MediaConfig{
219 mediaServerItem.setRtspSSLPort(rtspSSLPort); 212 mediaServerItem.setRtspSSLPort(rtspSSLPort);
220 mediaServerItem.setAutoConfig(autoConfig); 213 mediaServerItem.setAutoConfig(autoConfig);
221 mediaServerItem.setSecret(secret); 214 mediaServerItem.setSecret(secret);
222 - mediaServerItem.setStreamNoneReaderDelayMS(streamNoneReaderDelayMS);  
223 mediaServerItem.setRtpEnable(rtpEnable); 215 mediaServerItem.setRtpEnable(rtpEnable);
224 mediaServerItem.setRtpPortRange(rtpPortRange); 216 mediaServerItem.setRtpPortRange(rtpPortRange);
225 mediaServerItem.setSendRtpPortRange(sendRtpPortRange); 217 mediaServerItem.setSendRtpPortRange(sendRtpPortRange);
src/main/java/com/genersoft/iot/vmp/conf/UserSetting.java
@@ -33,6 +33,8 @@ public class UserSetting { @@ -33,6 +33,8 @@ public class UserSetting {
33 33
34 private Boolean usePushingAsStatus = Boolean.TRUE; 34 private Boolean usePushingAsStatus = Boolean.TRUE;
35 35
  36 + private Boolean streamOnDemand = Boolean.TRUE;
  37 +
36 private String serverId = "000000"; 38 private String serverId = "000000";
37 39
38 private String thirdPartyGBIdReg = "[\\s\\S]*"; 40 private String thirdPartyGBIdReg = "[\\s\\S]*";
@@ -146,4 +148,12 @@ public class UserSetting { @@ -146,4 +148,12 @@ public class UserSetting {
146 public void setUsePushingAsStatus(Boolean usePushingAsStatus) { 148 public void setUsePushingAsStatus(Boolean usePushingAsStatus) {
147 this.usePushingAsStatus = usePushingAsStatus; 149 this.usePushingAsStatus = usePushingAsStatus;
148 } 150 }
  151 +
  152 + public Boolean getStreamOnDemand() {
  153 + return streamOnDemand;
  154 + }
  155 +
  156 + public void setStreamOnDemand(Boolean streamOnDemand) {
  157 + this.streamOnDemand = streamOnDemand;
  158 + }
149 } 159 }
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java
@@ -558,9 +558,12 @@ public class ZLMHttpHookListener { @@ -558,9 +558,12 @@ public class ZLMHttpHookListener {
558 String app = json.getString("app"); 558 String app = json.getString("app");
559 JSONObject ret = new JSONObject(); 559 JSONObject ret = new JSONObject();
560 ret.put("code", 0); 560 ret.put("code", 0);
  561 + // 录像下载
  562 + ret.put("close", userSetting.getStreamOnDemand());
561 if ("rtp".equals(app)){ 563 if ("rtp".equals(app)){
562 - ret.put("close", true); 564 + // 国标流, 点播/录像回放/录像下载
563 StreamInfo streamInfoForPlayCatch = redisCatchStorage.queryPlayByStreamId(streamId); 565 StreamInfo streamInfoForPlayCatch = redisCatchStorage.queryPlayByStreamId(streamId);
  566 + // 点播
564 if (streamInfoForPlayCatch != null) { 567 if (streamInfoForPlayCatch != null) {
565 // 收到无人观看说明流也没有在往上级推送 568 // 收到无人观看说明流也没有在往上级推送
566 if (redisCatchStorage.isChannelSendingRTP(streamInfoForPlayCatch.getChannelId())) { 569 if (redisCatchStorage.isChannelSendingRTP(streamInfoForPlayCatch.getChannelId())) {
@@ -590,40 +593,39 @@ public class ZLMHttpHookListener { @@ -590,40 +593,39 @@ public class ZLMHttpHookListener {
590 593
591 redisCatchStorage.stopPlay(streamInfoForPlayCatch); 594 redisCatchStorage.stopPlay(streamInfoForPlayCatch);
592 storager.stopPlay(streamInfoForPlayCatch.getDeviceID(), streamInfoForPlayCatch.getChannelId()); 595 storager.stopPlay(streamInfoForPlayCatch.getDeviceID(), streamInfoForPlayCatch.getChannelId());
593 - }else{  
594 - StreamInfo streamInfoForPlayBackCatch = redisCatchStorage.queryPlayback(null, null, streamId, null);  
595 - if (streamInfoForPlayBackCatch != null ) {  
596 - if (streamInfoForPlayBackCatch.isPause()) {  
597 - ret.put("close", false);  
598 - }else {  
599 - Device device = deviceService.queryDevice(streamInfoForPlayBackCatch.getDeviceID());  
600 - if (device != null) {  
601 - try {  
602 - cmder.streamByeCmd(device,streamInfoForPlayBackCatch.getChannelId(),  
603 - streamInfoForPlayBackCatch.getStream(), null);  
604 - } catch (InvalidArgumentException | ParseException | SipException |  
605 - SsrcTransactionNotFoundException e) {  
606 - logger.error("[无人观看]回放, 发送BYE失败 {}", e.getMessage());  
607 - }  
608 - }  
609 - redisCatchStorage.stopPlayback(streamInfoForPlayBackCatch.getDeviceID(),  
610 - streamInfoForPlayBackCatch.getChannelId(), streamInfoForPlayBackCatch.getStream(), null);  
611 - }  
612 - 596 + return ret;
  597 + }
  598 + // 录像回放
  599 + StreamInfo streamInfoForPlayBackCatch = redisCatchStorage.queryPlayback(null, null, streamId, null);
  600 + if (streamInfoForPlayBackCatch != null ) {
  601 + if (streamInfoForPlayBackCatch.isPause()) {
  602 + ret.put("close", false);
613 }else { 603 }else {
614 - StreamInfo streamInfoForDownload = redisCatchStorage.queryDownload(null, null, streamId, null);  
615 - // 进行录像下载时无人观看不断流  
616 - if (streamInfoForDownload != null) {  
617 - ret.put("close", false); 604 + Device device = deviceService.queryDevice(streamInfoForPlayBackCatch.getDeviceID());
  605 + if (device != null) {
  606 + try {
  607 + cmder.streamByeCmd(device,streamInfoForPlayBackCatch.getChannelId(),
  608 + streamInfoForPlayBackCatch.getStream(), null);
  609 + } catch (InvalidArgumentException | ParseException | SipException |
  610 + SsrcTransactionNotFoundException e) {
  611 + logger.error("[无人观看]回放, 发送BYE失败 {}", e.getMessage());
  612 + }
618 } 613 }
  614 + redisCatchStorage.stopPlayback(streamInfoForPlayBackCatch.getDeviceID(),
  615 + streamInfoForPlayBackCatch.getChannelId(), streamInfoForPlayBackCatch.getStream(), null);
619 } 616 }
  617 + return ret;
620 } 618 }
621 - MediaServerItem mediaServerItem = mediaServerService.getOne(mediaServerId);  
622 - if (mediaServerItem != null && mediaServerItem.getStreamNoneReaderDelayMS() == -1) { 619 + // 录像下载
  620 + StreamInfo streamInfoForDownload = redisCatchStorage.queryDownload(null, null, streamId, null);
  621 + // 进行录像下载时无人观看不断流
  622 + if (streamInfoForDownload != null) {
623 ret.put("close", false); 623 ret.put("close", false);
  624 + return ret;
624 } 625 }
625 - return ret;  
626 }else { 626 }else {
  627 + // 非国标流 推流/拉流代理
  628 + // 拉流代理
627 StreamProxyItem streamProxyItem = streamProxyService.getStreamProxyByAppAndStream(app, streamId); 629 StreamProxyItem streamProxyItem = streamProxyService.getStreamProxyByAppAndStream(app, streamId);
628 if (streamProxyItem != null ) { 630 if (streamProxyItem != null ) {
629 if (streamProxyItem.isEnable_remove_none_reader()) { 631 if (streamProxyItem.isEnable_remove_none_reader()) {
@@ -635,12 +637,21 @@ public class ZLMHttpHookListener { @@ -635,12 +637,21 @@ public class ZLMHttpHookListener {
635 }else if (streamProxyItem.isEnable_disable_none_reader()) { 637 }else if (streamProxyItem.isEnable_disable_none_reader()) {
636 // 无人观看停用 638 // 无人观看停用
637 ret.put("close", true); 639 ret.put("close", true);
  640 + // 修改数据
  641 + streamProxyService.stop(app, streamId);
638 }else { 642 }else {
639 ret.put("close", false); 643 ret.put("close", false);
640 } 644 }
  645 + return ret;
641 } 646 }
642 - return ret; 647 + // 推流具有主动性,暂时不做处理
  648 +// StreamPushItem streamPushItem = streamPushService.getPush(app, streamId);
  649 +// if (streamPushItem != null) {
  650 +// // TODO 发送停止
  651 +//
  652 +// }
643 } 653 }
  654 + return ret;
644 } 655 }
645 656
646 /** 657 /**
@@ -655,19 +666,27 @@ public class ZLMHttpHookListener { @@ -655,19 +666,27 @@ public class ZLMHttpHookListener {
655 } 666 }
656 String mediaServerId = json.getString("mediaServerId"); 667 String mediaServerId = json.getString("mediaServerId");
657 MediaServerItem mediaInfo = mediaServerService.getOne(mediaServerId); 668 MediaServerItem mediaInfo = mediaServerService.getOne(mediaServerId);
658 - if (userSetting.isAutoApplyPlay() && mediaInfo != null && mediaInfo.isRtpEnable()) { 669 + if (userSetting.isAutoApplyPlay() && mediaInfo != null) {
659 String app = json.getString("app"); 670 String app = json.getString("app");
660 String streamId = json.getString("stream"); 671 String streamId = json.getString("stream");
661 if ("rtp".equals(app)) { 672 if ("rtp".equals(app)) {
662 - String[] s = streamId.split("_");  
663 - if (s.length == 2) {  
664 - String deviceId = s[0];  
665 - String channelId = s[1];  
666 - Device device = redisCatchStorage.getDevice(deviceId);  
667 - if (device != null) {  
668 - playService.play(mediaInfo,deviceId, channelId, null, null, null); 673 + if (mediaInfo.isRtpEnable()) {
  674 + String[] s = streamId.split("_");
  675 + if (s.length == 2) {
  676 + String deviceId = s[0];
  677 + String channelId = s[1];
  678 + Device device = redisCatchStorage.getDevice(deviceId);
  679 + if (device != null) {
  680 + playService.play(mediaInfo,deviceId, channelId, null, null, null);
  681 + }
669 } 682 }
670 } 683 }
  684 + }else {
  685 + // 拉流代理
  686 + StreamProxyItem streamProxyByAppAndStream = streamProxyService.getStreamProxyByAppAndStream(app, streamId);
  687 + if (streamProxyByAppAndStream != null && streamProxyByAppAndStream.isEnable_disable_none_reader()) {
  688 + streamProxyService.start(app, streamId);
  689 + }
671 } 690 }
672 } 691 }
673 692
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/MediaServerItem.java
@@ -54,9 +54,6 @@ public class MediaServerItem{ @@ -54,9 +54,6 @@ public class MediaServerItem{
54 @Schema(description = "ZLM鉴权参数") 54 @Schema(description = "ZLM鉴权参数")
55 private String secret; 55 private String secret;
56 56
57 - @Schema(description = "某个流无人观看时,触发hook.on_stream_none_reader事件的最大等待时间,单位毫秒")  
58 - private int streamNoneReaderDelayMS;  
59 -  
60 @Schema(description = "keepalive hook触发间隔,单位秒") 57 @Schema(description = "keepalive hook触发间隔,单位秒")
61 private int hookAliveInterval; 58 private int hookAliveInterval;
62 59
@@ -119,7 +116,6 @@ public class MediaServerItem{ @@ -119,7 +116,6 @@ public class MediaServerItem{
119 rtspSSLPort = zlmServerConfig.getRtspSSlport(); 116 rtspSSLPort = zlmServerConfig.getRtspSSlport();
120 autoConfig = true; // 默认值true; 117 autoConfig = true; // 默认值true;
121 secret = zlmServerConfig.getApiSecret(); 118 secret = zlmServerConfig.getApiSecret();
122 - streamNoneReaderDelayMS = zlmServerConfig.getGeneralStreamNoneReaderDelayMS();  
123 hookAliveInterval = zlmServerConfig.getHookAliveInterval(); 119 hookAliveInterval = zlmServerConfig.getHookAliveInterval();
124 rtpEnable = false; // 默认使用单端口;直到用户自己设置开启多端口 120 rtpEnable = false; // 默认使用单端口;直到用户自己设置开启多端口
125 rtpPortRange = zlmServerConfig.getPortRange().replace("_",","); // 默认使用30000,30500作为级联时发送流的端口号 121 rtpPortRange = zlmServerConfig.getPortRange().replace("_",","); // 默认使用30000,30500作为级联时发送流的端口号
@@ -240,14 +236,6 @@ public class MediaServerItem{ @@ -240,14 +236,6 @@ public class MediaServerItem{
240 this.secret = secret; 236 this.secret = secret;
241 } 237 }
242 238
243 - public int getStreamNoneReaderDelayMS() {  
244 - return streamNoneReaderDelayMS;  
245 - }  
246 -  
247 - public void setStreamNoneReaderDelayMS(int streamNoneReaderDelayMS) {  
248 - this.streamNoneReaderDelayMS = streamNoneReaderDelayMS;  
249 - }  
250 -  
251 public boolean isRtpEnable() { 239 public boolean isRtpEnable() {
252 return rtpEnable; 240 return rtpEnable;
253 } 241 }
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/StreamProxyItem.java
@@ -38,7 +38,7 @@ public class StreamProxyItem extends GbStream { @@ -38,7 +38,7 @@ public class StreamProxyItem extends GbStream {
38 @Schema(description = "是否 无人观看时删除") 38 @Schema(description = "是否 无人观看时删除")
39 private boolean enable_remove_none_reader; 39 private boolean enable_remove_none_reader;
40 40
41 - @Schema(description = "是否 无人观看时不启用") 41 + @Schema(description = "是否 无人观看时自动停用")
42 private boolean enable_disable_none_reader; 42 private boolean enable_disable_none_reader;
43 @Schema(description = "上级平台国标ID") 43 @Schema(description = "上级平台国标ID")
44 private String platformGbId; 44 private String platformGbId;
src/main/java/com/genersoft/iot/vmp/service/impl/MediaServerServiceImpl.java
@@ -541,7 +541,6 @@ public class MediaServerServiceImpl implements IMediaServerService { @@ -541,7 +541,6 @@ public class MediaServerServiceImpl implements IMediaServerService {
541 param.put("hook.on_record_mp4",""); 541 param.put("hook.on_record_mp4","");
542 } 542 }
543 param.put("hook.timeoutSec","20"); 543 param.put("hook.timeoutSec","20");
544 - param.put("general.streamNoneReaderDelayMS",mediaServerItem.getStreamNoneReaderDelayMS()==-1?"3600000":mediaServerItem.getStreamNoneReaderDelayMS() );  
545 // 推流断开后可以在超时时间内重新连接上继续推流,这样播放器会接着播放。 544 // 推流断开后可以在超时时间内重新连接上继续推流,这样播放器会接着播放。
546 // 置0关闭此特性(推流断开会导致立即断开播放器) 545 // 置0关闭此特性(推流断开会导致立即断开播放器)
547 // 此参数不应大于播放器超时时间 546 // 此参数不应大于播放器超时时间
@@ -606,7 +605,6 @@ public class MediaServerServiceImpl implements IMediaServerService { @@ -606,7 +605,6 @@ public class MediaServerServiceImpl implements IMediaServerService {
606 mediaServerItem.setStreamIp(ip); 605 mediaServerItem.setStreamIp(ip);
607 mediaServerItem.setHookIp(sipConfig.getIp()); 606 mediaServerItem.setHookIp(sipConfig.getIp());
608 mediaServerItem.setSdpIp(ip); 607 mediaServerItem.setSdpIp(ip);
609 - mediaServerItem.setStreamNoneReaderDelayMS(zlmServerConfig.getGeneralStreamNoneReaderDelayMS());  
610 return mediaServerItem; 608 return mediaServerItem;
611 } 609 }
612 610
src/main/java/com/genersoft/iot/vmp/storager/dao/MediaServerMapper.java
@@ -26,7 +26,6 @@ public interface MediaServerMapper { @@ -26,7 +26,6 @@ public interface MediaServerMapper {
26 "rtspSSLPort, " + 26 "rtspSSLPort, " +
27 "autoConfig, " + 27 "autoConfig, " +
28 "secret, " + 28 "secret, " +
29 - "streamNoneReaderDelayMS, " +  
30 "rtpEnable, " + 29 "rtpEnable, " +
31 "rtpPortRange, " + 30 "rtpPortRange, " +
32 "sendRtpPortRange, " + 31 "sendRtpPortRange, " +
@@ -51,7 +50,6 @@ public interface MediaServerMapper { @@ -51,7 +50,6 @@ public interface MediaServerMapper {
51 "${rtspSSLPort}, " + 50 "${rtspSSLPort}, " +
52 "${autoConfig}, " + 51 "${autoConfig}, " +
53 "'${secret}', " + 52 "'${secret}', " +
54 - "${streamNoneReaderDelayMS}, " +  
55 "${rtpEnable}, " + 53 "${rtpEnable}, " +
56 "'${rtpPortRange}', " + 54 "'${rtpPortRange}', " +
57 "'${sendRtpPortRange}', " + 55 "'${sendRtpPortRange}', " +
@@ -77,7 +75,6 @@ public interface MediaServerMapper { @@ -77,7 +75,6 @@ public interface MediaServerMapper {
77 "<if test=\"rtspPort != null\">, rtspPort=${rtspPort}</if>" + 75 "<if test=\"rtspPort != null\">, rtspPort=${rtspPort}</if>" +
78 "<if test=\"rtspSSLPort != null\">, rtspSSLPort=${rtspSSLPort}</if>" + 76 "<if test=\"rtspSSLPort != null\">, rtspSSLPort=${rtspSSLPort}</if>" +
79 "<if test=\"autoConfig != null\">, autoConfig=${autoConfig}</if>" + 77 "<if test=\"autoConfig != null\">, autoConfig=${autoConfig}</if>" +
80 - "<if test=\"streamNoneReaderDelayMS != null\">, streamNoneReaderDelayMS=${streamNoneReaderDelayMS}</if>" +  
81 "<if test=\"rtpEnable != null\">, rtpEnable=${rtpEnable}</if>" + 78 "<if test=\"rtpEnable != null\">, rtpEnable=${rtpEnable}</if>" +
82 "<if test=\"rtpPortRange != null\">, rtpPortRange='${rtpPortRange}'</if>" + 79 "<if test=\"rtpPortRange != null\">, rtpPortRange='${rtpPortRange}'</if>" +
83 "<if test=\"sendRtpPortRange != null\">, sendRtpPortRange='${sendRtpPortRange}'</if>" + 80 "<if test=\"sendRtpPortRange != null\">, sendRtpPortRange='${sendRtpPortRange}'</if>" +
@@ -102,7 +99,6 @@ public interface MediaServerMapper { @@ -102,7 +99,6 @@ public interface MediaServerMapper {
102 "<if test=\"rtspPort != null\">, rtspPort=${rtspPort}</if>" + 99 "<if test=\"rtspPort != null\">, rtspPort=${rtspPort}</if>" +
103 "<if test=\"rtspSSLPort != null\">, rtspSSLPort=${rtspSSLPort}</if>" + 100 "<if test=\"rtspSSLPort != null\">, rtspSSLPort=${rtspSSLPort}</if>" +
104 "<if test=\"autoConfig != null\">, autoConfig=${autoConfig}</if>" + 101 "<if test=\"autoConfig != null\">, autoConfig=${autoConfig}</if>" +
105 - "<if test=\"streamNoneReaderDelayMS != null\">, streamNoneReaderDelayMS=${streamNoneReaderDelayMS}</if>" +  
106 "<if test=\"rtpEnable != null\">, rtpEnable=${rtpEnable}</if>" + 102 "<if test=\"rtpEnable != null\">, rtpEnable=${rtpEnable}</if>" +
107 "<if test=\"rtpPortRange != null\">, rtpPortRange='${rtpPortRange}'</if>" + 103 "<if test=\"rtpPortRange != null\">, rtpPortRange='${rtpPortRange}'</if>" +
108 "<if test=\"sendRtpPortRange != null\">, sendRtpPortRange='${sendRtpPortRange}'</if>" + 104 "<if test=\"sendRtpPortRange != null\">, sendRtpPortRange='${sendRtpPortRange}'</if>" +
src/main/java/com/genersoft/iot/vmp/storager/dao/StreamProxyMapper.java
@@ -11,10 +11,10 @@ import java.util.List; @@ -11,10 +11,10 @@ import java.util.List;
11 public interface StreamProxyMapper { 11 public interface StreamProxyMapper {
12 12
13 @Insert("INSERT INTO stream_proxy (type, name, app, stream,mediaServerId, url, src_url, dst_url, " + 13 @Insert("INSERT INTO stream_proxy (type, name, app, stream,mediaServerId, url, src_url, dst_url, " +
14 - "timeout_ms, ffmpeg_cmd_key, rtp_type, enable_hls, enable_mp4, enable, status, enable_remove_none_reader, createTime) VALUES" + 14 + "timeout_ms, ffmpeg_cmd_key, rtp_type, enable_hls, enable_mp4, enable, status, enable_remove_none_reader, enable_disable_none_reader, createTime) VALUES" +
15 "('${type}','${name}', '${app}', '${stream}', '${mediaServerId}','${url}', '${src_url}', '${dst_url}', " + 15 "('${type}','${name}', '${app}', '${stream}', '${mediaServerId}','${url}', '${src_url}', '${dst_url}', " +
16 "'${timeout_ms}', '${ffmpeg_cmd_key}', '${rtp_type}', ${enable_hls}, ${enable_mp4}, ${enable}, ${status}, " + 16 "'${timeout_ms}', '${ffmpeg_cmd_key}', '${rtp_type}', ${enable_hls}, ${enable_mp4}, ${enable}, ${status}, " +
17 - "${enable_remove_none_reader}, '${createTime}' )") 17 + "${enable_remove_none_reader}, ${enable_disable_none_reader}, '${createTime}' )")
18 int add(StreamProxyItem streamProxyDto); 18 int add(StreamProxyItem streamProxyDto);
19 19
20 @Update("UPDATE stream_proxy " + 20 @Update("UPDATE stream_proxy " +
@@ -33,6 +33,7 @@ public interface StreamProxyMapper { @@ -33,6 +33,7 @@ public interface StreamProxyMapper {
33 "enable=#{enable}, " + 33 "enable=#{enable}, " +
34 "status=#{status}, " + 34 "status=#{status}, " +
35 "enable_remove_none_reader=#{enable_remove_none_reader}, " + 35 "enable_remove_none_reader=#{enable_remove_none_reader}, " +
  36 + "enable_disable_none_reader=#{enable_disable_none_reader}, " +
36 "enable_mp4=#{enable_mp4} " + 37 "enable_mp4=#{enable_mp4} " +
37 "WHERE app=#{app} AND stream=#{stream}") 38 "WHERE app=#{app} AND stream=#{stream}")
38 int update(StreamProxyItem streamProxyDto); 39 int update(StreamProxyItem streamProxyDto);
src/main/resources/all-application.yml
@@ -146,8 +146,6 @@ media: @@ -146,8 +146,6 @@ media:
146 auto-config: true 146 auto-config: true
147 # [可选] zlm服务器的hook.admin_params=secret 147 # [可选] zlm服务器的hook.admin_params=secret
148 secret: 035c73f7-bb6b-4889-a715-d9eb2d1925cc 148 secret: 035c73f7-bb6b-4889-a715-d9eb2d1925cc
149 - # [可选] zlm服务器的general.streamNoneReaderDelayMS  
150 - stream-none-reader-delay-ms: 18000 # 无人观看多久自动关闭流, -1表示永不自动关闭,即 关闭按需拉流  
151 # 启用多端口模式, 多端口模式使用端口区分每路流,兼容性更好。 单端口使用流的ssrc区分, 点播超时建议使用多端口测试 149 # 启用多端口模式, 多端口模式使用端口区分每路流,兼容性更好。 单端口使用流的ssrc区分, 点播超时建议使用多端口测试
152 rtp: 150 rtp:
153 # [可选] 是否启用多端口模式, 开启后会在portRange范围内选择端口用于媒体流传输 151 # [可选] 是否启用多端口模式, 开启后会在portRange范围内选择端口用于媒体流传输
@@ -190,6 +188,8 @@ user-settings: @@ -190,6 +188,8 @@ user-settings:
190 logInDatebase: true 188 logInDatebase: true
191 # 使用推流状态作为推流通道状态 189 # 使用推流状态作为推流通道状态
192 use-pushing-as-status: true 190 use-pushing-as-status: true
  191 + # 按需拉流, true:有人观看拉流,无人观看释放, false:拉起后不自动释放
  192 + stream-on-demand: true
193 193
194 # 关闭在线文档(生产环境建议关闭) 194 # 关闭在线文档(生产环境建议关闭)
195 springdoc: 195 springdoc:
web_src/src/components/dialog/MediaServerEdit.vue
@@ -41,10 +41,6 @@ @@ -41,10 +41,6 @@
41 <el-input v-if="currentStep === 2" v-model="mediaServerForm.httpPort" disabled :disabled="mediaServerForm.defaultServer"></el-input> 41 <el-input v-if="currentStep === 2" v-model="mediaServerForm.httpPort" disabled :disabled="mediaServerForm.defaultServer"></el-input>
42 <el-input v-if="currentStep === 3" v-model="mediaServerForm.httpPort" :disabled="mediaServerForm.defaultServer"></el-input> 42 <el-input v-if="currentStep === 3" v-model="mediaServerForm.httpPort" :disabled="mediaServerForm.defaultServer"></el-input>
43 </el-form-item> 43 </el-form-item>
44 - <el-form-item label="SECRET" prop="secret">  
45 - <el-input v-if="currentStep === 2" v-model="mediaServerForm.secret" disabled :disabled="mediaServerForm.defaultServer"></el-input>  
46 - <el-input v-if="currentStep === 3" v-model="mediaServerForm.secret" :disabled="mediaServerForm.defaultServer"></el-input>  
47 - </el-form-item>  
48 <el-form-item label="HOOK IP" prop="ip"> 44 <el-form-item label="HOOK IP" prop="ip">
49 <el-input v-model="mediaServerForm.hookIp" placeholder="媒体服务HOOK_IP" clearable :disabled="mediaServerForm.defaultServer"></el-input> 45 <el-input v-model="mediaServerForm.hookIp" placeholder="媒体服务HOOK_IP" clearable :disabled="mediaServerForm.defaultServer"></el-input>
50 </el-form-item> 46 </el-form-item>
@@ -74,6 +70,10 @@ @@ -74,6 +70,10 @@
74 <el-form-item label="RTMPS PORT" prop="rtmpSSlPort"> 70 <el-form-item label="RTMPS PORT" prop="rtmpSSlPort">
75 <el-input v-model="mediaServerForm.rtmpSSlPort" placeholder="媒体服务RTMPS_PORT" clearable :disabled="mediaServerForm.defaultServer"></el-input> 71 <el-input v-model="mediaServerForm.rtmpSSlPort" placeholder="媒体服务RTMPS_PORT" clearable :disabled="mediaServerForm.defaultServer"></el-input>
76 </el-form-item> 72 </el-form-item>
  73 + <el-form-item label="SECRET" prop="secret">
  74 + <el-input v-if="currentStep === 2" v-model="mediaServerForm.secret" disabled :disabled="mediaServerForm.defaultServer"></el-input>
  75 + <el-input v-if="currentStep === 3" v-model="mediaServerForm.secret" :disabled="mediaServerForm.defaultServer"></el-input>
  76 + </el-form-item>
77 <el-form-item label="自动配置媒体服务" > 77 <el-form-item label="自动配置媒体服务" >
78 <el-switch v-model="mediaServerForm.autoConfig" :disabled="mediaServerForm.defaultServer"></el-switch> 78 <el-switch v-model="mediaServerForm.autoConfig" :disabled="mediaServerForm.defaultServer"></el-switch>
79 </el-form-item> 79 </el-form-item>
@@ -94,9 +94,6 @@ @@ -94,9 +94,6 @@
94 - 94 -
95 <el-input v-model="sendRtpPortRange2" placeholder="终止" @change="portRangeChange" clearable style="width: 100px" prop="sendRtpPortRange2" :disabled="mediaServerForm.defaultServer"></el-input> 95 <el-input v-model="sendRtpPortRange2" placeholder="终止" @change="portRangeChange" clearable style="width: 100px" prop="sendRtpPortRange2" :disabled="mediaServerForm.defaultServer"></el-input>
96 </el-form-item> 96 </el-form-item>
97 - <el-form-item label="无人观看多久后停止拉流" >  
98 - <el-input v-model.number="mediaServerForm.streamNoneReaderDelayMS" clearable :disabled="mediaServerForm.defaultServer"></el-input>  
99 - </el-form-item>  
100 <el-form-item label="录像管理服务端口" prop="recordAssistPort"> 97 <el-form-item label="录像管理服务端口" prop="recordAssistPort">
101 <el-input v-model.number="mediaServerForm.recordAssistPort" :disabled="mediaServerForm.defaultServer"> 98 <el-input v-model.number="mediaServerForm.recordAssistPort" :disabled="mediaServerForm.defaultServer">
102 <!-- <el-button v-if="mediaServerForm.recordAssistPort > 0" slot="append" type="primary" @click="checkRecordServer">测试</el-button>--> 99 <!-- <el-button v-if="mediaServerForm.recordAssistPort > 0" slot="append" type="primary" @click="checkRecordServer">测试</el-button>-->
@@ -172,7 +169,6 @@ export default { @@ -172,7 +169,6 @@ export default {
172 hookIp: "", 169 hookIp: "",
173 sdpIp: "", 170 sdpIp: "",
174 streamIp: "", 171 streamIp: "",
175 - streamNoneReaderDelayMS: "",  
176 secret: "035c73f7-bb6b-4889-a715-d9eb2d1925cc", 172 secret: "035c73f7-bb6b-4889-a715-d9eb2d1925cc",
177 httpPort: "", 173 httpPort: "",
178 httpSSlPort: "", 174 httpSSlPort: "",
@@ -332,7 +328,6 @@ export default { @@ -332,7 +328,6 @@ export default {
332 hookIp: "", 328 hookIp: "",
333 sdpIp: "", 329 sdpIp: "",
334 streamIp: "", 330 streamIp: "",
335 - streamNoneReaderDelayMS: "",  
336 secret: "035c73f7-bb6b-4889-a715-d9eb2d1925cc", 331 secret: "035c73f7-bb6b-4889-a715-d9eb2d1925cc",
337 httpPort: "", 332 httpPort: "",
338 httpSSlPort: "", 333 httpSSlPort: "",
web_src/src/components/dialog/StreamProxyEdit.vue
@@ -105,7 +105,9 @@ @@ -105,7 +105,9 @@
105 <el-checkbox label="启用" v-model="proxyParam.enable" ></el-checkbox> 105 <el-checkbox label="启用" v-model="proxyParam.enable" ></el-checkbox>
106 <el-checkbox label="转HLS" v-model="proxyParam.enable_hls" ></el-checkbox> 106 <el-checkbox label="转HLS" v-model="proxyParam.enable_hls" ></el-checkbox>
107 <el-checkbox label="MP4录制" v-model="proxyParam.enable_mp4" ></el-checkbox> 107 <el-checkbox label="MP4录制" v-model="proxyParam.enable_mp4" ></el-checkbox>
108 - <el-checkbox label="无人观看自动删除" v-model="proxyParam.enable_remove_none_reader" ></el-checkbox> 108 + <el-checkbox label="无人观看自动删除" v-model="proxyParam.enable_remove_none_reader" @change="removeNoneReader"></el-checkbox>
  109 + <el-checkbox label="无人观看停止拉流" v-model="proxyParam.enable_disable_none_reader" @change="disableNoneReaderHandType"></el-checkbox>
  110 +
109 </div> 111 </div>
110 112
111 </el-form-item> 113 </el-form-item>
@@ -170,6 +172,7 @@ export default { @@ -170,6 +172,7 @@ export default {
170 enable_hls: true, 172 enable_hls: true,
171 enable_mp4: false, 173 enable_mp4: false,
172 enable_remove_none_reader: false, 174 enable_remove_none_reader: false,
  175 + enable_disable_none_reader: true,
173 platformGbId: null, 176 platformGbId: null,
174 mediaServerId: null, 177 mediaServerId: null,
175 }, 178 },
@@ -276,6 +279,12 @@ export default { @@ -276,6 +279,12 @@ export default {
276 if (this.platform.enable && this.platform.expires == "0") { 279 if (this.platform.enable && this.platform.expires == "0") {
277 this.platform.expires = "300"; 280 this.platform.expires = "300";
278 } 281 }
  282 + },
  283 + removeNoneReader: function(checked) {
  284 + this.proxyParam.enable_disable_none_reader = !checked;
  285 + },
  286 + disableNoneReaderHandType: function(checked) {
  287 + this.proxyParam.enable_remove_none_reader = !checked;
279 } 288 }
280 }, 289 },
281 }; 290 };
web_src/src/components/setting/Media.vue
@@ -42,9 +42,6 @@ @@ -42,9 +42,6 @@
42 <el-form-item label="接口密钥" prop="secret"> 42 <el-form-item label="接口密钥" prop="secret">
43 <el-input v-model="form.secret" clearable></el-input> 43 <el-input v-model="form.secret" clearable></el-input>
44 </el-form-item> 44 </el-form-item>
45 - <el-form-item label="无人观看触发时长">  
46 - <el-input v-model.number="form.streamNoneReaderDelayMS" clearable></el-input>  
47 - </el-form-item>  
48 <el-form-item label="自动配置"> 45 <el-form-item label="自动配置">
49 <el-switch v-model="form.autoConfig"></el-switch> 46 <el-switch v-model="form.autoConfig"></el-switch>
50 </el-form-item> 47 </el-form-item>