diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/InviteStreamType.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/InviteStreamType.java index 24d509fd..677dcd71 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/InviteStreamType.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/InviteStreamType.java @@ -2,7 +2,7 @@ package com.genersoft.iot.vmp.gb28181.bean; public enum InviteStreamType { - PLAY,PLAYBACK,PUSH,PROXY,CLOUD_RECORD_PUSH,CLOUD_RECORD_PROXY + PLAY,PLAYBACK,DOWNLOAD,PUSH,PROXY,CLOUD_RECORD_PUSH,CLOUD_RECORD_PROXY } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java index 88de9635..a9b64ca2 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java @@ -540,7 +540,7 @@ public class SIPCommander implements ISIPCommander { content.append("y=" + ssrcInfo.getSsrc() + "\r\n");//ssrc logger.debug("此时请求下载信令的ssrc===>{}",ssrcInfo.getSsrc()); - HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", ssrcInfo.getStream(), true, null, mediaServerItem.getId()); + HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", ssrcInfo.getStream(), true, "rtsp", mediaServerItem.getId()); // 添加订阅 CallIdHeader newCallIdHeader = sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()), device.getTransport()); String callId= newCallIdHeader.getCallId(); diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java index 44f03495..f2e0698c 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java @@ -429,8 +429,10 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements InviteErrorCallback errorEvent = ((statusCode, msg, data) -> { // 未知错误。直接转发设备点播的错误 try { - Response response = getMessageFactory().createResponse(statusCode, evt.getRequest()); - sipSender.transmitRequest(request.getLocalAddress().getHostAddress(), response); + if (statusCode > 0) { + Response response = getMessageFactory().createResponse(statusCode, evt.getRequest()); + sipSender.transmitRequest(request.getLocalAddress().getHostAddress(), response); + } } catch (ParseException | SipException e) { logger.error("未处理的异常 ", e); } @@ -455,7 +457,37 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements errorEvent.run(code, msg, data); } }); - } else { + }else if ("Download".equalsIgnoreCase(sessionName)) { + // 获取指定的下载速度 + Vector sdpMediaDescriptions = sdp.getMediaDescriptions(true); + MediaDescription mediaDescription = null; + String downloadSpeed = "1"; + if (sdpMediaDescriptions.size() > 0) { + mediaDescription = (MediaDescription)sdpMediaDescriptions.get(0); + } + if (mediaDescription != null) { + downloadSpeed = mediaDescription.getAttribute("downloadspeed"); + } + + sendRtpItem.setPlayType(InviteStreamType.DOWNLOAD); + SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, null, null, device.isSsrcCheck(), true, 0, false, device.getStreamModeForParam()); + sendRtpItem.setStreamId(ssrcInfo.getStream()); + // 写入redis, 超时时回复 + redisCatchStorage.updateSendRTPSever(sendRtpItem); + playService.download(mediaServerItem, ssrcInfo, device.getDeviceId(), channelId, DateUtil.formatter.format(start), + DateUtil.formatter.format(end), Integer.parseInt(downloadSpeed), + (code, msg, data) -> { + if (code == InviteErrorCode.SUCCESS.getCode()){ + hookEvent.run(code, msg, data); + }else if (code == InviteErrorCode.ERROR_FOR_SIGNALLING_TIMEOUT.getCode() || code == InviteErrorCode.ERROR_FOR_STREAM_TIMEOUT.getCode()){ + logger.info("[录像下载]超时, 用户:{}, 通道:{}", username, channelId); + redisCatchStorage.deleteSendRTPServer(platform.getServerGBId(), channelId, callIdHeader.getCallId(), null); + errorEvent.run(code, msg, data); + }else { + errorEvent.run(code, msg, data); + } + }); + }else { sendRtpItem.setPlayType(InviteStreamType.PLAY); String streamId = null; if (mediaServerItem.isRtpEnable()) { diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java index fae90fe9..637f5efc 100644 --- a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java +++ b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java @@ -438,7 +438,7 @@ public class ZLMHttpHookListener { @PostMapping(value = "/on_stream_none_reader", produces = "application/json;charset=UTF-8") public JSONObject onStreamNoneReader(@RequestBody OnStreamNoneReaderHookParam param) { - logger.info("[ZLM HOOK]流无人观看:{]->{}->{}/{}" + param.getMediaServerId(), param.getSchema(), + logger.info("[ZLM HOOK]流无人观看:{}->{}->{}/{}", param.getMediaServerId(), param.getSchema(), param.getApp(), param.getStream()); JSONObject ret = new JSONObject(); ret.put("code", 0); diff --git a/src/main/java/com/genersoft/iot/vmp/service/impl/DeviceServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/service/impl/DeviceServiceImpl.java index b171c71c..a0d120c6 100644 --- a/src/main/java/com/genersoft/iot/vmp/service/impl/DeviceServiceImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/service/impl/DeviceServiceImpl.java @@ -501,8 +501,10 @@ public class DeviceServiceImpl implements IDeviceService { node.setBasicData(channel); node.setParent(false); if (channel.getChannelId().length() > 8) { - String gbCodeType = channel.getChannelId().substring(10, 13); - node.setParent(gbCodeType.equals(ChannelIdType.BUSINESS_GROUP) || gbCodeType.equals(ChannelIdType.VIRTUAL_ORGANIZATION) ); + if (channel.getChannelId().length() > 13) { + String gbCodeType = channel.getChannelId().substring(10, 13); + node.setParent(gbCodeType.equals(ChannelIdType.BUSINESS_GROUP) || gbCodeType.equals(ChannelIdType.VIRTUAL_ORGANIZATION) ); + } }else { node.setParent(true); } diff --git a/src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java index 879e9ca6..661a2ec7 100644 --- a/src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java @@ -757,7 +757,7 @@ public class PlayServiceImpl implements IPlayService { null); return; } - logger.info("[录像下载] deviceId: {}, channelId: {},收流端口:{}, 收流模式:{}, SSRC: {}, SSRC校验:{}", device.getDeviceId(), channelId, ssrcInfo.getPort(), device.getStreamMode(), ssrcInfo.getSsrc(), device.isSsrcCheck()); + logger.info("[录像下载] deviceId: {}, channelId: {}, 下载速度:{}, 收流端口:{}, 收流模式:{}, SSRC: {}, SSRC校验:{}", device.getDeviceId(), channelId, downloadSpeed, ssrcInfo.getPort(), device.getStreamMode(), ssrcInfo.getSsrc(), device.isSsrcCheck()); // 初始化redis中的invite消息状态 InviteInfo inviteInfo = InviteInfo.getinviteInfo(device.getDeviceId(), channelId, ssrcInfo.getStream(), ssrcInfo, mediaServerItem.getSdpIp(), ssrcInfo.getPort(), device.getStreamMode(), InviteSessionType.DOWNLOAD, @@ -888,7 +888,6 @@ public class PlayServiceImpl implements IPlayService { cmder.streamByeCmd(device, channelId, ssrcInfo.getStream(), null, null); } catch (InvalidArgumentException | SipException | ParseException | SsrcTransactionNotFoundException e) { logger.error("[命令发送失败] 停止点播, 发送BYE: {}", e.getMessage()); - } dynamicTask.stop(downLoadTimeOutTaskKey); @@ -970,10 +969,12 @@ public class PlayServiceImpl implements IPlayService { private StreamInfo onPublishHandlerForDownload(MediaServerItem mediaServerItemInuse, JSONObject response, String deviceId, String channelId, String startTime, String endTime) { StreamInfo streamInfo = onPublishHandler(mediaServerItemInuse, response, deviceId, channelId); if (streamInfo != null) { + streamInfo.setProgress(0); streamInfo.setStartTime(startTime); streamInfo.setEndTime(endTime); - InviteInfo inviteInfo = inviteStreamService.getInviteInfoByDeviceAndChannel(InviteSessionType.DOWNLOAD, deviceId, channelId); + InviteInfo inviteInfo = inviteStreamService.getInviteInfo(InviteSessionType.DOWNLOAD, deviceId, channelId, streamInfo.getStream()); if (inviteInfo != null) { + logger.info("[录像下载] 更新invite消息中的stream信息"); inviteInfo.setStatus(InviteSessionStatus.ok); inviteInfo.setStreamInfo(streamInfo); inviteStreamService.updateInviteInfo(inviteInfo); diff --git a/web_src/src/components/GBRecordDetail.vue b/web_src/src/components/GBRecordDetail.vue index 6fe29a89..f9fce20d 100644 --- a/web_src/src/components/GBRecordDetail.vue +++ b/web_src/src/components/GBRecordDetail.vue @@ -182,9 +182,11 @@ this.playerStyle["height"] = this.winHeight + "px"; this.chooseDate = moment().format('YYYY-MM-DD') this.dateChange(); + window.addEventListener('beforeunload', this.stopPlayRecord) }, destroyed() { this.$destroy('recordVideoPlayer'); + window.removeEventListener('beforeunload', this.stopPlayRecord) }, methods: { dateChange(){ @@ -338,14 +340,18 @@ }); }, stopPlayRecord: function (callback) { - this.$refs["recordVideoPlayer"].pause(); - this.videoUrl = ''; - this.$axios({ - method: 'get', - url: '/api/playback/stop/' + this.deviceId + "/" + this.channelId + "/" + this.streamId - }).then(function (res) { - if (callback) callback() - }); + console.log("停止录像回放") + if (this.streamId !== "") { + this.$refs["recordVideoPlayer"].pause(); + this.videoUrl = ''; + this.$axios({ + method: 'get', + url: '/api/playback/stop/' + this.deviceId + "/" + this.channelId + "/" + this.streamId + }).then(function (res) { + if (callback) callback() + }); + } + }, getDataWidth(item){ let timeForFile = this.getTimeForFile(item); @@ -423,8 +429,14 @@ return hStr + ":" + mStr + ":" + sStr }, goBack(){ + // 如果正在进行录像回放则,发送停止 + if (this.streamId !== "") { + this.stopPlayRecord(()=> { + this.streamId = ""; + }) + } window.history.go(-1); - } + }, } }; diff --git a/web_src/src/components/dialog/recordDownload.vue b/web_src/src/components/dialog/recordDownload.vue index c90cf138..ea44353a 100644 --- a/web_src/src/components/dialog/recordDownload.vue +++ b/web_src/src/components/dialog/recordDownload.vue @@ -21,7 +21,7 @@ import moment from "moment"; export default { name: 'recordDownload', created() { - + window.addEventListener('beforeunload', this.stopDownloadRecord) }, data() { @@ -197,6 +197,9 @@ export default { console.log(error); }); } + }, + destroyed() { + window.removeEventListener('beforeunload', this.stopDownloadRecord) } };