Commit 470625e0770e27e8f20c3221b9c4096218079294
1 parent
fa13b228
支持全局固定流地址
Showing
6 changed files
with
88 additions
and
62 deletions
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java
| ... | ... | @@ -459,7 +459,10 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements |
| 459 | 459 | sendRtpItem.setApp("rtp"); |
| 460 | 460 | if ("Playback".equalsIgnoreCase(sessionName)) { |
| 461 | 461 | sendRtpItem.setPlayType(InviteStreamType.PLAYBACK); |
| 462 | - SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, null, null, device.isSsrcCheck(), true, 0, false, device.getStreamModeForParam()); | |
| 462 | + String startTimeStr = DateUtil.urlFormatter.format(start); | |
| 463 | + String endTimeStr = DateUtil.urlFormatter.format(end); | |
| 464 | + String stream = device.getDeviceId() + "_" + channelId + "_" + startTimeStr + "_" + endTimeStr; | |
| 465 | + SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, stream, null, device.isSsrcCheck(), true, 0, false, device.getStreamModeForParam()); | |
| 463 | 466 | sendRtpItem.setStreamId(ssrcInfo.getStream()); |
| 464 | 467 | // 写入redis, 超时时回复 |
| 465 | 468 | redisCatchStorage.updateSendRTPSever(sendRtpItem); |
| ... | ... | @@ -520,12 +523,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements |
| 520 | 523 | } |
| 521 | 524 | })); |
| 522 | 525 | sendRtpItem.setPlayType(InviteStreamType.PLAY); |
| 523 | - String streamId = null; | |
| 524 | - if (mediaServerItem.isRtpEnable()) { | |
| 525 | - streamId = String.format("%s_%s", device.getDeviceId(), channelId); | |
| 526 | - }else { | |
| 527 | - streamId = String.format("%08x", Integer.parseInt(ssrcInfo.getSsrc())).toUpperCase(); | |
| 528 | - } | |
| 526 | + String streamId = String.format("%s_%s", device.getDeviceId(), channelId); | |
| 529 | 527 | sendRtpItem.setStreamId(streamId); |
| 530 | 528 | sendRtpItem.setSsrc(ssrcInfo.getSsrc()); |
| 531 | 529 | redisCatchStorage.updateSendRTPSever(sendRtpItem); | ... | ... |
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java
| ... | ... | @@ -193,7 +193,10 @@ public class ZLMHttpHookListener { |
| 193 | 193 | |
| 194 | 194 | String mediaServerId = json.getString("mediaServerId"); |
| 195 | 195 | MediaServerItem mediaInfo = mediaServerService.getOne(mediaServerId); |
| 196 | - | |
| 196 | + if (mediaInfo == null) { | |
| 197 | + return new HookResultForOnPublish(200, "success"); | |
| 198 | + } | |
| 199 | + // 推流鉴权的处理 | |
| 197 | 200 | if (!"rtp".equals(param.getApp())) { |
| 198 | 201 | if (userSetting.getPushAuthority()) { |
| 199 | 202 | // 推流鉴权 |
| ... | ... | @@ -245,11 +248,21 @@ public class ZLMHttpHookListener { |
| 245 | 248 | } |
| 246 | 249 | }); |
| 247 | 250 | |
| 251 | + // 是否录像 | |
| 248 | 252 | if ("rtp".equals(param.getApp())) { |
| 249 | 253 | result.setEnable_mp4(userSetting.getRecordSip()); |
| 250 | 254 | } else { |
| 251 | 255 | result.setEnable_mp4(userSetting.isRecordPushLive()); |
| 252 | 256 | } |
| 257 | + // 替换流地址 | |
| 258 | + if ("rtp".equals(param.getApp()) && !mediaInfo.isRtpEnable()) { | |
| 259 | + String ssrc = String.format("%010d", Long.parseLong(param.getStream(), 16));; | |
| 260 | + InviteInfo inviteInfo = inviteStreamService.getInviteInfoBySSRC(ssrc); | |
| 261 | + if (inviteInfo != null) { | |
| 262 | + result.setStream_replace(inviteInfo.getStream()); | |
| 263 | + logger.info("[ZLM HOOK]推流鉴权 stream: {} 替换为 {}", param.getStream(), inviteInfo.getStream()); | |
| 264 | + } | |
| 265 | + } | |
| 253 | 266 | List<SsrcTransaction> ssrcTransactionForAll = sessionManager.getSsrcTransactionForAll(null, null, null, param.getStream()); |
| 254 | 267 | if (ssrcTransactionForAll != null && ssrcTransactionForAll.size() == 1) { |
| 255 | 268 | String deviceId = ssrcTransactionForAll.get(0).getDeviceId(); |
| ... | ... | @@ -562,7 +575,7 @@ public class ZLMHttpHookListener { |
| 562 | 575 | |
| 563 | 576 | if ("rtp".equals(param.getApp())) { |
| 564 | 577 | String[] s = param.getStream().split("_"); |
| 565 | - if (!mediaInfo.isRtpEnable() || (s.length != 2 && s.length != 4)) { | |
| 578 | + if ((s.length != 2 && s.length != 4)) { | |
| 566 | 579 | defaultResult.setResult(HookResult.SUCCESS()); |
| 567 | 580 | return defaultResult; |
| 568 | 581 | } |
| ... | ... | @@ -591,7 +604,6 @@ public class ZLMHttpHookListener { |
| 591 | 604 | |
| 592 | 605 | result.onTimeout(() -> { |
| 593 | 606 | logger.info("[ZLM HOOK] 预览流自动点播, 等待超时"); |
| 594 | - // 释放rtpserver | |
| 595 | 607 | msg.setData(new HookResult(ErrorCode.ERROR100.getCode(), "点播超时")); |
| 596 | 608 | resultHolder.invokeResult(msg); |
| 597 | 609 | }); | ... | ... |
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/HookResultForOnPublish.java
| ... | ... | @@ -6,6 +6,7 @@ public class HookResultForOnPublish extends HookResult{ |
| 6 | 6 | private boolean enable_mp4; |
| 7 | 7 | private int mp4_max_second; |
| 8 | 8 | private String mp4_save_path; |
| 9 | + private String stream_replace; | |
| 9 | 10 | |
| 10 | 11 | public HookResultForOnPublish() { |
| 11 | 12 | } |
| ... | ... | @@ -51,12 +52,21 @@ public class HookResultForOnPublish extends HookResult{ |
| 51 | 52 | this.mp4_save_path = mp4_save_path; |
| 52 | 53 | } |
| 53 | 54 | |
| 55 | + public String getStream_replace() { | |
| 56 | + return stream_replace; | |
| 57 | + } | |
| 58 | + | |
| 59 | + public void setStream_replace(String stream_replace) { | |
| 60 | + this.stream_replace = stream_replace; | |
| 61 | + } | |
| 62 | + | |
| 54 | 63 | @Override |
| 55 | 64 | public String toString() { |
| 56 | 65 | return "HookResultForOnPublish{" + |
| 57 | 66 | "enable_audio=" + enable_audio + |
| 58 | 67 | ", enable_mp4=" + enable_mp4 + |
| 59 | 68 | ", mp4_max_second=" + mp4_max_second + |
| 69 | + ", stream_replace=" + stream_replace + | |
| 60 | 70 | ", mp4_save_path='" + mp4_save_path + '\'' + |
| 61 | 71 | '}'; |
| 62 | 72 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/service/IInviteStreamService.java
| ... | ... | @@ -74,5 +74,13 @@ public interface IInviteStreamService { |
| 74 | 74 | int getStreamInfoCount(String mediaServerId); |
| 75 | 75 | |
| 76 | 76 | |
| 77 | + /** | |
| 78 | + * 获取MediaServer下的流信息 | |
| 79 | + */ | |
| 80 | + InviteInfo getInviteInfoBySSRC(String ssrc); | |
| 77 | 81 | |
| 82 | + /** | |
| 83 | + * 更新ssrc | |
| 84 | + */ | |
| 85 | + InviteInfo updateInviteInfoForSSRC(InviteInfo inviteInfo, String ssrcInResponse); | |
| 78 | 86 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/service/impl/InviteStreamServiceImpl.java
| ... | ... | @@ -80,7 +80,8 @@ public class InviteStreamServiceImpl implements IInviteStreamService { |
| 80 | 80 | ":" + inviteInfoForUpdate.getType() + |
| 81 | 81 | ":" + inviteInfoForUpdate.getDeviceId() + |
| 82 | 82 | ":" + inviteInfoForUpdate.getChannelId() + |
| 83 | - ":" + inviteInfoForUpdate.getStream(); | |
| 83 | + ":" + inviteInfoForUpdate.getStream()+ | |
| 84 | + ":" + inviteInfoForUpdate.getSsrcInfo().getSsrc(); | |
| 84 | 85 | redisTemplate.opsForValue().set(key, inviteInfoForUpdate); |
| 85 | 86 | } |
| 86 | 87 | |
| ... | ... | @@ -96,7 +97,8 @@ public class InviteStreamServiceImpl implements IInviteStreamService { |
| 96 | 97 | ":" + inviteInfo.getType() + |
| 97 | 98 | ":" + inviteInfo.getDeviceId() + |
| 98 | 99 | ":" + inviteInfo.getChannelId() + |
| 99 | - ":" + stream; | |
| 100 | + ":" + stream + | |
| 101 | + ":" + inviteInfo.getSsrcInfo().getSsrc(); | |
| 100 | 102 | inviteInfoInDb.setStream(stream); |
| 101 | 103 | if (inviteInfoInDb.getSsrcInfo() != null) { |
| 102 | 104 | inviteInfoInDb.getSsrcInfo().setStream(stream); |
| ... | ... | @@ -111,7 +113,8 @@ public class InviteStreamServiceImpl implements IInviteStreamService { |
| 111 | 113 | ":" + (type != null ? type : "*") + |
| 112 | 114 | ":" + (deviceId != null ? deviceId : "*") + |
| 113 | 115 | ":" + (channelId != null ? channelId : "*") + |
| 114 | - ":" + (stream != null ? stream : "*"); | |
| 116 | + ":" + (stream != null ? stream : "*") | |
| 117 | + + ":*"; | |
| 115 | 118 | List<Object> scanResult = RedisUtil.scan(redisTemplate, key); |
| 116 | 119 | if (scanResult.size() != 1) { |
| 117 | 120 | return null; |
| ... | ... | @@ -136,7 +139,8 @@ public class InviteStreamServiceImpl implements IInviteStreamService { |
| 136 | 139 | ":" + (type != null ? type : "*") + |
| 137 | 140 | ":" + (deviceId != null ? deviceId : "*") + |
| 138 | 141 | ":" + (channelId != null ? channelId : "*") + |
| 139 | - ":" + (stream != null ? stream : "*"); | |
| 142 | + ":" + (stream != null ? stream : "*") + | |
| 143 | + ":*"; | |
| 140 | 144 | List<Object> scanResult = RedisUtil.scan(redisTemplate, scanKey); |
| 141 | 145 | if (scanResult.size() > 0) { |
| 142 | 146 | for (Object keyObj : scanResult) { |
| ... | ... | @@ -191,7 +195,7 @@ public class InviteStreamServiceImpl implements IInviteStreamService { |
| 191 | 195 | @Override |
| 192 | 196 | public int getStreamInfoCount(String mediaServerId) { |
| 193 | 197 | int count = 0; |
| 194 | - String key = VideoManagerConstants.INVITE_PREFIX + ":*:*:*:*"; | |
| 198 | + String key = VideoManagerConstants.INVITE_PREFIX + ":*:*:*:*:*"; | |
| 195 | 199 | List<Object> scanResult = RedisUtil.scan(redisTemplate, key); |
| 196 | 200 | if (scanResult.size() == 0) { |
| 197 | 201 | return 0; |
| ... | ... | @@ -229,4 +233,35 @@ public class InviteStreamServiceImpl implements IInviteStreamService { |
| 229 | 233 | } |
| 230 | 234 | return key; |
| 231 | 235 | } |
| 236 | + | |
| 237 | + @Override | |
| 238 | + public InviteInfo getInviteInfoBySSRC(String ssrc) { | |
| 239 | + String key = VideoManagerConstants.INVITE_PREFIX + ":*:*:*:*:" + ssrc; | |
| 240 | + List<Object> scanResult = RedisUtil.scan(redisTemplate, key); | |
| 241 | + if (scanResult.size() != 1) { | |
| 242 | + return null; | |
| 243 | + } | |
| 244 | + | |
| 245 | + return (InviteInfo) redisTemplate.opsForValue().get(scanResult.get(0)); | |
| 246 | + } | |
| 247 | + | |
| 248 | + @Override | |
| 249 | + public InviteInfo updateInviteInfoForSSRC(InviteInfo inviteInfo, String ssrc) { | |
| 250 | + InviteInfo inviteInfoInDb = getInviteInfo(inviteInfo.getType(), inviteInfo.getDeviceId(), inviteInfo.getChannelId(), inviteInfo.getStream()); | |
| 251 | + if (inviteInfoInDb == null) { | |
| 252 | + return null; | |
| 253 | + } | |
| 254 | + removeInviteInfo(inviteInfoInDb); | |
| 255 | + String key = VideoManagerConstants.INVITE_PREFIX + | |
| 256 | + ":" + inviteInfo.getType() + | |
| 257 | + ":" + inviteInfo.getDeviceId() + | |
| 258 | + ":" + inviteInfo.getChannelId() + | |
| 259 | + ":" + inviteInfo.getStream() + | |
| 260 | + ":" + inviteInfo.getSsrcInfo().getSsrc(); | |
| 261 | + if (inviteInfoInDb.getSsrcInfo() != null) { | |
| 262 | + inviteInfoInDb.getSsrcInfo().setSsrc(ssrc); | |
| 263 | + } | |
| 264 | + redisTemplate.opsForValue().set(key, inviteInfoInDb); | |
| 265 | + return inviteInfoInDb; | |
| 266 | + } | |
| 232 | 267 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java
| ... | ... | @@ -158,10 +158,7 @@ public class PlayServiceImpl implements IPlayService { |
| 158 | 158 | } |
| 159 | 159 | } |
| 160 | 160 | } |
| 161 | - String streamId = null; | |
| 162 | - if (mediaServerItem.isRtpEnable()) { | |
| 163 | - streamId = String.format("%s_%s", device.getDeviceId(), channelId); | |
| 164 | - } | |
| 161 | + String streamId = String.format("%s_%s", device.getDeviceId(), channelId);; | |
| 165 | 162 | SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, streamId, ssrc, device.isSsrcCheck(), false, 0, false, device.getStreamModeForParam()); |
| 166 | 163 | if (ssrcInfo == null) { |
| 167 | 164 | callback.run(InviteErrorCode.ERROR_FOR_RESOURCE_EXHAUSTION.getCode(), InviteErrorCode.ERROR_FOR_RESOURCE_EXHAUSTION.getMsg(), null); |
| ... | ... | @@ -457,16 +454,13 @@ public class PlayServiceImpl implements IPlayService { |
| 457 | 454 | logger.warn("[录像回放] 单端口收流时不支持TCP主动方式收流 deviceId: {},channelId:{}", deviceId, channelId); |
| 458 | 455 | throw new ControllerException(ErrorCode.ERROR100.getCode(), "单端口收流时不支持TCP主动方式收流"); |
| 459 | 456 | } |
| 460 | - String stream = null; | |
| 461 | - if (newMediaServerItem.isRtpEnable()) { | |
| 462 | - String startTimeStr = startTime.replace("-", "") | |
| 463 | - .replace(":", "") | |
| 464 | - .replace(" ", ""); | |
| 465 | - String endTimeTimeStr = endTime.replace("-", "") | |
| 466 | - .replace(":", "") | |
| 467 | - .replace(" ", ""); | |
| 468 | - stream = deviceId + "_" + channelId + "_" + startTimeStr + "_" + endTimeTimeStr; | |
| 469 | - } | |
| 457 | + String startTimeStr = startTime.replace("-", "") | |
| 458 | + .replace(":", "") | |
| 459 | + .replace(" ", ""); | |
| 460 | + String endTimeTimeStr = endTime.replace("-", "") | |
| 461 | + .replace(":", "") | |
| 462 | + .replace(" ", ""); | |
| 463 | + String stream = deviceId + "_" + channelId + "_" + startTimeStr + "_" + endTimeTimeStr; | |
| 470 | 464 | SSRCInfo ssrcInfo = mediaServerService.openRTPServer(newMediaServerItem, stream, null, device.isSsrcCheck(), true, 0, false, device.getStreamModeForParam()); |
| 471 | 465 | playBack(newMediaServerItem, ssrcInfo, deviceId, channelId, startTime, endTime, callback); |
| 472 | 466 | } |
| ... | ... | @@ -628,44 +622,13 @@ public class PlayServiceImpl implements IPlayService { |
| 628 | 622 | if (ssrcInResponse != null) { |
| 629 | 623 | // 单端口 |
| 630 | 624 | // 重新订阅流上线 |
| 631 | - HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", | |
| 632 | - ssrcInfo.getStream(), true, "rtsp", mediaServerItem.getId()); | |
| 633 | - subscribe.removeSubscribe(hookSubscribe); | |
| 634 | 625 | SsrcTransaction ssrcTransaction = streamSession.getSsrcTransaction(inviteInfo.getDeviceId(), |
| 635 | 626 | inviteInfo.getChannelId(), null, inviteInfo.getStream()); |
| 636 | 627 | streamSession.remove(inviteInfo.getDeviceId(), |
| 637 | 628 | inviteInfo.getChannelId(), inviteInfo.getStream()); |
| 638 | - | |
| 639 | - String stream = String.format("%08x", Integer.parseInt(ssrcInResponse)).toUpperCase(); | |
| 640 | - hookSubscribe.getContent().put("stream", stream); | |
| 641 | - | |
| 642 | - inviteStreamService.updateInviteInfoForStream(inviteInfo, stream); | |
| 629 | + inviteStreamService.updateInviteInfoForSSRC(inviteInfo, ssrcInResponse); | |
| 643 | 630 | streamSession.put(device.getDeviceId(), channelId, ssrcTransaction.getCallId(), |
| 644 | - stream, ssrcInResponse, mediaServerItem.getId(), (SIPResponse) responseEvent.getResponse(), inviteSessionType); | |
| 645 | - subscribe.addSubscribe(hookSubscribe, (mediaServerItemInUse, hookParam) -> { | |
| 646 | - logger.info("[Invite 200OK] ssrc修正后收到订阅消息: " + hookParam); | |
| 647 | - dynamicTask.stop(timeOutTaskKey); | |
| 648 | - subscribe.removeSubscribe(hookSubscribe); | |
| 649 | - // hook响应 | |
| 650 | - StreamInfo streamInfo = onPublishHandlerForPlay(mediaServerItemInUse, hookParam, device.getDeviceId(), channelId); | |
| 651 | - if (streamInfo == null){ | |
| 652 | - callback.run(InviteErrorCode.ERROR_FOR_STREAM_PARSING_EXCEPTIONS.getCode(), | |
| 653 | - InviteErrorCode.ERROR_FOR_STREAM_PARSING_EXCEPTIONS.getMsg(), null); | |
| 654 | - inviteStreamService.call(inviteSessionType, device.getDeviceId(), channelId, null, | |
| 655 | - InviteErrorCode.ERROR_FOR_STREAM_PARSING_EXCEPTIONS.getCode(), | |
| 656 | - InviteErrorCode.ERROR_FOR_STREAM_PARSING_EXCEPTIONS.getMsg(), null); | |
| 657 | - return; | |
| 658 | - } | |
| 659 | - callback.run(InviteErrorCode.SUCCESS.getCode(), | |
| 660 | - InviteErrorCode.SUCCESS.getMsg(), streamInfo); | |
| 661 | - inviteStreamService.call(inviteSessionType, device.getDeviceId(), channelId, null, | |
| 662 | - InviteErrorCode.SUCCESS.getCode(), | |
| 663 | - InviteErrorCode.SUCCESS.getMsg(), | |
| 664 | - streamInfo); | |
| 665 | - if (inviteSessionType == InviteSessionType.PLAY) { | |
| 666 | - snapOnPlay(mediaServerItemInUse, device.getDeviceId(), channelId, stream); | |
| 667 | - } | |
| 668 | - }); | |
| 631 | + inviteInfo.getStream(), ssrcInResponse, mediaServerItem.getId(), (SIPResponse) responseEvent.getResponse(), inviteSessionType); | |
| 669 | 632 | } |
| 670 | 633 | } |
| 671 | 634 | } | ... | ... |