Commit 688e222dcccb809cf314e175db944ad25cb9bc1e
1 parent
470be2dc
优化按需拉流配置,拉流代理支持按需拉流
Showing
14 changed files
with
91 additions
and
82 deletions
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
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> |