Commit d46fc9de827fe85a48f447cf1550444573a6f1a5

Authored by 648540858
1 parent 1f02cb91

优化下级平台自定义ssrc的情况,优化国标录像下载流程

src/main/java/com/genersoft/iot/vmp/common/CommonCallback.java 0 → 100644
  1 +package com.genersoft.iot.vmp.common;
  2 +
  3 +public interface CommonCallback<T>{
  4 + public void run(T t);
  5 +}
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java
@@ -546,7 +546,7 @@ public class SIPCommander implements ISIPCommander { @@ -546,7 +546,7 @@ public class SIPCommander implements ISIPCommander {
546 HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", ssrcInfo.getStream(), true, null, mediaServerItem.getId()); 546 HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", ssrcInfo.getStream(), true, null, mediaServerItem.getId());
547 // 添加订阅 547 // 添加订阅
548 CallIdHeader newCallIdHeader = sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()), device.getTransport()); 548 CallIdHeader newCallIdHeader = sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()), device.getTransport());
549 - String callId=newCallIdHeader.getCallId(); 549 + String callId= newCallIdHeader.getCallId();
550 subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, JSONObject json) -> { 550 subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, JSONObject json) -> {
551 logger.debug("sipc 添加订阅===callId {}",callId); 551 logger.debug("sipc 添加订阅===callId {}",callId);
552 hookEvent.call(new InviteStreamInfo(mediaServerItem, json,callId, "rtp", ssrcInfo.getStream())); 552 hookEvent.call(new InviteStreamInfo(mediaServerItem, json,callId, "rtp", ssrcInfo.getStream()));
@@ -558,7 +558,7 @@ public class SIPCommander implements ISIPCommander { @@ -558,7 +558,7 @@ public class SIPCommander implements ISIPCommander {
558 (MediaServerItem mediaServerItemForEnd, JSONObject jsonForEnd) -> { 558 (MediaServerItem mediaServerItemForEnd, JSONObject jsonForEnd) -> {
559 logger.info("[录像]下载结束, 发送BYE"); 559 logger.info("[录像]下载结束, 发送BYE");
560 try { 560 try {
561 - streamByeCmd(device, channelId, ssrcInfo.getStream(),callId); 561 + streamByeCmd(device, channelId, ssrcInfo.getStream(), callId);
562 } catch (InvalidArgumentException | ParseException | SipException | 562 } catch (InvalidArgumentException | ParseException | SipException |
563 SsrcTransactionNotFoundException e) { 563 SsrcTransactionNotFoundException e) {
564 logger.error("[录像]下载结束, 发送BYE失败 {}", e.getMessage()); 564 logger.error("[录像]下载结束, 发送BYE失败 {}", e.getMessage());
@@ -580,8 +580,6 @@ public class SIPCommander implements ISIPCommander { @@ -580,8 +580,6 @@ public class SIPCommander implements ISIPCommander {
580 if (ssrcIndex >= 0) { 580 if (ssrcIndex >= 0) {
581 ssrc = contentString.substring(ssrcIndex + 2, ssrcIndex + 12); 581 ssrc = contentString.substring(ssrcIndex + 2, ssrcIndex + 12);
582 } 582 }
583 - logger.debug("接收到的下载响应ssrc====>{}",ssrcInfo.getSsrc());  
584 - logger.debug("接收到的下载响应ssrc====>{}",ssrc);  
585 streamSession.put(device.getDeviceId(), channelId, response.getCallIdHeader().getCallId(), ssrcInfo.getStream(), ssrc, mediaServerItem.getId(), response, VideoStreamSessionManager.SessionType.download); 583 streamSession.put(device.getDeviceId(), channelId, response.getCallIdHeader().getCallId(), ssrcInfo.getStream(), ssrc, mediaServerItem.getId(), response, VideoStreamSessionManager.SessionType.download);
586 okEvent.response(event); 584 okEvent.response(event);
587 }); 585 });
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/MediaStatusNotifyMessageHandler.java
@@ -12,6 +12,9 @@ import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform; @@ -12,6 +12,9 @@ import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform;
12 import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent; 12 import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
13 import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler; 13 import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler;
14 import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.notify.NotifyMessageHandler; 14 import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.notify.NotifyMessageHandler;
  15 +import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe;
  16 +import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeFactory;
  17 +import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForStreamChange;
15 import com.genersoft.iot.vmp.storager.IRedisCatchStorage; 18 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
16 import com.genersoft.iot.vmp.storager.IVideoManagerStorage; 19 import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
17 import gov.nist.javax.sip.message.SIPRequest; 20 import gov.nist.javax.sip.message.SIPRequest;
@@ -58,6 +61,9 @@ public class MediaStatusNotifyMessageHandler extends SIPRequestProcessorParent i @@ -58,6 +61,9 @@ public class MediaStatusNotifyMessageHandler extends SIPRequestProcessorParent i
58 @Autowired 61 @Autowired
59 private VideoStreamSessionManager sessionManager; 62 private VideoStreamSessionManager sessionManager;
60 63
  64 + @Autowired
  65 + private ZlmHttpHookSubscribe subscribe;
  66 +
61 @Override 67 @Override
62 public void afterPropertiesSet() throws Exception { 68 public void afterPropertiesSet() throws Exception {
63 notifyMessageHandler.addHandler(cmdType, this); 69 notifyMessageHandler.addHandler(cmdType, this);
@@ -93,6 +99,9 @@ public class MediaStatusNotifyMessageHandler extends SIPRequestProcessorParent i @@ -93,6 +99,9 @@ public class MediaStatusNotifyMessageHandler extends SIPRequestProcessorParent i
93 } catch (InvalidArgumentException | ParseException | SsrcTransactionNotFoundException | SipException e) { 99 } catch (InvalidArgumentException | ParseException | SsrcTransactionNotFoundException | SipException e) {
94 logger.error("[录像流]推送完毕,收到关流通知, 发送BYE失败 {}", e.getMessage()); 100 logger.error("[录像流]推送完毕,收到关流通知, 发送BYE失败 {}", e.getMessage());
95 } 101 }
  102 + // 去除监听流注销自动停止下载的监听
  103 + HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", ssrcTransaction.getStream(), false, "rtsp", ssrcTransaction.getMediaServerId());
  104 + subscribe.removeSubscribe(hookSubscribe);
96 105
97 // 如果级联播放,需要给上级发送此通知 TODO 多个上级同时观看一个下级 可能存在停错的问题,需要将点播CallId进行上下级绑定 106 // 如果级联播放,需要给上级发送此通知 TODO 多个上级同时观看一个下级 可能存在停错的问题,需要将点播CallId进行上下级绑定
98 SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(null, ssrcTransaction.getChannelId(), null, null); 107 SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(null, ssrcTransaction.getChannelId(), null, null);
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRESTfulUtils.java
@@ -276,6 +276,10 @@ public class ZLMRESTfulUtils { @@ -276,6 +276,10 @@ public class ZLMRESTfulUtils {
276 return sendPost(mediaServerItem, "closeRtpServer",param, null); 276 return sendPost(mediaServerItem, "closeRtpServer",param, null);
277 } 277 }
278 278
  279 + public void closeRtpServer(MediaServerItem mediaServerItem, Map<String, Object> param, RequestCallback callback) {
  280 + sendPost(mediaServerItem, "closeRtpServer",param, callback);
  281 + }
  282 +
279 public JSONObject listRtpServer(MediaServerItem mediaServerItem) { 283 public JSONObject listRtpServer(MediaServerItem mediaServerItem) {
280 return sendPost(mediaServerItem, "listRtpServer",null, null); 284 return sendPost(mediaServerItem, "listRtpServer",null, null);
281 } 285 }
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRTPServerFactory.java
@@ -3,6 +3,7 @@ package com.genersoft.iot.vmp.media.zlm; @@ -3,6 +3,7 @@ package com.genersoft.iot.vmp.media.zlm;
3 import com.alibaba.fastjson2.JSON; 3 import com.alibaba.fastjson2.JSON;
4 import com.alibaba.fastjson2.JSONArray; 4 import com.alibaba.fastjson2.JSONArray;
5 import com.alibaba.fastjson2.JSONObject; 5 import com.alibaba.fastjson2.JSONObject;
  6 +import com.genersoft.iot.vmp.common.CommonCallback;
6 import com.genersoft.iot.vmp.conf.UserSetting; 7 import com.genersoft.iot.vmp.conf.UserSetting;
7 import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem; 8 import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
8 import com.genersoft.iot.vmp.media.zlm.dto.*; 9 import com.genersoft.iot.vmp.media.zlm.dto.*;
@@ -164,6 +165,31 @@ public class ZLMRTPServerFactory { @@ -164,6 +165,31 @@ public class ZLMRTPServerFactory {
164 return result; 165 return result;
165 } 166 }
166 167
  168 + public void closeRtpServer(MediaServerItem serverItem, String streamId, CommonCallback<Boolean> callback) {
  169 + if (serverItem == null) {
  170 + callback.run(false);
  171 + return;
  172 + }
  173 + Map<String, Object> param = new HashMap<>();
  174 + param.put("stream_id", streamId);
  175 + zlmresTfulUtils.closeRtpServer(serverItem, param, jsonObject -> {
  176 + if (jsonObject != null ) {
  177 + if (jsonObject.getInteger("code") == 0) {
  178 + callback.run(jsonObject.getInteger("hit") == 1);
  179 + return;
  180 + }else {
  181 + logger.error("关闭RTP Server 失败: " + jsonObject.getString("msg"));
  182 + }
  183 + }else {
  184 + // 检查ZLM状态
  185 + logger.error("关闭RTP Server 失败: 请检查ZLM服务");
  186 + }
  187 + callback.run(false);
  188 + });
  189 +
  190 +
  191 + }
  192 +
167 193
168 /** 194 /**
169 * 创建一个国标推流 195 * 创建一个国标推流
src/main/java/com/genersoft/iot/vmp/service/IMediaServerService.java
1 package com.genersoft.iot.vmp.service; 1 package com.genersoft.iot.vmp.service;
2 2
  3 +import com.genersoft.iot.vmp.common.CommonCallback;
3 import com.genersoft.iot.vmp.media.zlm.ZLMServerConfig; 4 import com.genersoft.iot.vmp.media.zlm.ZLMServerConfig;
4 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; 5 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
5 import com.genersoft.iot.vmp.media.zlm.dto.ServerKeepaliveData; 6 import com.genersoft.iot.vmp.media.zlm.dto.ServerKeepaliveData;
@@ -51,6 +52,8 @@ public interface IMediaServerService { @@ -51,6 +52,8 @@ public interface IMediaServerService {
51 52
52 void closeRTPServer(MediaServerItem mediaServerItem, String streamId); 53 void closeRTPServer(MediaServerItem mediaServerItem, String streamId);
53 54
  55 + void closeRTPServer(MediaServerItem mediaServerItem, String streamId, CommonCallback<Boolean> callback);
  56 +
54 void closeRTPServer(String mediaServerId, String streamId); 57 void closeRTPServer(String mediaServerId, String streamId);
55 58
56 void clearRTPServer(MediaServerItem mediaServerItem); 59 void clearRTPServer(MediaServerItem mediaServerItem);
src/main/java/com/genersoft/iot/vmp/service/impl/MediaServerServiceImpl.java
@@ -3,6 +3,7 @@ package com.genersoft.iot.vmp.service.impl; @@ -3,6 +3,7 @@ package com.genersoft.iot.vmp.service.impl;
3 import com.alibaba.fastjson2.JSON; 3 import com.alibaba.fastjson2.JSON;
4 import com.alibaba.fastjson2.JSONArray; 4 import com.alibaba.fastjson2.JSONArray;
5 import com.alibaba.fastjson2.JSONObject; 5 import com.alibaba.fastjson2.JSONObject;
  6 +import com.genersoft.iot.vmp.common.CommonCallback;
6 import com.genersoft.iot.vmp.common.VideoManagerConstants; 7 import com.genersoft.iot.vmp.common.VideoManagerConstants;
7 import com.genersoft.iot.vmp.conf.DynamicTask; 8 import com.genersoft.iot.vmp.conf.DynamicTask;
8 import com.genersoft.iot.vmp.conf.SipConfig; 9 import com.genersoft.iot.vmp.conf.SipConfig;
@@ -173,6 +174,15 @@ public class MediaServerServiceImpl implements IMediaServerService { @@ -173,6 +174,15 @@ public class MediaServerServiceImpl implements IMediaServerService {
173 } 174 }
174 175
175 @Override 176 @Override
  177 + public void closeRTPServer(MediaServerItem mediaServerItem, String streamId, CommonCallback<Boolean> callback) {
  178 + if (mediaServerItem == null) {
  179 + callback.run(false);
  180 + return;
  181 + }
  182 + zlmrtpServerFactory.closeRtpServer(mediaServerItem, streamId, callback);
  183 + }
  184 +
  185 + @Override
176 public void closeRTPServer(String mediaServerId, String streamId) { 186 public void closeRTPServer(String mediaServerId, String streamId) {
177 MediaServerItem mediaServerItem = this.getOne(mediaServerId); 187 MediaServerItem mediaServerItem = this.getOne(mediaServerId);
178 closeRTPServer(mediaServerItem, streamId); 188 closeRTPServer(mediaServerItem, streamId);
src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java
@@ -328,9 +328,30 @@ public class PlayServiceImpl implements IPlayService { @@ -328,9 +328,30 @@ public class PlayServiceImpl implements IPlayService {
328 }); 328 });
329 } 329 }
330 // 关闭rtp server 330 // 关闭rtp server
331 - mediaServerService.closeRTPServer(mediaServerItem, ssrcInfo.getStream());  
332 - // 重新开启ssrc server  
333 - mediaServerService.openRTPServer(mediaServerItem, ssrcInfo.getStream(), ssrcInResponse, device.isSsrcCheck(), false, ssrcInfo.getPort()); 331 + mediaServerService.closeRTPServer(mediaServerItem, ssrcInfo.getStream(), result->{
  332 + if (result) {
  333 + // 重新开启ssrc server
  334 + mediaServerService.openRTPServer(mediaServerItem, ssrcInfo.getStream(), ssrcInResponse, device.isSsrcCheck(), false, ssrcInfo.getPort());
  335 + }else {
  336 + try {
  337 + logger.warn("[停止点播] {}/{}", device.getDeviceId(), channelId);
  338 + cmder.streamByeCmd(device, channelId, ssrcInfo.getStream(), null, null);
  339 + } catch (InvalidArgumentException | SipException | ParseException | SsrcTransactionNotFoundException e) {
  340 + logger.error("[命令发送失败] 停止点播, 发送BYE: {}", e.getMessage());
  341 + throw new ControllerException(ErrorCode.ERROR100.getCode(), "命令发送失败: " + e.getMessage());
  342 + }
  343 +
  344 + dynamicTask.stop(timeOutTaskKey);
  345 + // 释放ssrc
  346 + mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
  347 +
  348 + streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream());
  349 + event.msg = "下级自定义了ssrc,重新设置收流信息失败";
  350 + event.statusCode = 500;
  351 + errorEvent.response(event);
  352 + }
  353 + });
  354 +
334 355
335 } 356 }
336 } 357 }
@@ -472,7 +493,7 @@ public class PlayServiceImpl implements IPlayService { @@ -472,7 +493,7 @@ public class PlayServiceImpl implements IPlayService {
472 if (device == null) { 493 if (device == null) {
473 throw new ControllerException(ErrorCode.ERROR100.getCode(), "设备: " + deviceId + "不存在"); 494 throw new ControllerException(ErrorCode.ERROR100.getCode(), "设备: " + deviceId + "不存在");
474 } 495 }
475 - 496 + logger.info("[回放消息] deviceId: {}, channelId: {},收流端口: {}, 收流模式:{}, SSRC: {}, SSRC校验:{}", device.getDeviceId(), channelId, ssrcInfo.getPort(), device.getStreamMode(), ssrcInfo.getSsrc(), device.isSsrcCheck());
476 PlayBackResult<StreamInfo> playBackResult = new PlayBackResult<>(); 497 PlayBackResult<StreamInfo> playBackResult = new PlayBackResult<>();
477 String playBackTimeOutTaskKey = UUID.randomUUID().toString(); 498 String playBackTimeOutTaskKey = UUID.randomUUID().toString();
478 dynamicTask.startDelay(playBackTimeOutTaskKey, () -> { 499 dynamicTask.startDelay(playBackTimeOutTaskKey, () -> {
@@ -546,6 +567,7 @@ public class PlayServiceImpl implements IPlayService { @@ -546,6 +567,7 @@ public class PlayServiceImpl implements IPlayService {
546 if (!ssrcFactory.checkSsrc(mediaServerItem.getId(),ssrcInResponse)) { 567 if (!ssrcFactory.checkSsrc(mediaServerItem.getId(),ssrcInResponse)) {
547 // ssrc 不可用 568 // ssrc 不可用
548 // 释放ssrc 569 // 释放ssrc
  570 + dynamicTask.stop(playBackTimeOutTaskKey);
549 mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc()); 571 mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
550 streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream()); 572 streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream());
551 eventResult.msg = "下级自定义了ssrc,但是此ssrc不可用"; 573 eventResult.msg = "下级自定义了ssrc,但是此ssrc不可用";
@@ -568,10 +590,31 @@ public class PlayServiceImpl implements IPlayService { @@ -568,10 +590,31 @@ public class PlayServiceImpl implements IPlayService {
568 hookEvent.call(new InviteStreamInfo(mediaServerItem, null, eventResult.callId, "rtp", ssrcInfo.getStream())); 590 hookEvent.call(new InviteStreamInfo(mediaServerItem, null, eventResult.callId, "rtp", ssrcInfo.getStream()));
569 }); 591 });
570 } 592 }
  593 +
571 // 关闭rtp server 594 // 关闭rtp server
572 - mediaServerService.closeRTPServer(mediaServerItem, ssrcInfo.getStream());  
573 - // 重新开启ssrc server  
574 - mediaServerService.openRTPServer(mediaServerItem, ssrcInfo.getStream(), ssrcInResponse, device.isSsrcCheck(), true, ssrcInfo.getPort()); 595 + mediaServerService.closeRTPServer(mediaServerItem, ssrcInfo.getStream(), result->{
  596 + if (result) {
  597 + // 重新开启ssrc server
  598 + mediaServerService.openRTPServer(mediaServerItem, ssrcInfo.getStream(), ssrcInResponse, device.isSsrcCheck(), true, ssrcInfo.getPort());
  599 + }else {
  600 + try {
  601 + logger.warn("[回放消息]停止 {}/{}", device.getDeviceId(), channelId);
  602 + cmder.streamByeCmd(device, channelId, ssrcInfo.getStream(), null, null);
  603 + } catch (InvalidArgumentException | SipException | ParseException | SsrcTransactionNotFoundException e) {
  604 + logger.error("[命令发送失败] 停止点播 停止, 发送BYE: {}", e.getMessage());
  605 + throw new ControllerException(ErrorCode.ERROR100.getCode(), "命令发送失败: " + e.getMessage());
  606 + }
  607 +
  608 + dynamicTask.stop(playBackTimeOutTaskKey);
  609 + // 释放ssrc
  610 + mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
  611 + streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream());
  612 + errorEvent.response(eventResult);
  613 + eventResult.msg = "下级自定义了ssrc,重新设置收流信息失败";
  614 + eventResult.statusCode = 500;
  615 + errorEvent.response(eventResult);
  616 + }
  617 + });
575 } 618 }
576 } 619 }
577 } 620 }
@@ -619,7 +662,7 @@ public class PlayServiceImpl implements IPlayService { @@ -619,7 +662,7 @@ public class PlayServiceImpl implements IPlayService {
619 throw new ControllerException(ErrorCode.ERROR400.getCode(), "设备:" + deviceId + "不存在"); 662 throw new ControllerException(ErrorCode.ERROR400.getCode(), "设备:" + deviceId + "不存在");
620 } 663 }
621 PlayBackResult<StreamInfo> downloadResult = new PlayBackResult<>(); 664 PlayBackResult<StreamInfo> downloadResult = new PlayBackResult<>();
622 - 665 + logger.info("[录像下载] deviceId: {}, channelId: {},收流端口: {}, 收流模式:{}, SSRC: {}, SSRC校验:{}", device.getDeviceId(), channelId, ssrcInfo.getPort(), device.getStreamMode(), ssrcInfo.getSsrc(), device.isSsrcCheck());
623 String downLoadTimeOutTaskKey = UUID.randomUUID().toString(); 666 String downLoadTimeOutTaskKey = UUID.randomUUID().toString();
624 dynamicTask.startDelay(downLoadTimeOutTaskKey, () -> { 667 dynamicTask.startDelay(downLoadTimeOutTaskKey, () -> {
625 logger.warn(String.format("录像下载请求超时,deviceId:%s ,channelId:%s", deviceId, channelId)); 668 logger.warn(String.format("录像下载请求超时,deviceId:%s ,channelId:%s", deviceId, channelId));
@@ -648,7 +691,7 @@ public class PlayServiceImpl implements IPlayService { @@ -648,7 +691,7 @@ public class PlayServiceImpl implements IPlayService {
648 streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream()); 691 streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream());
649 }; 692 };
650 InviteStreamCallback hookEvent = (InviteStreamInfo inviteStreamInfo) -> { 693 InviteStreamCallback hookEvent = (InviteStreamInfo inviteStreamInfo) -> {
651 - logger.info("收到订阅消息: " + inviteStreamInfo.getCallId()); 694 + logger.info("[录像下载]收到订阅消息: " + inviteStreamInfo.getCallId());
652 dynamicTask.stop(downLoadTimeOutTaskKey); 695 dynamicTask.stop(downLoadTimeOutTaskKey);
653 StreamInfo streamInfo = onPublishHandler(inviteStreamInfo.getMediaServerItem(), inviteStreamInfo.getResponse(), deviceId, channelId); 696 StreamInfo streamInfo = onPublishHandler(inviteStreamInfo.getMediaServerItem(), inviteStreamInfo.getResponse(), deviceId, channelId);
654 streamInfo.setStartTime(startTime); 697 streamInfo.setStartTime(startTime);
@@ -678,9 +721,9 @@ public class PlayServiceImpl implements IPlayService { @@ -678,9 +721,9 @@ public class PlayServiceImpl implements IPlayService {
678 if (ssrcInfo.getSsrc().equals(ssrcInResponse)) { 721 if (ssrcInfo.getSsrc().equals(ssrcInResponse)) {
679 return; 722 return;
680 } 723 }
681 - logger.info("[回放消息] 收到invite 200, 发现下级自定义了ssrc: {}", ssrcInResponse); 724 + logger.info("[录像下载] 收到invite 200, 发现下级自定义了ssrc: {}", ssrcInResponse);
682 if (!mediaServerItem.isRtpEnable() || device.isSsrcCheck()) { 725 if (!mediaServerItem.isRtpEnable() || device.isSsrcCheck()) {
683 - logger.info("[回放消息] SSRC修正 {}->{}", ssrcInfo.getSsrc(), ssrcInResponse); 726 + logger.info("[录像下载] SSRC修正 {}->{}", ssrcInfo.getSsrc(), ssrcInResponse);
684 727
685 if (!ssrcFactory.checkSsrc(mediaServerItem.getId(),ssrcInResponse)) { 728 if (!ssrcFactory.checkSsrc(mediaServerItem.getId(),ssrcInResponse)) {
686 // ssrc 不可用 729 // ssrc 不可用
@@ -707,14 +750,34 @@ public class PlayServiceImpl implements IPlayService { @@ -707,14 +750,34 @@ public class PlayServiceImpl implements IPlayService {
707 hookEvent.call(new InviteStreamInfo(mediaServerItem, null, eventResult.callId, "rtp", ssrcInfo.getStream())); 750 hookEvent.call(new InviteStreamInfo(mediaServerItem, null, eventResult.callId, "rtp", ssrcInfo.getStream()));
708 }); 751 });
709 } 752 }
  753 +
710 // 关闭rtp server 754 // 关闭rtp server
711 - mediaServerService.closeRTPServer(mediaServerItem, ssrcInfo.getStream());  
712 - // 重新开启ssrc server  
713 - mediaServerService.openRTPServer(mediaServerItem, ssrcInfo.getStream(), ssrcInResponse, device.isSsrcCheck(), true, ssrcInfo.getPort()); 755 + mediaServerService.closeRTPServer(mediaServerItem, ssrcInfo.getStream(), result->{
  756 + if (result) {
  757 + // 重新开启ssrc server
  758 + mediaServerService.openRTPServer(mediaServerItem, ssrcInfo.getStream(), ssrcInResponse, device.isSsrcCheck(), true, ssrcInfo.getPort());
  759 + }else {
  760 + try {
  761 + logger.warn("[录像下载] 停止{}/{}", device.getDeviceId(), channelId);
  762 + cmder.streamByeCmd(device, channelId, ssrcInfo.getStream(), null, null);
  763 + } catch (InvalidArgumentException | SipException | ParseException | SsrcTransactionNotFoundException e) {
  764 + logger.error("[命令发送失败] 录像下载停止, 发送BYE: {}", e.getMessage());
  765 + throw new ControllerException(ErrorCode.ERROR100.getCode(), "命令发送失败: " + e.getMessage());
  766 + }
  767 +
  768 + dynamicTask.stop(downLoadTimeOutTaskKey);
  769 + // 释放ssrc
  770 + mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
  771 +
  772 + streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream());
  773 + eventResult.msg = "下级自定义了ssrc,重新设置收流信息失败";
  774 + eventResult.statusCode = 500;
  775 + errorEvent.response(eventResult);
  776 + }
  777 + });
714 } 778 }
715 } 779 }
716 } 780 }
717 -  
718 }); 781 });
719 } catch (InvalidArgumentException | SipException | ParseException e) { 782 } catch (InvalidArgumentException | SipException | ParseException e) {
720 logger.error("[命令发送失败] 录像下载: {}", e.getMessage()); 783 logger.error("[命令发送失败] 录像下载: {}", e.getMessage());
web_src/src/components/dialog/recordDownload.vue
@@ -96,7 +96,10 @@ export default { @@ -96,7 +96,10 @@ export default {
96 }); 96 });
97 }, 97 },
98 close: function (){ 98 close: function (){
99 - this.stopDownloadRecord(); 99 + if (this.streamInfo.progress < 1) {
  100 + this.stopDownloadRecord();
  101 + }
  102 +
100 if (this.timer !== null) { 103 if (this.timer !== null) {
101 window.clearTimeout(this.timer); 104 window.clearTimeout(this.timer);
102 this.timer = null; 105 this.timer = null;