From 1e5ae105717c0241cd31eed2d52277bdea43bab9 Mon Sep 17 00:00:00 2001 From: lin <648540858@qq.com> Date: Wed, 15 Apr 2026 00:31:49 +0800 Subject: [PATCH] =?UTF-8?q?=E8=B0=83=E6=95=B4=E6=B5=81=E5=A4=84=E7=90=86?= =?UTF-8?q?=E9=80=BB=E8=BE=91=E4=BB=A5=E6=94=AF=E6=8C=81=E5=8D=95=E7=AB=AF?= =?UTF-8?q?=E5=8F=A3=E6=94=B6=E6=B5=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../genersoft/iot/vmp/common/InviteInfo.java | 9 +- .../iot/vmp/common/enums/MediaStreamUtil.java | 8 +- .../vmp/gb28181/controller/DeviceControl.java | 8 +- .../controller/GBRecordController.java | 8 +- .../controller/PlaybackController.java | 4 +- .../impl/DeviceChannelServiceImpl.java | 1 + .../service/impl/PlatformServiceImpl.java | 2 +- .../gb28181/service/impl/PlayServiceImpl.java | 40 +++---- .../iot/vmp/jt1078/config/JT1078Config.java | 2 + .../service/impl/jt1078PlayServiceImpl.java | 45 +++++++- .../vmp/media/bean/ResultForOnPublish.java | 59 ++-------- .../media/zlm/ZLMMediaNodeServerService.java | 4 +- .../zlm/ZLMMediaServerStatusManager.java | 10 ++ .../zlm/dto/hook/HookResultForOnPublish.java | 10 +- .../vmp/service/IReceiveRtpServerService.java | 13 ++- .../vmp/service/impl/MediaServiceImpl.java | 107 ++---------------- .../service/impl/RtpServerServiceImpl.java | 92 +++++++++++---- .../iot/vmp/vmanager/ps/PsController.java | 4 + .../iot/vmp/vmanager/rtp/RtpController.java | 7 +- web/src/api/jtDevice.js | 2 +- 20 files changed, 196 insertions(+), 239 deletions(-) diff --git a/src/main/java/com/genersoft/iot/vmp/common/InviteInfo.java b/src/main/java/com/genersoft/iot/vmp/common/InviteInfo.java index 0c1279688..adf9643fd 100644 --- a/src/main/java/com/genersoft/iot/vmp/common/InviteInfo.java +++ b/src/main/java/com/genersoft/iot/vmp/common/InviteInfo.java @@ -35,16 +35,10 @@ public class InviteInfo { private Long createTime; - private Boolean record; - - private String startTime; - - private String endTime; - public static InviteInfo getInviteInfo(String deviceId, Integer channelId, String stream, SSRCInfo ssrcInfo, String mediaServerId, String receiveIp, Integer receivePort, String streamMode, - InviteSessionType type, InviteSessionStatus status, Boolean record) { + InviteSessionType type, InviteSessionStatus status) { InviteInfo inviteInfo = new InviteInfo(); inviteInfo.setDeviceId(deviceId); inviteInfo.setChannelId(channelId); @@ -56,7 +50,6 @@ public class InviteInfo { inviteInfo.setType(type); inviteInfo.setStatus(status); inviteInfo.setMediaServerId(mediaServerId); - inviteInfo.setRecord(record); return inviteInfo; } diff --git a/src/main/java/com/genersoft/iot/vmp/common/enums/MediaStreamUtil.java b/src/main/java/com/genersoft/iot/vmp/common/enums/MediaStreamUtil.java index 3f297ca31..9e0e90f3b 100644 --- a/src/main/java/com/genersoft/iot/vmp/common/enums/MediaStreamUtil.java +++ b/src/main/java/com/genersoft/iot/vmp/common/enums/MediaStreamUtil.java @@ -1,9 +1,11 @@ package com.genersoft.iot.vmp.common.enums; public class MediaStreamUtil { + public final static String LOAD_MP4_APP = "mp4_record"; public final static String RTP_APP = "rtp"; public final static String RTP_STREAM_REST_PREFIX = "s"; + public final static String GB28181_TALK = "talk"; public final static String GB28181_BROADCAST = "broadcast"; @@ -24,11 +26,11 @@ public class MediaStreamUtil { return GB28181_TALK.equals(app); } - public static boolean isBroadcast(String app, String streamId) { - return GB28181_BROADCAST.equals(app); + public static boolean isBroadcast(String app, String streamId) { + return GB28181_BROADCAST.equals(app); } - public static boolean isJT1078(String app, String streamId) { + public static boolean isJT1078(String app, String streamId) { return RTP_APP.equals(app) || streamId.startsWith(JT1078_STREAM_PREFIX); } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/controller/DeviceControl.java b/src/main/java/com/genersoft/iot/vmp/gb28181/controller/DeviceControl.java index 6170cb1b9..92a43b1c6 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/controller/DeviceControl.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/controller/DeviceControl.java @@ -73,9 +73,7 @@ public class DeviceControl { @Parameter(name = "guardCmd", description = "命令, 可选值:SetGuard(布防),ResetGuard(撤防)", required = true) @GetMapping("/guard") public DeferredResult> guardApi(String deviceId, String guardCmd) { - if (log.isDebugEnabled()) { - log.debug("布防/撤防API调用"); - } + log.info("[布防/撤防] API调用, deviceId: {}, guardCmd: {}", deviceId, guardCmd); Device device = deviceService.getDeviceByDeviceId(deviceId); Assert.notNull(device, "设备不存在"); DeferredResult> result = new DeferredResult<>(); @@ -109,9 +107,7 @@ public class DeviceControl { public DeferredResult> resetAlarm(String deviceId, String channelId, @RequestParam(required = false) String alarmMethod, @RequestParam(required = false) String alarmType) { - if (log.isDebugEnabled()) { - log.debug("报警复位API调用"); - } + log.info("[报警复位] deviceId: {}, channelId: {}, alarmMethod: {}, alarmType: {}", deviceId, channelId, alarmMethod, alarmType); Device device = deviceService.getDeviceByDeviceId(deviceId); Assert.notNull(device, "设备不存在"); DeferredResult> result = new DeferredResult<>(); diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/controller/GBRecordController.java b/src/main/java/com/genersoft/iot/vmp/gb28181/controller/GBRecordController.java index 368538f68..eeee596e9 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/controller/GBRecordController.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/controller/GBRecordController.java @@ -67,9 +67,7 @@ public class GBRecordController { @GetMapping("/query/{deviceId}/{channelId}") public DeferredResult> recordinfo(@PathVariable String deviceId, @PathVariable String channelId, String startTime, String endTime){ - if (log.isDebugEnabled()) { - log.debug(String.format("录像信息查询 API调用,deviceId:%s ,startTime:%s, endTime:%s",deviceId, startTime, endTime)); - } + DeferredResult> result = new DeferredResult<>(Long.valueOf(userSetting.getRecordInfoTimeout()), TimeUnit.MILLISECONDS); if (!DateUtil.verification(startTime, DateUtil.formatter)){ throw new ControllerException(ErrorCode.ERROR100.getCode(), "startTime格式为" + DateUtil.PATTERN); @@ -113,9 +111,7 @@ public class GBRecordController { public DeferredResult> download(HttpServletRequest request, @PathVariable String deviceId, @PathVariable String channelId, String startTime, String endTime, String downloadSpeed) { - if (log.isDebugEnabled()) { - log.debug(String.format("历史媒体下载 API调用,deviceId:%s,channelId:%s,downloadSpeed:%s", deviceId, channelId, downloadSpeed)); - } + log.info("[开始历史媒体下载] deviceId: {}, channelId: {}, startTime: {}, endTime: {}, downloadSpeed: {}", deviceId, channelId, startTime, endTime, downloadSpeed); String uuid = UUID.randomUUID().toString(); String key = DeferredResultHolder.CALLBACK_CMD_DOWNLOAD + deviceId + channelId; diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/controller/PlaybackController.java b/src/main/java/com/genersoft/iot/vmp/gb28181/controller/PlaybackController.java index d5e47b57a..5e45c3be7 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/controller/PlaybackController.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/controller/PlaybackController.java @@ -80,9 +80,7 @@ public class PlaybackController { public DeferredResult> start(HttpServletRequest request, @PathVariable String deviceId, @PathVariable String channelId, String startTime, String endTime) { - if (log.isDebugEnabled()) { - log.debug(String.format("设备回放 API调用,deviceId:%s ,channelId:%s", deviceId, channelId)); - } + log.info("[录像回放] deviceId: {}, channelId: {}, startTime: {}, endTime: {}", deviceId, channelId, startTime, endTime); String uuid = UUID.randomUUID().toString(); String key = DeferredResultHolder.CALLBACK_CMD_PLAYBACK + deviceId + channelId; diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/DeviceChannelServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/DeviceChannelServiceImpl.java index ba5df91ee..4b9e7214f 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/DeviceChannelServiceImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/DeviceChannelServiceImpl.java @@ -609,6 +609,7 @@ public class DeviceChannelServiceImpl implements IDeviceChannelService { @Override public void queryRecordInfo(Device device, DeviceChannel channel, String startTime, String endTime, ErrorCallback callback) { + log.info("录像查询 API调用,deviceId:{},channelId:{},startTime:{},endTime:{}", device.getDeviceId(), channel.getDeviceId(), startTime, endTime); if (!userSetting.getServerId().equals(device.getServerId())){ redisRpcPlayService.queryRecordInfo(device.getServerId(), channel.getId(), startTime, endTime, callback); return; diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/PlatformServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/PlatformServiceImpl.java index eb4299fcf..8acda4698 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/PlatformServiceImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/PlatformServiceImpl.java @@ -650,7 +650,7 @@ public class PlatformServiceImpl implements IPlatformService, CommandLineRunner // 初始化redis中的invite消息状态 InviteInfo inviteInfo = InviteInfo.getInviteInfo(platform.getServerGBId(), channel.getGbId(), ssrcInfo.getStream(), ssrcInfo, mediaServerItem.getId(), mediaServerItem.getSdpIp(), ssrcInfo.getPort(), userSetting.getBroadcastForPlatform(), InviteSessionType.BROADCAST, - InviteSessionStatus.ready, userSetting.getRecordSip()); + InviteSessionStatus.ready); inviteStreamService.updateInviteInfo(inviteInfo); commanderForPlatform.broadcastInviteCmd(platform, channel,sourceId, mediaServerItem, ssrcInfo, event -> { inviteOKHandler(event, ssrcInfo, false, mediaServerItem, platform, channel, diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/PlayServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/PlayServiceImpl.java index 6a970ffb3..3ced633df 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/PlayServiceImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/PlayServiceImpl.java @@ -376,7 +376,9 @@ public class PlayServiceImpl implements IPlayService { String streamId = String.format("%s_%s", device.getDeviceId(), channel.getDeviceId()); - SSRCInfo ssrcInfo = receiveRtpServerService.openGbRTPServerForPlay(mediaServer, device, channel, ssrc, (code, msg, result) -> { + SSRCInfo ssrcInfo = receiveRtpServerService.openGbRTPServerForPlay(mediaServer, device, channel, ssrc, + record != null ? record : userSetting.getRecordSip(), + (code, msg, result) -> { if (code == InviteErrorCode.SUCCESS.getCode() && result != null && result.getHookData() != null) { // hook 响应 @@ -436,13 +438,7 @@ public class PlayServiceImpl implements IPlayService { // 初始化redis中的invite消息状态 InviteInfo inviteInfo = InviteInfo.getInviteInfo(device.getDeviceId(), channel.getId(), ssrcInfo.getStream(), ssrcInfo, mediaServer.getId(), mediaServer.getSdpIp(), ssrcInfo.getPort(), device.getStreamMode(), InviteSessionType.PLAY, - InviteSessionStatus.ready, userSetting.getRecordSip()); - if (record != null) { - inviteInfo.setRecord(record); - }else { - inviteInfo.setRecord(userSetting.getRecordSip()); - } - + InviteSessionStatus.ready); inviteStreamService.updateInviteInfo(inviteInfo); try { @@ -542,6 +538,9 @@ public class PlayServiceImpl implements IPlayService { return; } sendRtpInfo.setPort(localPort); + // 增加鉴权信息 + receiveRtpServerService.addAuthenticateInfoForGb28181Talk(mediaServerItem, sendRtpInfo.getStream()); + }catch (ControllerException e) { mediaServerService.releaseSsrc(mediaServerItem.getId(), sendRtpInfo.getSsrcToRelease()); log.info("[语音对讲]失败 deviceId: {}, channelId: {}", device.getDeviceId(), channel.getDeviceId()); @@ -760,16 +759,9 @@ public class PlayServiceImpl implements IPlayService { Device device, DeviceChannel channel, String startTime, String endTime, ErrorCallback callback) { - String startTimeStr = startTime.replace("-", "") - .replace(":", "") - .replace(" ", ""); - String endTimeTimeStr = endTime.replace("-", "") - .replace(":", "") - .replace(" ", ""); + String stream = receiveRtpServerService.getPlaybackStream(device, channel, startTime, endTime); - String stream = device.getDeviceId() + "_" + channel.getDeviceId() + "_" + startTimeStr + "_" + endTimeTimeStr; - - SSRCInfo ssrcInfo = receiveRtpServerService.openGbRTPServerForPlayback(mediaServer, device, channel, startTimeStr, endTimeTimeStr, (code, msg, result) -> { + SSRCInfo ssrcInfo = receiveRtpServerService.openGbRTPServerForPlayback(mediaServer, device, channel, startTime, endTime, (code, msg, result) -> { if (code == InviteErrorCode.SUCCESS.getCode() && result != null && result.getHookData() != null) { // hook响应 StreamInfo streamInfo = onPublishHandlerForPlayback(result.getHookData().getMediaServer(), result.getHookData().getMediaInfo(), device, channel, startTime, endTime); @@ -812,12 +804,12 @@ public class PlayServiceImpl implements IPlayService { } log.info("[录像回放] deviceId: {}, channelId: {}, 开始时间: {}, 结束时间: {}, 收流端口:{}, 收流模式:{}, SSRC: {}, SSRC校验:{}", - device.getDeviceId(), channel.getGbDeviceId(), startTime, endTime, ssrcInfo.getPort(), device.getStreamMode(), + device.getDeviceId(), channel.getDeviceId(), startTime, endTime, ssrcInfo.getPort(), device.getStreamMode(), ssrcInfo.getSsrc(), device.isSsrcCheck()); // 初始化redis中的invite消息状态 InviteInfo inviteInfo = InviteInfo.getInviteInfo(device.getDeviceId(), channel.getId(), ssrcInfo.getStream(), ssrcInfo, mediaServer.getId(), mediaServer.getSdpIp(), ssrcInfo.getPort(), device.getStreamMode(), InviteSessionType.PLAYBACK, - InviteSessionStatus.ready, userSetting.getRecordSip()); + InviteSessionStatus.ready); inviteStreamService.updateInviteInfo(inviteInfo); try { @@ -1005,7 +997,7 @@ public class PlayServiceImpl implements IPlayService { return; } - SSRCInfo ssrcInfo = receiveRtpServerService.openGbRTPServerForDownload(mediaServer, device, channel, (code, msg, result) -> { + SSRCInfo ssrcInfo = receiveRtpServerService.openGbRTPServerForDownload(mediaServer, device, channel, startTime, endTime, (code, msg, result) -> { if (code == InviteErrorCode.SUCCESS.getCode() && result != null && result.getHookData() != null) { // hook响应 StreamInfo streamInfo = onPublishHandlerForDownload(mediaServer, result.getHookData().getMediaInfo(), device, channel, startTime, endTime); @@ -1056,10 +1048,7 @@ public class PlayServiceImpl implements IPlayService { // 初始化redis中的invite消息状态 InviteInfo inviteInfo = InviteInfo.getInviteInfo(device.getDeviceId(), channel.getId(), ssrcInfo.getStream(), ssrcInfo, mediaServer.getId(), mediaServer.getSdpIp(), ssrcInfo.getPort(), device.getStreamMode(), InviteSessionType.DOWNLOAD, - InviteSessionStatus.ready, true); - inviteInfo.setStartTime(startTime); - inviteInfo.setEndTime(endTime); - + InviteSessionStatus.ready); inviteStreamService.updateInviteInfo(inviteInfo); try { cmder.downloadStreamCmd(mediaServer, ssrcInfo, device, channel, startTime, endTime, downloadSpeed, @@ -1722,6 +1711,7 @@ public class PlayServiceImpl implements IPlayService { if (!userSetting.getServerId().equals(device.getServerId())) { redisRpcPlayService.stop(device.getServerId(), type, channel.getId(), stream); }else { + log.info("[停止点播/回放/下载] {}/{}", device.getDeviceId(), channel.getDeviceId()); InviteInfo inviteInfo = inviteStreamService.getInviteInfo(type, channel.getId(), stream); if (inviteInfo == null) { if (type == InviteSessionType.PLAY) { @@ -1732,7 +1722,7 @@ public class PlayServiceImpl implements IPlayService { inviteStreamService.removeInviteInfo(inviteInfo); if (InviteSessionStatus.ok == inviteInfo.getStatus()) { try { - log.info("[停止点播/回放/下载] {}/{}", device.getDeviceId(), channel.getDeviceId()); + log.info("[停止点播/回放/下载] 成功 {}/{}", device.getDeviceId(), channel.getDeviceId()); cmder.streamByeCmd(device, channel.getDeviceId(), MediaStreamUtil.RTP_APP, inviteInfo.getStream(), null, null); } catch (InvalidArgumentException | SipException | ParseException | SsrcTransactionNotFoundException e) { log.error("[命令发送失败] 停止点播/回放/下载, 发送BYE: {}", e.getMessage()); diff --git a/src/main/java/com/genersoft/iot/vmp/jt1078/config/JT1078Config.java b/src/main/java/com/genersoft/iot/vmp/jt1078/config/JT1078Config.java index 6a6afee19..fba25a7c9 100644 --- a/src/main/java/com/genersoft/iot/vmp/jt1078/config/JT1078Config.java +++ b/src/main/java/com/genersoft/iot/vmp/jt1078/config/JT1078Config.java @@ -15,4 +15,6 @@ public class JT1078Config { private Integer port; private String password; + + private Boolean record = false; } diff --git a/src/main/java/com/genersoft/iot/vmp/jt1078/service/impl/jt1078PlayServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/jt1078/service/impl/jt1078PlayServiceImpl.java index e4941bfe8..54f7d7e3f 100644 --- a/src/main/java/com/genersoft/iot/vmp/jt1078/service/impl/jt1078PlayServiceImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/jt1078/service/impl/jt1078PlayServiceImpl.java @@ -10,6 +10,7 @@ import com.genersoft.iot.vmp.conf.exception.ControllerException; import com.genersoft.iot.vmp.gb28181.bean.*; import com.genersoft.iot.vmp.jt1078.bean.*; import com.genersoft.iot.vmp.jt1078.cmd.JT1078Template; +import com.genersoft.iot.vmp.jt1078.config.JT1078Config; import com.genersoft.iot.vmp.jt1078.proc.request.J1205; import com.genersoft.iot.vmp.jt1078.proc.response.*; import com.genersoft.iot.vmp.jt1078.service.Ijt1078PlayService; @@ -36,6 +37,7 @@ import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; import com.genersoft.iot.vmp.vmanager.bean.WVPResult; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.ObjectUtils; +import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.event.EventListener; import org.springframework.data.redis.core.RedisTemplate; @@ -80,6 +82,9 @@ public class jt1078PlayServiceImpl implements Ijt1078PlayService { @Autowired private UserSetting userSetting; + @Autowired + private JT1078Config jt1078Config; + /** * 流到来的处理 */ @@ -195,7 +200,7 @@ public class jt1078PlayServiceImpl implements Ijt1078PlayService { private void play(JTDevice device, JTChannel channel, int type, CommonCallback> callback) { String phoneNumber = device.getPhoneNumber(); int channelId = channel.getChannelId(); - String stream = MediaStreamUtil.getJTPlayStreamId(phoneNumber, channelId); + String finalStream = MediaStreamUtil.getJTPlayStreamId(phoneNumber, channelId); // 检查流是否已经存在,存在则返回 String playKey = VideoManagerConstants.INVITE_INFO_1078_PLAY + phoneNumber + ":" + channelId; List>> errorCallbacks = inviteErrorCallbackMap.computeIfAbsent(playKey, k -> new ArrayList<>()); @@ -230,11 +235,23 @@ public class jt1078PlayServiceImpl implements Ijt1078PlayService { } return; } + + String streamId; + String streamReplace = null; + if (mediaServer.isRtpEnable()) { + log.info("[JT-点播] 媒体服务器支持rtp,开启rtp点播, phoneNumber: {}, channelId: {}", phoneNumber, channelId); + streamId = finalStream; + }else { + String phone = StringUtils.leftPad(device.getPhoneNumber(), 12, '0'); + streamId = String.format("%s_%s", phone, channelId); + streamReplace = finalStream; + } + // 开启收流端口 RTPServerParam rtpServerParam = new RTPServerParam(); rtpServerParam.setMediaServer(mediaServer); rtpServerParam.setApp(MediaStreamUtil.RTP_APP); - rtpServerParam.setStreamId(stream); + rtpServerParam.setStreamId(finalStream); rtpServerParam.setPort(0); rtpServerParam.setTcpMode(1); // 1 表示tcp被动 rtpServerParam.setOnlyAuto(false); @@ -260,7 +277,7 @@ public class jt1078PlayServiceImpl implements Ijt1078PlayService { String fileName = phoneNumber + "_" + channelId + ".jpg"; // 请求截图 log.info("[请求截图]: {}", fileName); - mediaServerService.getSnap(mediaServer, MediaStreamUtil.RTP_APP, stream, 15, 1, path, fileName); + mediaServerService.getSnap(mediaServer, MediaStreamUtil.RTP_APP, finalStream, 15, 1, path, fileName); }else { if (callback != null) { callback.run(WVPResult.fail(code, msg)); @@ -277,6 +294,8 @@ public class jt1078PlayServiceImpl implements Ijt1078PlayService { stopPlay(phoneNumber, channelId); return; } + // 补充鉴权参数 + receiveRtpServerService.addAuthenticateInfo(streamId, streamReplace, !channel.isHasAudio(), jt1078Config.getRecord(), null); log.info("[JT-点播] phoneNumber: {}, channelId: {},IP: {}, 端口: {}", phoneNumber, channelId, mediaServer.getSdpIp(), port); J9101 j9101 = new J9101(); @@ -434,7 +453,7 @@ public class jt1078PlayServiceImpl implements Ijt1078PlayService { } String app = MediaStreamUtil.RTP_APP; - String stream = MediaStreamUtil.getJTPlaybackStreamId(phoneNumber, channelId, + String finalStream = MediaStreamUtil.getJTPlaybackStreamId(phoneNumber, channelId, DateUtil.yyyy_MM_dd_HH_mm_ssToUrl(startTime), DateUtil.yyyy_MM_dd_HH_mm_ssToUrl(endTime)); MediaServer mediaServer; if (org.springframework.util.ObjectUtils.isEmpty(device.getMediaServerId()) || "auto".equals(device.getMediaServerId())) { @@ -448,12 +467,22 @@ public class jt1078PlayServiceImpl implements Ijt1078PlayService { } return; } + String streamId; + String streamReplace = null; + if (mediaServer.isRtpEnable()) { + log.info("[JT-点播] 媒体服务器支持rtp,开启rtp点播, phoneNumber: {}, channelId: {}", phoneNumber, channelId); + streamId = finalStream; + }else { + String phone = StringUtils.leftPad(device.getPhoneNumber(), 12, '0'); + streamId = String.format("%s_%s", phone, channelId); + streamReplace = finalStream; + } // 开启收流端口 RTPServerParam rtpServerParam = new RTPServerParam(); rtpServerParam.setMediaServer(mediaServer); rtpServerParam.setApp(MediaStreamUtil.RTP_APP); - rtpServerParam.setStreamId(stream); + rtpServerParam.setStreamId(finalStream); rtpServerParam.setPort(0); rtpServerParam.setTcpMode(1); // 1 表示tcp被动 rtpServerParam.setOnlyAuto(false); @@ -479,10 +508,14 @@ public class jt1078PlayServiceImpl implements Ijt1078PlayService { errorCallback.run(new WVPResult<>(InviteErrorCode.ERROR_FOR_SIGNALLING_TIMEOUT.getCode(), InviteErrorCode.ERROR_FOR_SIGNALLING_TIMEOUT.getMsg(), null)); } - receiveRtpServerService.closeRTPServer(mediaServer, app, stream); + receiveRtpServerService.closeRTPServer(mediaServer, app, finalStream); } }); log.info("[JT-回放] logInfo: {}, 端口: {}", logInfo, port); + + // 补充鉴权参数 + receiveRtpServerService.addAuthenticateInfo(streamId, streamReplace, !channel.isHasAudio(), jt1078Config.getRecord(), null); + J9201 j9201 = new J9201(); j9201.setChannel(channelId); j9201.setIp(mediaServer.getSdpIp()); diff --git a/src/main/java/com/genersoft/iot/vmp/media/bean/ResultForOnPublish.java b/src/main/java/com/genersoft/iot/vmp/media/bean/ResultForOnPublish.java index 88f7387db..a41f1776c 100644 --- a/src/main/java/com/genersoft/iot/vmp/media/bean/ResultForOnPublish.java +++ b/src/main/java/com/genersoft/iot/vmp/media/bean/ResultForOnPublish.java @@ -1,59 +1,16 @@ package com.genersoft.iot.vmp.media.bean; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter public class ResultForOnPublish { - private boolean enable_audio; - private boolean enable_mp4; - private int mp4_max_second; + private Boolean enable_audio; + private Boolean enable_mp4; + private Integer mp4_max_second; private String mp4_save_path; private String stream_replace; private Integer modify_stamp; - - public boolean isEnable_audio() { - return enable_audio; - } - - public void setEnable_audio(boolean enable_audio) { - this.enable_audio = enable_audio; - } - - public boolean isEnable_mp4() { - return enable_mp4; - } - - public void setEnable_mp4(boolean enable_mp4) { - this.enable_mp4 = enable_mp4; - } - - public int getMp4_max_second() { - return mp4_max_second; - } - - public void setMp4_max_second(int mp4_max_second) { - this.mp4_max_second = mp4_max_second; - } - - public String getMp4_save_path() { - return mp4_save_path; - } - - public void setMp4_save_path(String mp4_save_path) { - this.mp4_save_path = mp4_save_path; - } - - public String getStream_replace() { - return stream_replace; - } - - public void setStream_replace(String stream_replace) { - this.stream_replace = stream_replace; - } - - public Integer getModify_stamp() { - return modify_stamp; - } - - public void setModify_stamp(Integer modify_stamp) { - this.modify_stamp = modify_stamp; - } } diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMMediaNodeServerService.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMMediaNodeServerService.java index 7d8c1d930..2f8b83a9e 100644 --- a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMMediaNodeServerService.java +++ b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMMediaNodeServerService.java @@ -516,7 +516,7 @@ public class ZLMMediaNodeServerService implements IMediaNodeServerService { @Override public void loadMP4File(MediaServer mediaServer, String app, String stream, String filePath, String fileName, ErrorCallback callback) { - String buildApp = "mp4_record"; + String buildApp = MediaStreamUtil.LOAD_MP4_APP; String buildStream = app + "_" + stream + "_" + fileName + "_" + RandomStringUtils.randomAlphabetic(6).toLowerCase(); Hook hook = Hook.getInstance(HookType.on_media_arrival, buildApp, buildStream, mediaServer.getServerId()); @@ -539,7 +539,7 @@ public class ZLMMediaNodeServerService implements IMediaNodeServerService { @Override public void loadMP4FileForDate(MediaServer mediaServer, String app, String stream, String date, String dateDir, ErrorCallback callback) { - String buildApp = "mp4_record"; + String buildApp = MediaStreamUtil.LOAD_MP4_APP; String buildStream = app + "_" + stream + "_" + date; MediaInfo mediaInfo = getMediaInfo(mediaServer, buildApp, buildStream); if (mediaInfo != null) { diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMMediaServerStatusManager.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMMediaServerStatusManager.java index b0693c89d..a56f450bc 100644 --- a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMMediaServerStatusManager.java +++ b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMMediaServerStatusManager.java @@ -211,6 +211,16 @@ public class ZLMMediaServerStatusManager { String key = "zlm-keepalive-" + mediaServer.getId(); dynamicTask.startDelay(key, ()->{ log.warn("[ZLM-心跳超时] ID:{}", mediaServer.getId()); + // 主动探测一次,避免因短暂网络抖动误判离线 + ZLMResult> probeResult = zlmresTfulUtils.getMediaServerConfig(mediaServer); + if (probeResult != null && probeResult.getData() != null && !probeResult.getData().isEmpty()) { + log.info("[ZLM-心跳超时] 主动探测成功,服务仍在线,重置心跳计时器 ID:{}", mediaServer.getId()); + ZLMServerConfig zlmServerConfig = JSON.parseObject(JSON.toJSONString(probeResult.getData().get(0)), ZLMServerConfig.class); + initPort(mediaServer, zlmServerConfig); + online(mediaServer, zlmServerConfig); + return; + } + log.warn("[ZLM-心跳超时] 主动探测失败,确认离线 ID:{}", mediaServer.getId()); mediaServer.setStatus(false); offlineZlmPrimaryMap.put(mediaServer.getId(), mediaServer); offlineZlmTimeMap.put(mediaServer.getId(), System.currentTimeMillis()); diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/HookResultForOnPublish.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/HookResultForOnPublish.java index 3777e19ec..685b365e5 100755 --- a/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/HookResultForOnPublish.java +++ b/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/HookResultForOnPublish.java @@ -8,9 +8,9 @@ import lombok.Setter; @Getter public class HookResultForOnPublish extends HookResult{ - private boolean enable_audio; - private boolean enable_mp4; - private int mp4_max_second; + private Boolean enable_audio; + private Boolean enable_mp4; + private Integer mp4_max_second; private String mp4_save_path; private String stream_replace; private Integer modify_stamp; @@ -24,8 +24,8 @@ public class HookResultForOnPublish extends HookResult{ public static HookResultForOnPublish getInstance(ResultForOnPublish resultForOnPublish){ HookResultForOnPublish successResult = new HookResultForOnPublish(0, "success"); - successResult.setEnable_audio(resultForOnPublish.isEnable_audio()); - successResult.setEnable_mp4(resultForOnPublish.isEnable_mp4()); + successResult.setEnable_audio(resultForOnPublish.getEnable_audio()); + successResult.setEnable_mp4(resultForOnPublish.getEnable_mp4()); successResult.setModify_stamp(resultForOnPublish.getModify_stamp()); successResult.setStream_replace(resultForOnPublish.getStream_replace()); successResult.setMp4_max_second(resultForOnPublish.getMp4_max_second()); diff --git a/src/main/java/com/genersoft/iot/vmp/service/IReceiveRtpServerService.java b/src/main/java/com/genersoft/iot/vmp/service/IReceiveRtpServerService.java index f0987b4cd..b8e7cab30 100644 --- a/src/main/java/com/genersoft/iot/vmp/service/IReceiveRtpServerService.java +++ b/src/main/java/com/genersoft/iot/vmp/service/IReceiveRtpServerService.java @@ -2,6 +2,7 @@ package com.genersoft.iot.vmp.service; import com.genersoft.iot.vmp.gb28181.bean.*; import com.genersoft.iot.vmp.media.bean.MediaServer; +import com.genersoft.iot.vmp.media.bean.ResultForOnPublish; import com.genersoft.iot.vmp.media.event.hook.HookData; import com.genersoft.iot.vmp.service.bean.ErrorCallback; import com.genersoft.iot.vmp.service.bean.RTPServerParam; @@ -14,13 +15,15 @@ public interface IReceiveRtpServerService { ErrorCallback callback); SSRCInfo openGbRTPServerForPlay(MediaServer mediaServer, Device device, DeviceChannel channel, - String presetSSRC, ErrorCallback callback); + String presetSSRC, boolean record, ErrorCallback callback); SSRCInfo openGbRTPServerForPlayback(MediaServer mediaServer, Device device, DeviceChannel channel, String startTime, String endTime, ErrorCallback callback); SSRCInfo openGbRTPServerForDownload(MediaServer mediaServer, Device device, DeviceChannel channel, - ErrorCallback callback); + String startTime, String endTime, ErrorCallback callback); + + String getPlaybackStream(Device device, DeviceChannel channel, String startTime, String endTime); SSRCInfo openGbRTPServerForBroadcast(MediaServer mediaServer, Platform platform, CommonGBChannel channel, ErrorCallback callback); @@ -30,4 +33,10 @@ public interface IReceiveRtpServerService { void closeRTPServer(MediaServer mediaServer, String app, String stream); void closeRTPServerByMediaServerId(String mediaServerId, String app, String stream); + + void addAuthenticateInfoForGb28181Talk(MediaServer mediaServer, String streamId); + + void addAuthenticateInfo(String streamId, String streamReplace, Boolean enableAudio, Boolean enableMp4, Integer mp4MaxSecond); + + ResultForOnPublish getAuthenticateInfo(String streamId); } diff --git a/src/main/java/com/genersoft/iot/vmp/service/impl/MediaServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/service/impl/MediaServiceImpl.java index b8e380bc0..53ffe667c 100755 --- a/src/main/java/com/genersoft/iot/vmp/service/impl/MediaServiceImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/service/impl/MediaServiceImpl.java @@ -18,10 +18,7 @@ import com.genersoft.iot.vmp.jt1078.service.Ijt1078Service; import com.genersoft.iot.vmp.media.bean.MediaServer; import com.genersoft.iot.vmp.media.bean.ResultForOnPublish; import com.genersoft.iot.vmp.media.zlm.dto.StreamAuthorityInfo; -import com.genersoft.iot.vmp.service.IMediaService; -import com.genersoft.iot.vmp.service.IRecordPlanService; -import com.genersoft.iot.vmp.service.ISendRtpServerService; -import com.genersoft.iot.vmp.service.IUserService; +import com.genersoft.iot.vmp.service.*; import com.genersoft.iot.vmp.storager.IRedisCatchStorage; import com.genersoft.iot.vmp.streamProxy.bean.StreamProxy; import com.genersoft.iot.vmp.streamProxy.service.IStreamProxyService; @@ -72,7 +69,7 @@ public class MediaServiceImpl implements IMediaService { private Ijt1078PlayService jt1078PlayService; @Autowired - private ISendRtpServerService sendRtpServerService; + private IReceiveRtpServerService receiveRtpServerService; @Autowired @@ -95,23 +92,24 @@ public class MediaServiceImpl implements IMediaService { @Override public ResultForOnPublish authenticatePublish(MediaServer mediaServer, String app, String stream, String params) { - // 推流鉴权的处理 - if (!MediaStreamUtil.RTP_APP.equals(app)) { - if (MediaStreamUtil.GB28181_TALK.equals(app) || MediaStreamUtil.JT_TALK.equals(app)) { - ResultForOnPublish result = new ResultForOnPublish(); + + if (MediaStreamUtil.RTP_APP.equals(app)) { + return receiveRtpServerService.getAuthenticateInfo(stream); + }else { + ResultForOnPublish result = new ResultForOnPublish(); + // app 非 RTP_APP 的流, 如果是国标对讲或者广播则默认获取声音并且不录制, 其他的流先查询是否有代理配置,如果没有代理配置再进行鉴权 + if (MediaStreamUtil.GB28181_TALK.equals(app) || MediaStreamUtil.GB28181_BROADCAST.equals(app) || MediaStreamUtil.JT_TALK.equals(app)) { result.setEnable_mp4(false); result.setEnable_audio(true); return result; } - if ("mp4_record".equals(app) ) { - ResultForOnPublish result = new ResultForOnPublish(); + if (MediaStreamUtil.LOAD_MP4_APP.equals(app) ) { result.setEnable_mp4(false); result.setEnable_audio(true); return result; } StreamProxy streamProxyItem = streamProxyService.getStreamProxyByAppAndStream(app, stream); if (streamProxyItem != null) { - ResultForOnPublish result = new ResultForOnPublish(); result.setEnable_audio(streamProxyItem.isEnableAudio()); result.setEnable_mp4(streamProxyItem.isEnableMp4()); return result; @@ -144,90 +142,9 @@ public class MediaServiceImpl implements IMediaService { // 鉴权通过 redisCatchStorage.updateStreamAuthorityInfo(app, stream, streamAuthorityInfo); } - } - - - ResultForOnPublish result = new ResultForOnPublish(); - result.setEnable_audio(true); - - // RTP SERVER 收流 - if (MediaStreamUtil.isGB28181(app, stream)) { - InviteInfo inviteInfo = inviteStreamService.getInviteInfoByStream(null, stream); - - if (inviteInfo != null) { - result.setEnable_mp4(inviteInfo.getRecord()); - }else { - result.setEnable_mp4(userSetting.getRecordSip()); - } - - // 单端口模式下修改流 ID - if (!mediaServer.isRtpEnable() && inviteInfo == null) { - String ssrc = String.format("%010d", Long.parseLong(stream, 16)); - inviteInfo = inviteStreamService.getInviteInfoBySSRC(ssrc); - if (inviteInfo != null) { - result.setStream_replace(inviteInfo.getStream()); - log.info("[HOOK]推流鉴权 stream: {} 替换为 {}", stream, inviteInfo.getStream()); - stream = inviteInfo.getStream(); - } - } - - // 设置音频信息及录制信息 - SsrcTransaction ssrcTransaction = sessionManager.getSsrcTransactionByStream(app, stream); - if (ssrcTransaction != null ) { - - // 为录制国标模拟一个鉴权信息, 方便后续写入录像文件时使用 - StreamAuthorityInfo streamAuthorityInfo = StreamAuthorityInfo.getInstanceByHook(app, stream, mediaServer.getId()); - streamAuthorityInfo.setApp(app); - streamAuthorityInfo.setStream(ssrcTransaction.getStream()); - streamAuthorityInfo.setCallId(ssrcTransaction.getSipTransactionInfo().getCallId()); - - redisCatchStorage.updateStreamAuthorityInfo(app, ssrcTransaction.getStream(), streamAuthorityInfo); - - String deviceId = ssrcTransaction.getDeviceId(); - Integer channelId = ssrcTransaction.getChannelId(); - DeviceChannel deviceChannel = deviceChannelService.getOneForSourceById(channelId); - if (deviceChannel != null) { - result.setEnable_audio(deviceChannel.isHasAudio()); - } - // 如果是录像下载就设置视频间隔十秒 - if (ssrcTransaction.getType() == InviteSessionType.DOWNLOAD) { - // 获取录像的总时长,然后设置为这个视频的时长 - InviteInfo inviteInfoForDownload = inviteStreamService.getInviteInfo(InviteSessionType.DOWNLOAD, channelId, stream); - if (inviteInfoForDownload != null) { - String startTime = inviteInfoForDownload.getStartTime(); - String endTime = inviteInfoForDownload.getEndTime(); - long difference = DateUtil.getDifference(startTime, endTime) / 1000; - result.setMp4_max_second((int) difference); - result.setEnable_mp4(true); - // 设置为2保证得到的mp4的时长是正常的 - result.setModify_stamp(2); - } - } - // 如果是talk对讲,则默认获取声音 - if (ssrcTransaction.getType() == InviteSessionType.TALK) { - result.setEnable_audio(true); - } - } - } else if (app.equals(MediaStreamUtil.GB28181_BROADCAST)) { - result.setEnable_audio(true); - result.setEnable_mp4(userSetting.getRecordSip()); - } else if (app.equals(MediaStreamUtil.GB28181_TALK)) { - result.setEnable_audio(true); - result.setEnable_mp4(userSetting.getRecordSip()); - }else { result.setEnable_mp4(userSetting.getRecordPushLive()); + return result; } - if (app.equalsIgnoreCase(MediaStreamUtil.RTP_APP)) { - String receiveKey = VideoManagerConstants.WVP_OTHER_RECEIVE_RTP_INFO + userSetting.getServerId() + "_" + stream; - OtherRtpSendInfo otherRtpSendInfo = (OtherRtpSendInfo) redisTemplate.opsForValue().get(receiveKey); - - String receiveKeyForPS = VideoManagerConstants.WVP_OTHER_RECEIVE_PS_INFO + userSetting.getServerId() + "_" + stream; - OtherPsSendInfo otherPsSendInfo = (OtherPsSendInfo) redisTemplate.opsForValue().get(receiveKeyForPS); - if (otherRtpSendInfo != null || otherPsSendInfo != null) { - result.setEnable_mp4(true); - } - } - return result; } @Override @@ -269,7 +186,7 @@ public class MediaServiceImpl implements IMediaService { } }else if (MediaStreamUtil.GB28181_TALK.equals(app) || MediaStreamUtil.GB28181_BROADCAST.equals(app)) { return false; - } else if ("mp4_record".equals(app)) { + } else if (MediaStreamUtil.LOAD_MP4_APP.equals(app)) { return true; } else { // 非国标流 推流/拉流代理 diff --git a/src/main/java/com/genersoft/iot/vmp/service/impl/RtpServerServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/service/impl/RtpServerServiceImpl.java index 6fea42bb6..ea25a48a4 100644 --- a/src/main/java/com/genersoft/iot/vmp/service/impl/RtpServerServiceImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/service/impl/RtpServerServiceImpl.java @@ -7,6 +7,7 @@ import com.genersoft.iot.vmp.conf.UserSetting; import com.genersoft.iot.vmp.gb28181.bean.*; import com.genersoft.iot.vmp.gb28181.session.SSRCFactory; import com.genersoft.iot.vmp.media.bean.MediaServer; +import com.genersoft.iot.vmp.media.bean.ResultForOnPublish; import com.genersoft.iot.vmp.media.event.hook.Hook; import com.genersoft.iot.vmp.media.event.hook.HookData; import com.genersoft.iot.vmp.media.event.hook.HookSubscribe; @@ -14,12 +15,12 @@ import com.genersoft.iot.vmp.media.event.hook.HookType; import com.genersoft.iot.vmp.media.event.media.MediaArrivalEvent; import com.genersoft.iot.vmp.media.event.media.MediaDepartureEvent; import com.genersoft.iot.vmp.media.service.IMediaServerService; -import com.genersoft.iot.vmp.media.zlm.dto.hook.HookResultForOnPublish; import com.genersoft.iot.vmp.service.IReceiveRtpServerService; import com.genersoft.iot.vmp.service.bean.ErrorCallback; import com.genersoft.iot.vmp.service.bean.InviteErrorCode; import com.genersoft.iot.vmp.service.bean.RTPServerParam; import com.genersoft.iot.vmp.service.bean.SSRCInfo; +import com.genersoft.iot.vmp.utils.DateUtil; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.event.EventListener; @@ -132,7 +133,7 @@ public class RtpServerServiceImpl implements IReceiveRtpServerService { @Override public SSRCInfo openGbRTPServerForPlay(MediaServer mediaServer, Device device, DeviceChannel channel, - String presetSSRC, ErrorCallback callback) { + String presetSSRC, boolean record, ErrorCallback callback) { if (callback == null) { log.warn("[开启国标点播RTP收流] 失败,回调为NULL"); return null; @@ -142,9 +143,6 @@ public class RtpServerServiceImpl implements IReceiveRtpServerService { return null; } - String streamId = String.format("%s_%s", device.getDeviceId(), channel.getDeviceId()); - int tcpMode = device.getStreamMode().equals("TCP-ACTIVE")? 2: (device.getStreamMode().equals("TCP-PASSIVE")? 1:0); - // 获取 mediaServer 可用的 ssrc final String ssrc; if (presetSSRC != null) { @@ -152,6 +150,18 @@ public class RtpServerServiceImpl implements IReceiveRtpServerService { }else { ssrc = ssrcFactory.getPlaySsrc(mediaServer.getId()); } + + String streamId; + String streamReplace = null; + if (mediaServer.isRtpEnable()) { + streamId = String.format("%s_%s", device.getDeviceId(), channel.getDeviceId()); + }else { + streamId = String.format("%08x", Long.parseLong(ssrc)).toUpperCase(); + streamReplace = String.format("%s_%s", device.getDeviceId(), channel.getDeviceId()); + } + + int tcpMode = device.getStreamMode().equals("TCP-ACTIVE")? 2: (device.getStreamMode().equals("TCP-PASSIVE")? 1:0); + if (device.isSsrcCheck() && tcpMode > 0) { // 目前zlm不支持 tcp模式更新ssrc,暂时关闭ssrc校验 log.warn("[开启国标点播RTP收流] 平台对接时下级可能自定义ssrc,但是tcp模式zlm收流目前无法更新ssrc,可能收流超时,此时请使用udp收流或者关闭ssrc校验"); @@ -159,17 +169,18 @@ public class RtpServerServiceImpl implements IReceiveRtpServerService { Long checkSsrc = device.isSsrcCheck() ? Long.parseLong(ssrc) : 0L; - SSRCInfo ssrcInfo = new SSRCInfo(0, ssrc, MediaStreamUtil.RTP_APP, streamId); + SSRCInfo ssrcInfo = new SSRCInfo(0, ssrc, MediaStreamUtil.RTP_APP, streamReplace != null ? streamReplace : streamId); if (presetSSRC == null) { ssrcInfo.setAllocatedSsrc(ssrc); } openRtpServer(mediaServer, ssrcInfo, checkSsrc, !channel.isHasAudio(), false, tcpMode, callback); + addAuthenticateInfo(streamId, streamReplace, !channel.isHasAudio(), record, null); return ssrcInfo; } @Override public SSRCInfo openGbRTPServerForPlayback(MediaServer mediaServer, Device device, DeviceChannel channel, - String startTimeStr, String endTimeTimeStr, ErrorCallback callback) { + String startTime, String endTime, ErrorCallback callback) { if (callback == null) { log.warn("[开启国标回放RTP收流] 失败,回调为NULL"); return null; @@ -179,11 +190,19 @@ public class RtpServerServiceImpl implements IReceiveRtpServerService { return null; } - String streamId = device.getDeviceId() + "_" + channel.getDeviceId() + "_" + startTimeStr + "_" + endTimeTimeStr; - int tcpMode = device.getStreamMode().equals("TCP-ACTIVE")? 2: (device.getStreamMode().equals("TCP-PASSIVE")? 1:0); - // 获取 mediaServer 可用的 ssrc - final String ssrc = ssrcFactory.getPlayBackSsrc(mediaServer.getId()); + String ssrc = ssrcFactory.getPlayBackSsrc(mediaServer.getId()); + + String streamId; + String streamReplace = null; + if (mediaServer.isRtpEnable()) { + streamId = getPlaybackStream(device, channel, startTime, endTime); + }else { + streamId = String.format("%08x", Long.parseLong(ssrc)).toUpperCase(); + streamReplace = getPlaybackStream(device, channel, startTime, endTime); + } + + int tcpMode = device.getStreamMode().equals("TCP-ACTIVE")? 2: (device.getStreamMode().equals("TCP-PASSIVE")? 1:0); if (device.isSsrcCheck() && tcpMode > 0) { // 目前zlm不支持 tcp模式更新ssrc,暂时关闭ssrc校验 @@ -192,15 +211,28 @@ public class RtpServerServiceImpl implements IReceiveRtpServerService { Long checkSsrc = device.isSsrcCheck() ? Long.parseLong(ssrc) : 0L; - SSRCInfo ssrcInfo = new SSRCInfo(0, ssrc, MediaStreamUtil.RTP_APP, streamId); + SSRCInfo ssrcInfo = new SSRCInfo(0, ssrc, MediaStreamUtil.RTP_APP, streamReplace != null ? streamReplace : streamId); ssrcInfo.setAllocatedSsrc(ssrc); openRtpServer(mediaServer, ssrcInfo, checkSsrc, !channel.isHasAudio(), false, tcpMode, callback); + addAuthenticateInfo(streamId, streamReplace, !channel.isHasAudio(), false,null); return ssrcInfo; } + @Override + public String getPlaybackStream(Device device, DeviceChannel channel, String startTime, String endTime) { + String startTimeStr = startTime.replace("-", "") + .replace(":", "") + .replace(" ", ""); + String endTimeTimeStr = endTime.replace("-", "") + .replace(":", "") + .replace(" ", ""); + + return device.getDeviceId() + "_" + channel.getDeviceId() + "_" + startTimeStr + "_" + endTimeTimeStr; + } + @Override public SSRCInfo openGbRTPServerForDownload(MediaServer mediaServer, Device device, DeviceChannel channel, - ErrorCallback callback) { + String startTime, String endTime, ErrorCallback callback) { if (callback == null) { log.warn("[开启国标录像下载RTP收流] 失败,回调为NULL"); return null; @@ -213,8 +245,8 @@ public class RtpServerServiceImpl implements IReceiveRtpServerService { int tcpMode = device.getStreamMode().equals("TCP-ACTIVE")? 2: (device.getStreamMode().equals("TCP-PASSIVE")? 1:0); // 获取 mediaServer 可用的 ssrc - String ssrc = ssrcFactory.getPlaySsrc(mediaServer.getId()); - String streamId = String.format("%08x", Long.parseLong(ssrc)).toUpperCase();; + String ssrc = ssrcFactory.getPlayBackSsrc(mediaServer.getId()); + String streamId = String.format("%08x", Long.parseLong(ssrc)).toUpperCase(); if (device.isSsrcCheck() && tcpMode > 0) { // 目前zlm不支持 tcp模式更新ssrc,暂时关闭ssrc校验 log.warn("[开启国标录像下载RTP收流] 平台对接时下级可能自定义ssrc,但是tcp模式zlm收流目前无法更新ssrc,可能收流超时,此时请使用udp收流或者关闭ssrc校验"); @@ -225,6 +257,10 @@ public class RtpServerServiceImpl implements IReceiveRtpServerService { SSRCInfo ssrcInfo = new SSRCInfo(0, ssrc, MediaStreamUtil.RTP_APP, streamId); ssrcInfo.setAllocatedSsrc(ssrc); openRtpServer(mediaServer, ssrcInfo, checkSsrc, !channel.isHasAudio(), false, tcpMode, callback); + + long difference = DateUtil.getDifference(startTime, endTime) / 1000; + + addAuthenticateInfo(streamId, null, !channel.isHasAudio(), true, (int) difference); return ssrcInfo; } @@ -257,7 +293,6 @@ public class RtpServerServiceImpl implements IReceiveRtpServerService { // 获取 mediaServer 可用的 ssrc String ssrc = ssrcFactory.getPlaySsrc(mediaServer.getId()); - SSRCInfo ssrcInfo = new SSRCInfo(0, ssrc, MediaStreamUtil.RTP_APP, streamId); ssrcInfo.setAllocatedSsrc(ssrc); openRtpServer(mediaServer, ssrcInfo, 0L, false, true, tcpMode, callback); @@ -354,29 +389,38 @@ public class RtpServerServiceImpl implements IReceiveRtpServerService { closeRTPServer(mediaServer, app, stream); } - private void addAuthenticateInfoForGb28181(MediaServer mediaServer, String streamId, Boolean enableMp4, Boolean enableAudio, String mapSavePath, Integer modifyStamp) { + @Override + public void addAuthenticateInfoForGb28181Talk(MediaServer mediaServer, String streamId) { String streamReplace = null; if (!mediaServer.isRtpEnable() ) { streamReplace = streamId; } - addAuthenticateInfo(streamId, streamReplace, enableAudio, enableMp4, mapSavePath, modifyStamp); + addAuthenticateInfo(streamId, streamReplace, true, false, null); } - private void addAuthenticateInfo(String streamId, String streamReplace, Boolean enableAudio, Boolean enableMp4, String mapSavePath, Integer modifyStamp) { - HookResultForOnPublish hookResultForOnPublish = new HookResultForOnPublish(); - hookResultForOnPublish.setCode(0); - hookResultForOnPublish.setMsg("success"); + @Override + public void addAuthenticateInfo(String streamId, String streamReplace, Boolean enableAudio, Boolean enableMp4, Integer mp4MaxSecond) { + ResultForOnPublish hookResultForOnPublish = new ResultForOnPublish(); hookResultForOnPublish.setStream_replace(streamReplace); hookResultForOnPublish.setEnable_audio(enableAudio); hookResultForOnPublish.setEnable_mp4(enableMp4); - hookResultForOnPublish.setMp4_save_path(mapSavePath); - hookResultForOnPublish.setModify_stamp(modifyStamp); + hookResultForOnPublish.setMp4_max_second(mp4MaxSecond); String key = String.format("%s:%s", VideoManagerConstants.RTP_AUTHENTICATE, streamId); // 存储认证信息,过期时间为60秒, 过期则无法通过认证 redisTemplate.opsForValue().set(key, hookResultForOnPublish); redisTemplate.expire(key, 60, TimeUnit.SECONDS); } + + @Override + public ResultForOnPublish getAuthenticateInfo(String streamId) { + String key = String.format("%s:%s", VideoManagerConstants.RTP_AUTHENTICATE, streamId); + Object obj = redisTemplate.opsForValue().get(key); + if (obj instanceof ResultForOnPublish) { + return (ResultForOnPublish) obj; + } + return null; + } } diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/ps/PsController.java b/src/main/java/com/genersoft/iot/vmp/vmanager/ps/PsController.java index 057398ddd..3d053fc57 100755 --- a/src/main/java/com/genersoft/iot/vmp/vmanager/ps/PsController.java +++ b/src/main/java/com/genersoft/iot/vmp/vmanager/ps/PsController.java @@ -133,6 +133,10 @@ public class PsController { if (rtpServerPort == 0) { throw new ControllerException(ErrorCode.ERROR100.getCode(), "获取端口失败"); } + + // 补充鉴权参数 + receiveRtpServerService.addAuthenticateInfo(stream, null, false, false, null); + OtherPsSendInfo otherPsSendInfo = new OtherPsSendInfo(); otherPsSendInfo.setReceiveIp(mediaServer.getSdpIp()); otherPsSendInfo.setReceivePort(rtpServerPort); diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/rtp/RtpController.java b/src/main/java/com/genersoft/iot/vmp/vmanager/rtp/RtpController.java index e7085ec2b..d8f130a89 100755 --- a/src/main/java/com/genersoft/iot/vmp/vmanager/rtp/RtpController.java +++ b/src/main/java/com/genersoft/iot/vmp/vmanager/rtp/RtpController.java @@ -126,7 +126,8 @@ public class RtpController { log.info("[开启收流和获取发流信息] 视频流收流失败,callId->{},stream->{}", callId, stream); } })); - + // 补充鉴权参数 + receiveRtpServerService.addAuthenticateInfo(stream, null, false, false, null); rtpServerParam.setStreamId(stream + "_a"); int rtpServerPortForAudio = receiveRtpServerService.openCommonRTPServer(rtpServerParam, ((code, msg, data) -> { @@ -136,6 +137,10 @@ public class RtpController { log.info("[开启收流和获取发流信息] 音频流收流失败,callId->{},stream->{}", callId, stream); } })); + + // 补充鉴权参数 + receiveRtpServerService.addAuthenticateInfo(rtpServerParam.getStreamId(), null, true, false, null); + if (rtpServerPortForVideo == 0 || rtpServerPortForAudio == 0) { throw new ControllerException(ErrorCode.ERROR100.getCode(), "获取端口失败"); } diff --git a/web/src/api/jtDevice.js b/web/src/api/jtDevice.js index 4f5210cb7..c6222dc5f 100644 --- a/web/src/api/jtDevice.js +++ b/web/src/api/jtDevice.js @@ -157,7 +157,7 @@ export function startPlayback(params) { const { phoneNumber, channelId, startTime, endTime, type, rate, playbackType, playbackSpeed } = params return request({ method: 'get', - url: '/api/jt1078/playback/start/', + url: '/api/jt1078/playback/start', params: { phoneNumber: phoneNumber, channelId: channelId,