Commit a2da81f79a40f275704e10789903ffe85d0c0be8

Authored by 648540858
1 parent affbd89f

支持级联国标录像下载

src/main/java/com/genersoft/iot/vmp/gb28181/bean/InviteStreamType.java
@@ -2,7 +2,7 @@ package com.genersoft.iot.vmp.gb28181.bean; @@ -2,7 +2,7 @@ package com.genersoft.iot.vmp.gb28181.bean;
2 2
3 public enum InviteStreamType { 3 public enum InviteStreamType {
4 4
5 - PLAY,PLAYBACK,PUSH,PROXY,CLOUD_RECORD_PUSH,CLOUD_RECORD_PROXY 5 + PLAY,PLAYBACK,DOWNLOAD,PUSH,PROXY,CLOUD_RECORD_PUSH,CLOUD_RECORD_PROXY
6 6
7 7
8 } 8 }
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java
@@ -540,7 +540,7 @@ public class SIPCommander implements ISIPCommander { @@ -540,7 +540,7 @@ public class SIPCommander implements ISIPCommander {
540 540
541 content.append("y=" + ssrcInfo.getSsrc() + "\r\n");//ssrc 541 content.append("y=" + ssrcInfo.getSsrc() + "\r\n");//ssrc
542 logger.debug("此时请求下载信令的ssrc===>{}",ssrcInfo.getSsrc()); 542 logger.debug("此时请求下载信令的ssrc===>{}",ssrcInfo.getSsrc());
543 - HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", ssrcInfo.getStream(), true, null, mediaServerItem.getId()); 543 + HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", ssrcInfo.getStream(), true, "rtsp", mediaServerItem.getId());
544 // 添加订阅 544 // 添加订阅
545 CallIdHeader newCallIdHeader = sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()), device.getTransport()); 545 CallIdHeader newCallIdHeader = sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()), device.getTransport());
546 String callId= newCallIdHeader.getCallId(); 546 String callId= newCallIdHeader.getCallId();
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java
@@ -429,8 +429,10 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -429,8 +429,10 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
429 InviteErrorCallback<Object> errorEvent = ((statusCode, msg, data) -> { 429 InviteErrorCallback<Object> errorEvent = ((statusCode, msg, data) -> {
430 // 未知错误。直接转发设备点播的错误 430 // 未知错误。直接转发设备点播的错误
431 try { 431 try {
432 - Response response = getMessageFactory().createResponse(statusCode, evt.getRequest());  
433 - sipSender.transmitRequest(request.getLocalAddress().getHostAddress(), response); 432 + if (statusCode > 0) {
  433 + Response response = getMessageFactory().createResponse(statusCode, evt.getRequest());
  434 + sipSender.transmitRequest(request.getLocalAddress().getHostAddress(), response);
  435 + }
434 } catch (ParseException | SipException e) { 436 } catch (ParseException | SipException e) {
435 logger.error("未处理的异常 ", e); 437 logger.error("未处理的异常 ", e);
436 } 438 }
@@ -455,7 +457,37 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -455,7 +457,37 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
455 errorEvent.run(code, msg, data); 457 errorEvent.run(code, msg, data);
456 } 458 }
457 }); 459 });
458 - } else { 460 + }else if ("Download".equalsIgnoreCase(sessionName)) {
  461 + // 获取指定的下载速度
  462 + Vector sdpMediaDescriptions = sdp.getMediaDescriptions(true);
  463 + MediaDescription mediaDescription = null;
  464 + String downloadSpeed = "1";
  465 + if (sdpMediaDescriptions.size() > 0) {
  466 + mediaDescription = (MediaDescription)sdpMediaDescriptions.get(0);
  467 + }
  468 + if (mediaDescription != null) {
  469 + downloadSpeed = mediaDescription.getAttribute("downloadspeed");
  470 + }
  471 +
  472 + sendRtpItem.setPlayType(InviteStreamType.DOWNLOAD);
  473 + SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, null, null, device.isSsrcCheck(), true, 0, false, device.getStreamModeForParam());
  474 + sendRtpItem.setStreamId(ssrcInfo.getStream());
  475 + // 写入redis, 超时时回复
  476 + redisCatchStorage.updateSendRTPSever(sendRtpItem);
  477 + playService.download(mediaServerItem, ssrcInfo, device.getDeviceId(), channelId, DateUtil.formatter.format(start),
  478 + DateUtil.formatter.format(end), Integer.parseInt(downloadSpeed),
  479 + (code, msg, data) -> {
  480 + if (code == InviteErrorCode.SUCCESS.getCode()){
  481 + hookEvent.run(code, msg, data);
  482 + }else if (code == InviteErrorCode.ERROR_FOR_SIGNALLING_TIMEOUT.getCode() || code == InviteErrorCode.ERROR_FOR_STREAM_TIMEOUT.getCode()){
  483 + logger.info("[录像下载]超时, 用户:{}, 通道:{}", username, channelId);
  484 + redisCatchStorage.deleteSendRTPServer(platform.getServerGBId(), channelId, callIdHeader.getCallId(), null);
  485 + errorEvent.run(code, msg, data);
  486 + }else {
  487 + errorEvent.run(code, msg, data);
  488 + }
  489 + });
  490 + }else {
459 sendRtpItem.setPlayType(InviteStreamType.PLAY); 491 sendRtpItem.setPlayType(InviteStreamType.PLAY);
460 String streamId = null; 492 String streamId = null;
461 if (mediaServerItem.isRtpEnable()) { 493 if (mediaServerItem.isRtpEnable()) {
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java
@@ -438,7 +438,7 @@ public class ZLMHttpHookListener { @@ -438,7 +438,7 @@ public class ZLMHttpHookListener {
438 @PostMapping(value = "/on_stream_none_reader", produces = "application/json;charset=UTF-8") 438 @PostMapping(value = "/on_stream_none_reader", produces = "application/json;charset=UTF-8")
439 public JSONObject onStreamNoneReader(@RequestBody OnStreamNoneReaderHookParam param) { 439 public JSONObject onStreamNoneReader(@RequestBody OnStreamNoneReaderHookParam param) {
440 440
441 - logger.info("[ZLM HOOK]流无人观看:{]->{}->{}/{}" + param.getMediaServerId(), param.getSchema(), 441 + logger.info("[ZLM HOOK]流无人观看:{}->{}->{}/{}", param.getMediaServerId(), param.getSchema(),
442 param.getApp(), param.getStream()); 442 param.getApp(), param.getStream());
443 JSONObject ret = new JSONObject(); 443 JSONObject ret = new JSONObject();
444 ret.put("code", 0); 444 ret.put("code", 0);
src/main/java/com/genersoft/iot/vmp/service/impl/DeviceServiceImpl.java
@@ -501,8 +501,10 @@ public class DeviceServiceImpl implements IDeviceService { @@ -501,8 +501,10 @@ public class DeviceServiceImpl implements IDeviceService {
501 node.setBasicData(channel); 501 node.setBasicData(channel);
502 node.setParent(false); 502 node.setParent(false);
503 if (channel.getChannelId().length() > 8) { 503 if (channel.getChannelId().length() > 8) {
504 - String gbCodeType = channel.getChannelId().substring(10, 13);  
505 - node.setParent(gbCodeType.equals(ChannelIdType.BUSINESS_GROUP) || gbCodeType.equals(ChannelIdType.VIRTUAL_ORGANIZATION) ); 504 + if (channel.getChannelId().length() > 13) {
  505 + String gbCodeType = channel.getChannelId().substring(10, 13);
  506 + node.setParent(gbCodeType.equals(ChannelIdType.BUSINESS_GROUP) || gbCodeType.equals(ChannelIdType.VIRTUAL_ORGANIZATION) );
  507 + }
506 }else { 508 }else {
507 node.setParent(true); 509 node.setParent(true);
508 } 510 }
src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java
@@ -757,7 +757,7 @@ public class PlayServiceImpl implements IPlayService { @@ -757,7 +757,7 @@ public class PlayServiceImpl implements IPlayService {
757 null); 757 null);
758 return; 758 return;
759 } 759 }
760 - logger.info("[录像下载] deviceId: {}, channelId: {},收流端口:{}, 收流模式:{}, SSRC: {}, SSRC校验:{}", device.getDeviceId(), channelId, ssrcInfo.getPort(), device.getStreamMode(), ssrcInfo.getSsrc(), device.isSsrcCheck()); 760 + logger.info("[录像下载] deviceId: {}, channelId: {}, 下载速度:{}, 收流端口:{}, 收流模式:{}, SSRC: {}, SSRC校验:{}", device.getDeviceId(), channelId, downloadSpeed, ssrcInfo.getPort(), device.getStreamMode(), ssrcInfo.getSsrc(), device.isSsrcCheck());
761 // 初始化redis中的invite消息状态 761 // 初始化redis中的invite消息状态
762 InviteInfo inviteInfo = InviteInfo.getinviteInfo(device.getDeviceId(), channelId, ssrcInfo.getStream(), ssrcInfo, 762 InviteInfo inviteInfo = InviteInfo.getinviteInfo(device.getDeviceId(), channelId, ssrcInfo.getStream(), ssrcInfo,
763 mediaServerItem.getSdpIp(), ssrcInfo.getPort(), device.getStreamMode(), InviteSessionType.DOWNLOAD, 763 mediaServerItem.getSdpIp(), ssrcInfo.getPort(), device.getStreamMode(), InviteSessionType.DOWNLOAD,
@@ -888,7 +888,6 @@ public class PlayServiceImpl implements IPlayService { @@ -888,7 +888,6 @@ public class PlayServiceImpl implements IPlayService {
888 cmder.streamByeCmd(device, channelId, ssrcInfo.getStream(), null, null); 888 cmder.streamByeCmd(device, channelId, ssrcInfo.getStream(), null, null);
889 } catch (InvalidArgumentException | SipException | ParseException | SsrcTransactionNotFoundException e) { 889 } catch (InvalidArgumentException | SipException | ParseException | SsrcTransactionNotFoundException e) {
890 logger.error("[命令发送失败] 停止点播, 发送BYE: {}", e.getMessage()); 890 logger.error("[命令发送失败] 停止点播, 发送BYE: {}", e.getMessage());
891 -  
892 } 891 }
893 892
894 dynamicTask.stop(downLoadTimeOutTaskKey); 893 dynamicTask.stop(downLoadTimeOutTaskKey);
@@ -970,10 +969,12 @@ public class PlayServiceImpl implements IPlayService { @@ -970,10 +969,12 @@ public class PlayServiceImpl implements IPlayService {
970 private StreamInfo onPublishHandlerForDownload(MediaServerItem mediaServerItemInuse, JSONObject response, String deviceId, String channelId, String startTime, String endTime) { 969 private StreamInfo onPublishHandlerForDownload(MediaServerItem mediaServerItemInuse, JSONObject response, String deviceId, String channelId, String startTime, String endTime) {
971 StreamInfo streamInfo = onPublishHandler(mediaServerItemInuse, response, deviceId, channelId); 970 StreamInfo streamInfo = onPublishHandler(mediaServerItemInuse, response, deviceId, channelId);
972 if (streamInfo != null) { 971 if (streamInfo != null) {
  972 + streamInfo.setProgress(0);
973 streamInfo.setStartTime(startTime); 973 streamInfo.setStartTime(startTime);
974 streamInfo.setEndTime(endTime); 974 streamInfo.setEndTime(endTime);
975 - InviteInfo inviteInfo = inviteStreamService.getInviteInfoByDeviceAndChannel(InviteSessionType.DOWNLOAD, deviceId, channelId); 975 + InviteInfo inviteInfo = inviteStreamService.getInviteInfo(InviteSessionType.DOWNLOAD, deviceId, channelId, streamInfo.getStream());
976 if (inviteInfo != null) { 976 if (inviteInfo != null) {
  977 + logger.info("[录像下载] 更新invite消息中的stream信息");
977 inviteInfo.setStatus(InviteSessionStatus.ok); 978 inviteInfo.setStatus(InviteSessionStatus.ok);
978 inviteInfo.setStreamInfo(streamInfo); 979 inviteInfo.setStreamInfo(streamInfo);
979 inviteStreamService.updateInviteInfo(inviteInfo); 980 inviteStreamService.updateInviteInfo(inviteInfo);
web_src/src/components/GBRecordDetail.vue
@@ -182,9 +182,11 @@ @@ -182,9 +182,11 @@
182 this.playerStyle["height"] = this.winHeight + "px"; 182 this.playerStyle["height"] = this.winHeight + "px";
183 this.chooseDate = moment().format('YYYY-MM-DD') 183 this.chooseDate = moment().format('YYYY-MM-DD')
184 this.dateChange(); 184 this.dateChange();
  185 + window.addEventListener('beforeunload', this.stopPlayRecord)
185 }, 186 },
186 destroyed() { 187 destroyed() {
187 this.$destroy('recordVideoPlayer'); 188 this.$destroy('recordVideoPlayer');
  189 + window.removeEventListener('beforeunload', this.stopPlayRecord)
188 }, 190 },
189 methods: { 191 methods: {
190 dateChange(){ 192 dateChange(){
@@ -338,14 +340,18 @@ @@ -338,14 +340,18 @@
338 }); 340 });
339 }, 341 },
340 stopPlayRecord: function (callback) { 342 stopPlayRecord: function (callback) {
341 - this.$refs["recordVideoPlayer"].pause();  
342 - this.videoUrl = '';  
343 - this.$axios({  
344 - method: 'get',  
345 - url: '/api/playback/stop/' + this.deviceId + "/" + this.channelId + "/" + this.streamId  
346 - }).then(function (res) {  
347 - if (callback) callback()  
348 - }); 343 + console.log("停止录像回放")
  344 + if (this.streamId !== "") {
  345 + this.$refs["recordVideoPlayer"].pause();
  346 + this.videoUrl = '';
  347 + this.$axios({
  348 + method: 'get',
  349 + url: '/api/playback/stop/' + this.deviceId + "/" + this.channelId + "/" + this.streamId
  350 + }).then(function (res) {
  351 + if (callback) callback()
  352 + });
  353 + }
  354 +
349 }, 355 },
350 getDataWidth(item){ 356 getDataWidth(item){
351 let timeForFile = this.getTimeForFile(item); 357 let timeForFile = this.getTimeForFile(item);
@@ -423,8 +429,14 @@ @@ -423,8 +429,14 @@
423 return hStr + ":" + mStr + ":" + sStr 429 return hStr + ":" + mStr + ":" + sStr
424 }, 430 },
425 goBack(){ 431 goBack(){
  432 + // 如果正在进行录像回放则,发送停止
  433 + if (this.streamId !== "") {
  434 + this.stopPlayRecord(()=> {
  435 + this.streamId = "";
  436 + })
  437 + }
426 window.history.go(-1); 438 window.history.go(-1);
427 - } 439 + },
428 } 440 }
429 }; 441 };
430 </script> 442 </script>
web_src/src/components/dialog/recordDownload.vue
@@ -21,7 +21,7 @@ import moment from &quot;moment&quot;; @@ -21,7 +21,7 @@ import moment from &quot;moment&quot;;
21 export default { 21 export default {
22 name: 'recordDownload', 22 name: 'recordDownload',
23 created() { 23 created() {
24 - 24 + window.addEventListener('beforeunload', this.stopDownloadRecord)
25 25
26 }, 26 },
27 data() { 27 data() {
@@ -197,6 +197,9 @@ export default { @@ -197,6 +197,9 @@ export default {
197 console.log(error); 197 console.log(error);
198 }); 198 });
199 } 199 }
  200 + },
  201 + destroyed() {
  202 + window.removeEventListener('beforeunload', this.stopDownloadRecord)
200 } 203 }
201 }; 204 };
202 </script> 205 </script>