|  | @@ -28,14 +28,10 @@ import com.genersoft.iot.vmp.media.event.media.MediaArrivalEvent;
 | 
	
		
			
				|  |  |  import com.genersoft.iot.vmp.media.event.media.MediaDepartureEvent;
 | 
	
		
			
				|  |  |  import com.genersoft.iot.vmp.media.event.media.MediaNotFoundEvent;
 | 
	
		
			
				|  |  |  import com.genersoft.iot.vmp.media.service.IMediaServerService;
 | 
	
		
			
				|  |  | -import com.genersoft.iot.vmp.media.zlm.SendRtpPortManager;
 | 
	
		
			
				|  |  | +import com.genersoft.iot.vmp.service.IReceiveRtpServerService;
 | 
	
		
			
				|  |  |  import com.genersoft.iot.vmp.service.ISendRtpServerService;
 | 
	
		
			
				|  |  | -import com.genersoft.iot.vmp.service.bean.DownloadFileInfo;
 | 
	
		
			
				|  |  | -import com.genersoft.iot.vmp.service.bean.ErrorCallback;
 | 
	
		
			
				|  |  | -import com.genersoft.iot.vmp.service.bean.InviteErrorCode;
 | 
	
		
			
				|  |  | -import com.genersoft.iot.vmp.service.bean.SSRCInfo;
 | 
	
		
			
				|  |  | +import com.genersoft.iot.vmp.service.bean.*;
 | 
	
		
			
				|  |  |  import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
 | 
	
		
			
				|  |  | -import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
 | 
	
		
			
				|  |  |  import com.genersoft.iot.vmp.utils.CloudRecordUtils;
 | 
	
		
			
				|  |  |  import com.genersoft.iot.vmp.utils.DateUtil;
 | 
	
		
			
				|  |  |  import com.genersoft.iot.vmp.vmanager.bean.AudioBroadcastResult;
 | 
	
	
		
			
				|  | @@ -71,11 +67,6 @@ import java.util.Vector;
 | 
	
		
			
				|  |  |  @DS("master")
 | 
	
		
			
				|  |  |  public class PlayServiceImpl implements IPlayService {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    @Autowired
 | 
	
		
			
				|  |  | -    private IVideoManagerStorage storager;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |      @Autowired
 | 
	
		
			
				|  |  |      private ISIPCommander cmder;
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -97,9 +88,6 @@ public class PlayServiceImpl implements IPlayService {
 | 
	
		
			
				|  |  |      @Autowired
 | 
	
		
			
				|  |  |      private HookSubscribe subscribe;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    @Autowired
 | 
	
		
			
				|  |  | -    private SendRtpPortManager sendRtpPortManager;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |      @Autowired
 | 
	
		
			
				|  |  |      private IMediaServerService mediaServerService;
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -130,6 +118,9 @@ public class PlayServiceImpl implements IPlayService {
 | 
	
		
			
				|  |  |      @Autowired
 | 
	
		
			
				|  |  |      private ISendRtpServerService sendRtpServerService;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +    @Autowired
 | 
	
		
			
				|  |  | +    private IReceiveRtpServerService receiveRtpServerService;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |      /**
 | 
	
		
			
				|  |  |       * 流到来的处理
 | 
	
		
			
				|  |  |       */
 | 
	
	
		
			
				|  | @@ -279,10 +270,7 @@ public class PlayServiceImpl implements IPlayService {
 | 
	
		
			
				|  |  |                      startTime, endTime
 | 
	
		
			
				|  |  |              );
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -            int tcpMode = device.getStreamMode().equals("TCP-ACTIVE")? 2: (device.getStreamMode().equals("TCP-PASSIVE")? 1:0);
 | 
	
		
			
				|  |  | -            SSRCInfo ssrcInfo = mediaServerService.openRTPServer(event.getMediaServer(), event.getStream(), null,
 | 
	
		
			
				|  |  | -                    device.isSsrcCheck(), true, 0, false, !deviceChannel.isHasAudio(), false, tcpMode);
 | 
	
		
			
				|  |  | -            playBack(event.getMediaServer(), ssrcInfo, device, deviceChannel, startTime, endTime, null);
 | 
	
		
			
				|  |  | +            playBack(event.getMediaServer(), device, deviceChannel, startTime, endTime, null);
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -341,21 +329,130 @@ public class PlayServiceImpl implements IPlayService {
 | 
	
		
			
				|  |  |                  }
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  | -        String streamId = String.format("%s_%s", device.getDeviceId(), channelId);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        return play(mediaServerItem, device, channel, ssrc, callback);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    private SSRCInfo play(MediaServer mediaServerItem, Device device, DeviceChannel channel, String ssrc,
 | 
	
		
			
				|  |  | +                      ErrorCallback<StreamInfo> callback) {
 | 
	
		
			
				|  |  | +        if (mediaServerItem == null ) {
 | 
	
		
			
				|  |  | +            if (callback != null) {
 | 
	
		
			
				|  |  | +                callback.run(InviteErrorCode.ERROR_FOR_PARAMETER_ERROR.getCode(),
 | 
	
		
			
				|  |  | +                        InviteErrorCode.ERROR_FOR_PARAMETER_ERROR.getMsg(),
 | 
	
		
			
				|  |  | +                        null);
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +            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);
 | 
	
		
			
				|  |  | -        SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, streamId, ssrc, device.isSsrcCheck(),  false, 0, false, !channel.isHasAudio(), false, tcpMode);
 | 
	
		
			
				|  |  | -        if (ssrcInfo == null) {
 | 
	
		
			
				|  |  | -            callback.run(InviteErrorCode.ERROR_FOR_RESOURCE_EXHAUSTION.getCode(), InviteErrorCode.ERROR_FOR_RESOURCE_EXHAUSTION.getMsg(), null);
 | 
	
		
			
				|  |  | +        RTPServerParam rtpServerParam = new RTPServerParam();
 | 
	
		
			
				|  |  | +        rtpServerParam.setMediaServerItem(mediaServerItem);
 | 
	
		
			
				|  |  | +        rtpServerParam.setStreamId(streamId);
 | 
	
		
			
				|  |  | +        rtpServerParam.setPresetSsrc(ssrc);
 | 
	
		
			
				|  |  | +        rtpServerParam.setSsrcCheck(device.isSsrcCheck());
 | 
	
		
			
				|  |  | +        rtpServerParam.setPlayback(false);
 | 
	
		
			
				|  |  | +        rtpServerParam.setPort(0);
 | 
	
		
			
				|  |  | +        rtpServerParam.setTcpMode(tcpMode);
 | 
	
		
			
				|  |  | +        rtpServerParam.setOnlyAuto(false);
 | 
	
		
			
				|  |  | +        rtpServerParam.setDisableAudio(!channel.isHasAudio());
 | 
	
		
			
				|  |  | +        SSRCInfo ssrcInfo = receiveRtpServerService.openRTPServer(rtpServerParam, (code, msg, hookData) -> {
 | 
	
		
			
				|  |  | +            if (code == InviteErrorCode.SUCCESS.getCode()) {
 | 
	
		
			
				|  |  | +                // hook响应
 | 
	
		
			
				|  |  | +                StreamInfo streamInfo = onPublishHandlerForPlay(hookData.getMediaServer(), hookData.getMediaInfo(), device, channel);
 | 
	
		
			
				|  |  | +                if (streamInfo == null){
 | 
	
		
			
				|  |  | +                    if (callback != null) {
 | 
	
		
			
				|  |  | +                        callback.run(InviteErrorCode.ERROR_FOR_STREAM_PARSING_EXCEPTIONS.getCode(),
 | 
	
		
			
				|  |  | +                                InviteErrorCode.ERROR_FOR_STREAM_PARSING_EXCEPTIONS.getMsg(), null);
 | 
	
		
			
				|  |  | +                    }
 | 
	
		
			
				|  |  | +                    inviteStreamService.call(InviteSessionType.PLAY, channel.getId(), null,
 | 
	
		
			
				|  |  | +                            InviteErrorCode.ERROR_FOR_STREAM_PARSING_EXCEPTIONS.getCode(),
 | 
	
		
			
				|  |  | +                            InviteErrorCode.ERROR_FOR_STREAM_PARSING_EXCEPTIONS.getMsg(), null);
 | 
	
		
			
				|  |  | +                    return;
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +                if (callback != null) {
 | 
	
		
			
				|  |  | +                    callback.run(InviteErrorCode.SUCCESS.getCode(), InviteErrorCode.SUCCESS.getMsg(), streamInfo);
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +                inviteStreamService.call(InviteSessionType.PLAY, channel.getId(), null,
 | 
	
		
			
				|  |  | +                        InviteErrorCode.SUCCESS.getCode(),
 | 
	
		
			
				|  |  | +                        InviteErrorCode.SUCCESS.getMsg(),
 | 
	
		
			
				|  |  | +                        streamInfo);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                log.info("[点播成功] deviceId: {}, channelId:{}, 码流类型:{}", device.getDeviceId(), channel.getDeviceId(),
 | 
	
		
			
				|  |  | +                        channel.getStreamIdentification());
 | 
	
		
			
				|  |  | +                snapOnPlay(hookData.getMediaServer(), device.getDeviceId(), channel.getDeviceId(), streamId);
 | 
	
		
			
				|  |  | +            }else {
 | 
	
		
			
				|  |  | +                if (callback != null) {
 | 
	
		
			
				|  |  | +                    callback.run(code, msg, null);
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +                inviteStreamService.call(InviteSessionType.PLAY, channel.getId(), null, code, msg, null);
 | 
	
		
			
				|  |  | +                inviteStreamService.removeInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, channel.getId());
 | 
	
		
			
				|  |  | +                SsrcTransaction ssrcTransaction = sessionManager.getSsrcTransactionByStream(streamId);
 | 
	
		
			
				|  |  | +                if (ssrcTransaction != null) {
 | 
	
		
			
				|  |  | +                    try {
 | 
	
		
			
				|  |  | +                        cmder.streamByeCmd(device, channel.getDeviceId(), streamId, null);
 | 
	
		
			
				|  |  | +                    } catch (InvalidArgumentException | ParseException | SipException | SsrcTransactionNotFoundException e) {
 | 
	
		
			
				|  |  | +                        log.error("[点播超时], 发送BYE失败 {}", e.getMessage());
 | 
	
		
			
				|  |  | +                    } finally {
 | 
	
		
			
				|  |  | +                        sessionManager.removeByStream(streamId);
 | 
	
		
			
				|  |  | +                    }
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +        });
 | 
	
		
			
				|  |  | +        if (ssrcInfo == null || ssrcInfo.getPort() <= 0) {
 | 
	
		
			
				|  |  | +            log.info("[点播端口/SSRC]获取失败,deviceId={},channelId={},ssrcInfo={}", device.getDeviceId(), channel.getDeviceId(), ssrcInfo);
 | 
	
		
			
				|  |  | +            callback.run(InviteErrorCode.ERROR_FOR_RESOURCE_EXHAUSTION.getCode(), "获取端口或者ssrc失败", null);
 | 
	
		
			
				|  |  | +            sessionManager.removeByStream(streamId);
 | 
	
		
			
				|  |  |              inviteStreamService.call(InviteSessionType.PLAY, channel.getId(), null,
 | 
	
		
			
				|  |  |                      InviteErrorCode.ERROR_FOR_RESOURCE_EXHAUSTION.getCode(),
 | 
	
		
			
				|  |  |                      InviteErrorCode.ERROR_FOR_RESOURCE_EXHAUSTION.getMsg(),
 | 
	
		
			
				|  |  |                      null);
 | 
	
		
			
				|  |  |              return null;
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  | -        play(mediaServerItem, ssrcInfo, device, channel, callback);
 | 
	
		
			
				|  |  | +        log.info("[点播开始] deviceId: {}, channelId: {},码流类型:{}, 收流端口: {}, 码流:{}, 收流模式:{}, SSRC: {}, SSRC校验:{}",
 | 
	
		
			
				|  |  | +                device.getDeviceId(), channel.getDeviceId(), channel.getStreamIdentification(), ssrcInfo.getPort(), ssrcInfo.getStream(),
 | 
	
		
			
				|  |  | +                device.getStreamMode(), ssrcInfo.getSsrc(), device.isSsrcCheck());
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        // 初始化redis中的invite消息状态
 | 
	
		
			
				|  |  | +        InviteInfo inviteInfo = InviteInfo.getInviteInfo(device.getDeviceId(), channel.getId(), ssrcInfo.getStream(), ssrcInfo,
 | 
	
		
			
				|  |  | +                mediaServerItem.getSdpIp(), ssrcInfo.getPort(), device.getStreamMode(), InviteSessionType.PLAY,
 | 
	
		
			
				|  |  | +                InviteSessionStatus.ready);
 | 
	
		
			
				|  |  | +        inviteStreamService.updateInviteInfo(inviteInfo);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        try {
 | 
	
		
			
				|  |  | +            cmder.playStreamCmd(mediaServerItem, ssrcInfo, device, channel, (eventResult) -> {
 | 
	
		
			
				|  |  | +                // 处理收到200ok后的TCP主动连接以及SSRC不一致的问题
 | 
	
		
			
				|  |  | +                InviteOKHandler(eventResult, ssrcInfo, mediaServerItem, device, channel, callback, inviteInfo, InviteSessionType.PLAY);
 | 
	
		
			
				|  |  | +            }, (event) -> {
 | 
	
		
			
				|  |  | +                log.info("[点播失败] deviceId: {}, channelId:{}, {}: {}", device.getDeviceId(), channel.getDeviceId(), event.statusCode, event.msg);
 | 
	
		
			
				|  |  | +                receiveRtpServerService.closeRTPServer(mediaServerItem, ssrcInfo);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                sessionManager.removeByStream(ssrcInfo.getStream());
 | 
	
		
			
				|  |  | +                if (callback != null) {
 | 
	
		
			
				|  |  | +                    callback.run(event.statusCode, event.msg, null);
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +                inviteStreamService.call(InviteSessionType.PLAY, channel.getId(), null,
 | 
	
		
			
				|  |  | +                        event.statusCode, event.msg, null);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                inviteStreamService.removeInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, channel.getId());
 | 
	
		
			
				|  |  | +            });
 | 
	
		
			
				|  |  | +        } catch (InvalidArgumentException | SipException | ParseException e) {
 | 
	
		
			
				|  |  | +            log.error("[命令发送失败] 点播消息: {}", e.getMessage());
 | 
	
		
			
				|  |  | +            receiveRtpServerService.closeRTPServer(mediaServerItem, ssrcInfo);
 | 
	
		
			
				|  |  | +            sessionManager.removeByStream(ssrcInfo.getStream());
 | 
	
		
			
				|  |  | +            if (callback != null) {
 | 
	
		
			
				|  |  | +                callback.run(InviteErrorCode.ERROR_FOR_SIP_SENDING_FAILED.getCode(),
 | 
	
		
			
				|  |  | +                        InviteErrorCode.ERROR_FOR_SIP_SENDING_FAILED.getMsg(), null);
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +            inviteStreamService.call(InviteSessionType.PLAY, channel.getId(), null,
 | 
	
		
			
				|  |  | +                    InviteErrorCode.ERROR_FOR_SIP_SENDING_FAILED.getCode(),
 | 
	
		
			
				|  |  | +                    InviteErrorCode.ERROR_FOR_SIP_SENDING_FAILED.getMsg(), null);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            inviteStreamService.removeInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, channel.getId());
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  |          return ssrcInfo;
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |      private void talk(MediaServer mediaServerItem, Device device, DeviceChannel channel, String stream,
 | 
	
		
			
				|  |  |                        HookSubscribe.Event hookEvent, SipSubscribe.Event errorEvent,
 | 
	
		
			
				|  |  |                        Runnable timeoutCallback, AudioBroadcastEvent audioEvent) {
 | 
	
	
		
			
				|  | @@ -475,154 +572,8 @@ public class PlayServiceImpl implements IPlayService {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    @Override
 | 
	
		
			
				|  |  | -    public void play(MediaServer mediaServerItem, SSRCInfo ssrcInfo, Device device, DeviceChannel channel,
 | 
	
		
			
				|  |  | -                     ErrorCallback<StreamInfo> callback) {
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        if (mediaServerItem == null || ssrcInfo == null) {
 | 
	
		
			
				|  |  | -            if (callback != null) {
 | 
	
		
			
				|  |  | -                callback.run(InviteErrorCode.ERROR_FOR_PARAMETER_ERROR.getCode(),
 | 
	
		
			
				|  |  | -                        InviteErrorCode.ERROR_FOR_PARAMETER_ERROR.getMsg(),
 | 
	
		
			
				|  |  | -                        null);
 | 
	
		
			
				|  |  | -            }
 | 
	
		
			
				|  |  | -            return;
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -        log.info("[点播开始] deviceId: {}, channelId: {},码流类型:{}, 收流端口: {}, 码流:{}, 收流模式:{}, SSRC: {}, SSRC校验:{}",
 | 
	
		
			
				|  |  | -                device.getDeviceId(), channel.getDeviceId(), channel.getStreamIdentification(), ssrcInfo.getPort(), ssrcInfo.getStream(),
 | 
	
		
			
				|  |  | -                device.getStreamMode(), ssrcInfo.getSsrc(), device.isSsrcCheck());
 | 
	
		
			
				|  |  | -        //端口获取失败的ssrcInfo 没有必要发送点播指令
 | 
	
		
			
				|  |  | -        if (ssrcInfo.getPort() <= 0) {
 | 
	
		
			
				|  |  | -            log.info("[点播端口分配异常],deviceId={},channelId={},ssrcInfo={}", device.getDeviceId(), channel.getDeviceId(), ssrcInfo);
 | 
	
		
			
				|  |  | -            // 释放ssrc
 | 
	
		
			
				|  |  | -            mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
 | 
	
		
			
				|  |  | -            sessionManager.removeByStream(ssrcInfo.getStream());
 | 
	
		
			
				|  |  | -            if (callback != null) {
 | 
	
		
			
				|  |  | -                callback.run(InviteErrorCode.ERROR_FOR_RESOURCE_EXHAUSTION.getCode(), "点播端口分配异常", null);
 | 
	
		
			
				|  |  | -            }
 | 
	
		
			
				|  |  | -            inviteStreamService.call(InviteSessionType.PLAY, channel.getId(), null,
 | 
	
		
			
				|  |  | -                    InviteErrorCode.ERROR_FOR_RESOURCE_EXHAUSTION.getCode(), "点播端口分配异常", null);
 | 
	
		
			
				|  |  | -            return;
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        // 初始化redis中的invite消息状态
 | 
	
		
			
				|  |  | -        InviteInfo inviteInfo = InviteInfo.getInviteInfo(device.getDeviceId(), channel.getId(), ssrcInfo.getStream(), ssrcInfo,
 | 
	
		
			
				|  |  | -                mediaServerItem.getSdpIp(), ssrcInfo.getPort(), device.getStreamMode(), InviteSessionType.PLAY,
 | 
	
		
			
				|  |  | -                InviteSessionStatus.ready);
 | 
	
		
			
				|  |  | -        inviteStreamService.updateInviteInfo(inviteInfo);
 | 
	
		
			
				|  |  | -        // 超时处理
 | 
	
		
			
				|  |  | -        String timeOutTaskKey = UUID.randomUUID().toString();
 | 
	
		
			
				|  |  | -        dynamicTask.startDelay(timeOutTaskKey, () -> {
 | 
	
		
			
				|  |  | -            // 执行超时任务时查询是否已经成功,成功了则不执行超时任务,防止超时任务取消失败的情况
 | 
	
		
			
				|  |  | -            InviteInfo inviteInfoForTimeOut = inviteStreamService.getInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, channel.getId());
 | 
	
		
			
				|  |  | -            if (inviteInfoForTimeOut == null || inviteInfoForTimeOut.getStreamInfo() == null) {
 | 
	
		
			
				|  |  | -                log.info("[点播超时] 收流超时 deviceId: {}, channelId: {},码流:{},端口:{}, SSRC: {}",
 | 
	
		
			
				|  |  | -                        device.getDeviceId(), channel.getDeviceId(), channel.getStreamIdentification(),
 | 
	
		
			
				|  |  | -                        ssrcInfo.getPort(), ssrcInfo.getSsrc());
 | 
	
		
			
				|  |  | -                if (callback != null) {
 | 
	
		
			
				|  |  | -                    callback.run(InviteErrorCode.ERROR_FOR_STREAM_TIMEOUT.getCode(), InviteErrorCode.ERROR_FOR_STREAM_TIMEOUT.getMsg(), null);
 | 
	
		
			
				|  |  | -                }
 | 
	
		
			
				|  |  | -                inviteStreamService.call(InviteSessionType.PLAY, channel.getId(), null,
 | 
	
		
			
				|  |  | -                        InviteErrorCode.ERROR_FOR_STREAM_TIMEOUT.getCode(), InviteErrorCode.ERROR_FOR_STREAM_TIMEOUT.getMsg(), null);
 | 
	
		
			
				|  |  | -                inviteStreamService.removeInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, channel.getId());
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -                try {
 | 
	
		
			
				|  |  | -                    cmder.streamByeCmd(device, channel.getDeviceId(), ssrcInfo.getStream(), null);
 | 
	
		
			
				|  |  | -                } catch (InvalidArgumentException | ParseException | SipException | SsrcTransactionNotFoundException e) {
 | 
	
		
			
				|  |  | -                    log.error("[点播超时], 发送BYE失败 {}", e.getMessage());
 | 
	
		
			
				|  |  | -                } finally {
 | 
	
		
			
				|  |  | -                    mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
 | 
	
		
			
				|  |  | -                    mediaServerService.closeRTPServer(mediaServerItem, ssrcInfo.getStream());
 | 
	
		
			
				|  |  | -                    sessionManager.removeByStream(ssrcInfo.getStream());
 | 
	
		
			
				|  |  | -                    mediaServerService.closeRTPServer(mediaServerItem, ssrcInfo.getStream());
 | 
	
		
			
				|  |  | -                    // 取消订阅消息监听
 | 
	
		
			
				|  |  | -                    subscribe.removeSubscribe(Hook.getInstance(HookType.on_media_arrival, "rtp", ssrcInfo.getStream()));
 | 
	
		
			
				|  |  | -                }
 | 
	
		
			
				|  |  | -            }else {
 | 
	
		
			
				|  |  | -                log.info("[点播超时] 收流超时 deviceId: {}, channelId: {},码流:{},端口:{}, SSRC: {}",
 | 
	
		
			
				|  |  | -                        device.getDeviceId(), channel.getDeviceId(), channel.getStreamIdentification(),
 | 
	
		
			
				|  |  | -                        ssrcInfo.getPort(), ssrcInfo.getSsrc());
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -                mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -                mediaServerService.closeRTPServer(mediaServerItem.getId(), ssrcInfo.getStream());
 | 
	
		
			
				|  |  | -                sessionManager.removeByStream(ssrcInfo.getStream());
 | 
	
		
			
				|  |  | -            }
 | 
	
		
			
				|  |  | -        }, userSetting.getPlayTimeout());
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        try {
 | 
	
		
			
				|  |  | -            cmder.playStreamCmd(mediaServerItem, ssrcInfo, device, channel, (hookData ) -> {
 | 
	
		
			
				|  |  | -                log.info("收到订阅消息: " + hookData);
 | 
	
		
			
				|  |  | -                dynamicTask.stop(timeOutTaskKey);
 | 
	
		
			
				|  |  | -                // hook响应
 | 
	
		
			
				|  |  | -                StreamInfo streamInfo = onPublishHandlerForPlay(hookData.getMediaServer(), hookData.getMediaInfo(), device, channel);
 | 
	
		
			
				|  |  | -                if (streamInfo == null){
 | 
	
		
			
				|  |  | -                    if (callback != null) {
 | 
	
		
			
				|  |  | -                        callback.run(InviteErrorCode.ERROR_FOR_STREAM_PARSING_EXCEPTIONS.getCode(),
 | 
	
		
			
				|  |  | -                                InviteErrorCode.ERROR_FOR_STREAM_PARSING_EXCEPTIONS.getMsg(), null);
 | 
	
		
			
				|  |  | -                    }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -                    inviteStreamService.call(InviteSessionType.PLAY, channel.getId(), null,
 | 
	
		
			
				|  |  | -                            InviteErrorCode.ERROR_FOR_STREAM_PARSING_EXCEPTIONS.getCode(),
 | 
	
		
			
				|  |  | -                            InviteErrorCode.ERROR_FOR_STREAM_PARSING_EXCEPTIONS.getMsg(), null);
 | 
	
		
			
				|  |  | -                    return;
 | 
	
		
			
				|  |  | -                }
 | 
	
		
			
				|  |  | -                if (callback != null) {
 | 
	
		
			
				|  |  | -                    callback.run(InviteErrorCode.SUCCESS.getCode(), InviteErrorCode.SUCCESS.getMsg(), streamInfo);
 | 
	
		
			
				|  |  | -                }
 | 
	
		
			
				|  |  | -                inviteStreamService.call(InviteSessionType.PLAY, channel.getId(), null,
 | 
	
		
			
				|  |  | -                        InviteErrorCode.SUCCESS.getCode(),
 | 
	
		
			
				|  |  | -                        InviteErrorCode.SUCCESS.getMsg(),
 | 
	
		
			
				|  |  | -                        streamInfo);
 | 
	
		
			
				|  |  | -                log.info("[点播成功] deviceId: {}, channelId:{}, 码流类型:{}", device.getDeviceId(), channel.getDeviceId(),
 | 
	
		
			
				|  |  | -                        channel.getStreamIdentification());
 | 
	
		
			
				|  |  | -                snapOnPlay(hookData.getMediaServer(), device.getDeviceId(), channel.getDeviceId(), ssrcInfo.getStream());
 | 
	
		
			
				|  |  | -            }, (eventResult) -> {
 | 
	
		
			
				|  |  | -                // 处理收到200ok后的TCP主动连接以及SSRC不一致的问题
 | 
	
		
			
				|  |  | -                InviteOKHandler(eventResult, ssrcInfo, mediaServerItem, device, channel,
 | 
	
		
			
				|  |  | -                        timeOutTaskKey, callback, inviteInfo, InviteSessionType.PLAY);
 | 
	
		
			
				|  |  | -            }, (event) -> {
 | 
	
		
			
				|  |  | -                log.info("[点播失败] deviceId: {}, channelId:{}, {}: {}", device.getDeviceId(), channel.getDeviceId(), event.statusCode, event.msg);
 | 
	
		
			
				|  |  | -                dynamicTask.stop(timeOutTaskKey);
 | 
	
		
			
				|  |  | -                mediaServerService.closeRTPServer(mediaServerItem, ssrcInfo.getStream());
 | 
	
		
			
				|  |  | -                // 释放ssrc
 | 
	
		
			
				|  |  | -                mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -                sessionManager.removeByStream(ssrcInfo.getStream());
 | 
	
		
			
				|  |  | -                if (callback != null) {
 | 
	
		
			
				|  |  | -                    callback.run(event.statusCode, event.msg, null);
 | 
	
		
			
				|  |  | -                }
 | 
	
		
			
				|  |  | -                inviteStreamService.call(InviteSessionType.PLAY, channel.getId(), null,
 | 
	
		
			
				|  |  | -                        InviteErrorCode.ERROR_FOR_RESET_SSRC.getCode(),
 | 
	
		
			
				|  |  | -                        String.format("点播失败, 错误码: %s, %s", event.statusCode, event.msg), null);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -                inviteStreamService.removeInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, channel.getId());
 | 
	
		
			
				|  |  | -            });
 | 
	
		
			
				|  |  | -        } catch (InvalidArgumentException | SipException | ParseException e) {
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -            log.error("[命令发送失败] 点播消息: {}", e.getMessage());
 | 
	
		
			
				|  |  | -            dynamicTask.stop(timeOutTaskKey);
 | 
	
		
			
				|  |  | -            mediaServerService.closeRTPServer(mediaServerItem, ssrcInfo.getStream());
 | 
	
		
			
				|  |  | -            // 释放ssrc
 | 
	
		
			
				|  |  | -            mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -            sessionManager.removeByStream(ssrcInfo.getStream());
 | 
	
		
			
				|  |  | -            if (callback != null) {
 | 
	
		
			
				|  |  | -                callback.run(InviteErrorCode.ERROR_FOR_SIP_SENDING_FAILED.getCode(),
 | 
	
		
			
				|  |  | -                        InviteErrorCode.ERROR_FOR_SIP_SENDING_FAILED.getMsg(), null);
 | 
	
		
			
				|  |  | -            }
 | 
	
		
			
				|  |  | -            inviteStreamService.call(InviteSessionType.PLAY, channel.getId(), null,
 | 
	
		
			
				|  |  | -                    InviteErrorCode.ERROR_FOR_SIP_SENDING_FAILED.getCode(),
 | 
	
		
			
				|  |  | -                    InviteErrorCode.ERROR_FOR_SIP_SENDING_FAILED.getMsg(), null);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -            inviteStreamService.removeInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, channel.getId());
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |      private void tcpActiveHandler(Device device, DeviceChannel channel, String contentString,
 | 
	
		
			
				|  |  | -                                  MediaServer mediaServerItem, String timeOutTaskKey,
 | 
	
		
			
				|  |  | -                                  SSRCInfo ssrcInfo, ErrorCallback<StreamInfo> callback){
 | 
	
		
			
				|  |  | +                                  MediaServer mediaServerItem, SSRCInfo ssrcInfo, ErrorCallback<StreamInfo> callback){
 | 
	
		
			
				|  |  |          if (!device.getStreamMode().equalsIgnoreCase("TCP-ACTIVE")) {
 | 
	
		
			
				|  |  |              return;
 | 
	
		
			
				|  |  |          }
 | 
	
	
		
			
				|  | @@ -652,13 +603,8 @@ public class PlayServiceImpl implements IPlayService {
 | 
	
		
			
				|  |  |              log.info("[TCP主动连接对方] 结果: {}" , result);
 | 
	
		
			
				|  |  |              if (!result) {
 | 
	
		
			
				|  |  |                  // 主动连接失败,结束流程, 清理数据
 | 
	
		
			
				|  |  | -                dynamicTask.stop(timeOutTaskKey);
 | 
	
		
			
				|  |  | -                mediaServerService.closeRTPServer(mediaServerItem, ssrcInfo.getStream());
 | 
	
		
			
				|  |  | -                // 释放ssrc
 | 
	
		
			
				|  |  | -                mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | +                receiveRtpServerService.closeRTPServer(mediaServerItem, ssrcInfo);
 | 
	
		
			
				|  |  |                  sessionManager.removeByStream(ssrcInfo.getStream());
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |                  callback.run(InviteErrorCode.ERROR_FOR_SDP_PARSING_EXCEPTIONS.getCode(),
 | 
	
		
			
				|  |  |                          InviteErrorCode.ERROR_FOR_SDP_PARSING_EXCEPTIONS.getMsg(), null);
 | 
	
		
			
				|  |  |                  inviteStreamService.call(InviteSessionType.BROADCAST, channel.getId(), null,
 | 
	
	
		
			
				|  | @@ -667,10 +613,7 @@ public class PlayServiceImpl implements IPlayService {
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  |          } catch (SdpException e) {
 | 
	
		
			
				|  |  |              log.error("[TCP主动连接对方] deviceId: {}, channelId: {}, 解析200OK的SDP信息失败", device.getDeviceId(), channel.getDeviceId(), e);
 | 
	
		
			
				|  |  | -            dynamicTask.stop(timeOutTaskKey);
 | 
	
		
			
				|  |  | -            mediaServerService.closeRTPServer(mediaServerItem, ssrcInfo.getStream());
 | 
	
		
			
				|  |  | -            // 释放ssrc
 | 
	
		
			
				|  |  | -            mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
 | 
	
		
			
				|  |  | +            receiveRtpServerService.closeRTPServer(mediaServerItem, ssrcInfo);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |              sessionManager.removeByStream(ssrcInfo.getStream());
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -759,34 +702,86 @@ public class PlayServiceImpl implements IPlayService {
 | 
	
		
			
				|  |  |      @Override
 | 
	
		
			
				|  |  |      public void playBack(Device device, DeviceChannel channel, String startTime,
 | 
	
		
			
				|  |  |                           String endTime, ErrorCallback<StreamInfo> callback) {
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | +        if (device == null) {
 | 
	
		
			
				|  |  | +            throw new ControllerException(ErrorCode.ERROR100.getCode(), "设备不存在");
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        if (channel == null) {
 | 
	
		
			
				|  |  | +            throw new ControllerException(ErrorCode.ERROR100.getCode(), "通道不存在");
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  |          MediaServer newMediaServerItem = getNewMediaServerItem(device);
 | 
	
		
			
				|  |  | +        if (newMediaServerItem == null) {
 | 
	
		
			
				|  |  | +            throw new ControllerException(ErrorCode.ERROR100.getCode(), "未找到可用的节点");
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  |          if (device.getStreamMode().equalsIgnoreCase("TCP-ACTIVE") && ! newMediaServerItem.isRtpEnable()) {
 | 
	
		
			
				|  |  |              log.warn("[录像回放] 单端口收流时不支持TCP主动方式收流 deviceId: {},channelId:{}", device.getDeviceId(), channel.getDeviceId());
 | 
	
		
			
				|  |  |              throw new ControllerException(ErrorCode.ERROR100.getCode(), "单端口收流时不支持TCP主动方式收流");
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        playBack(newMediaServerItem, device, channel, startTime, endTime, callback);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    private void playBack(MediaServer mediaServerItem,
 | 
	
		
			
				|  |  | +                         Device device, DeviceChannel channel, String startTime,
 | 
	
		
			
				|  |  | +                         String endTime, ErrorCallback<StreamInfo> callback) {
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |          String startTimeStr = startTime.replace("-", "")
 | 
	
		
			
				|  |  |                  .replace(":", "")
 | 
	
		
			
				|  |  |                  .replace(" ", "");
 | 
	
		
			
				|  |  |          String endTimeTimeStr = endTime.replace("-", "")
 | 
	
		
			
				|  |  |                  .replace(":", "")
 | 
	
		
			
				|  |  |                  .replace(" ", "");
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |          String stream = device.getDeviceId() + "_" + channel.getDeviceId() + "_" + startTimeStr + "_" + endTimeTimeStr;
 | 
	
		
			
				|  |  |          int tcpMode = device.getStreamMode().equals("TCP-ACTIVE")? 2: (device.getStreamMode().equals("TCP-PASSIVE")? 1:0);
 | 
	
		
			
				|  |  | -        SSRCInfo ssrcInfo = mediaServerService.openRTPServer(newMediaServerItem, stream, null, device.isSsrcCheck(),
 | 
	
		
			
				|  |  | -                true, 0, false,  !channel.isHasAudio(),  false, tcpMode);
 | 
	
		
			
				|  |  | -        playBack(newMediaServerItem, ssrcInfo, device, channel, startTime, endTime, callback);
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    public void playBack(MediaServer mediaServerItem, SSRCInfo ssrcInfo,
 | 
	
		
			
				|  |  | -                         Device device, DeviceChannel channel, String startTime,
 | 
	
		
			
				|  |  | -                         String endTime, ErrorCallback<StreamInfo> callback) {
 | 
	
		
			
				|  |  | -        if (device == null) {
 | 
	
		
			
				|  |  | -            throw new ControllerException(ErrorCode.ERROR100.getCode(), "设备不存在");
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -        if (mediaServerItem == null || ssrcInfo == null) {
 | 
	
		
			
				|  |  | -            callback.run(InviteErrorCode.ERROR_FOR_PARAMETER_ERROR.getCode(),
 | 
	
		
			
				|  |  | -                    InviteErrorCode.ERROR_FOR_PARAMETER_ERROR.getMsg(),
 | 
	
		
			
				|  |  | +        RTPServerParam rtpServerParam = new RTPServerParam();
 | 
	
		
			
				|  |  | +        rtpServerParam.setMediaServerItem(mediaServerItem);
 | 
	
		
			
				|  |  | +        rtpServerParam.setStreamId(stream);
 | 
	
		
			
				|  |  | +        rtpServerParam.setSsrcCheck(device.isSsrcCheck());
 | 
	
		
			
				|  |  | +        rtpServerParam.setPlayback(true);
 | 
	
		
			
				|  |  | +        rtpServerParam.setPort(0);
 | 
	
		
			
				|  |  | +        rtpServerParam.setTcpMode(tcpMode);
 | 
	
		
			
				|  |  | +        rtpServerParam.setOnlyAuto(false);
 | 
	
		
			
				|  |  | +        rtpServerParam.setDisableAudio(!channel.isHasAudio());
 | 
	
		
			
				|  |  | +        SSRCInfo ssrcInfo = receiveRtpServerService.openRTPServer(rtpServerParam, (code, msg, hookData) -> {
 | 
	
		
			
				|  |  | +            if (code == InviteErrorCode.SUCCESS.getCode()) {
 | 
	
		
			
				|  |  | +                // hook响应
 | 
	
		
			
				|  |  | +                StreamInfo streamInfo = onPublishHandlerForPlayback(hookData.getMediaServer(), hookData.getMediaInfo(), device, channel, startTime, endTime);
 | 
	
		
			
				|  |  | +                if (streamInfo == null) {
 | 
	
		
			
				|  |  | +                    log.warn("设备回放API调用失败!");
 | 
	
		
			
				|  |  | +                    callback.run(InviteErrorCode.ERROR_FOR_STREAM_PARSING_EXCEPTIONS.getCode(),
 | 
	
		
			
				|  |  | +                            InviteErrorCode.ERROR_FOR_STREAM_PARSING_EXCEPTIONS.getMsg(), null);
 | 
	
		
			
				|  |  | +                    return;
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +                callback.run(InviteErrorCode.SUCCESS.getCode(), InviteErrorCode.SUCCESS.getMsg(), streamInfo);
 | 
	
		
			
				|  |  | +                log.info("[录像回放] 成功 deviceId: {}, channelId: {},  开始时间: {}, 结束时间: {}", device.getDeviceId(), channel.getGbDeviceId(), startTime, endTime);
 | 
	
		
			
				|  |  | +            }else {
 | 
	
		
			
				|  |  | +                if (callback != null) {
 | 
	
		
			
				|  |  | +                    callback.run(code, msg, null);
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +                inviteStreamService.call(InviteSessionType.PLAYBACK, channel.getId(), null, code, msg, null);
 | 
	
		
			
				|  |  | +                inviteStreamService.removeInviteInfoByDeviceAndChannel(InviteSessionType.PLAYBACK, channel.getId());
 | 
	
		
			
				|  |  | +                SsrcTransaction ssrcTransaction = sessionManager.getSsrcTransactionByStream(stream);
 | 
	
		
			
				|  |  | +                if (ssrcTransaction != null) {
 | 
	
		
			
				|  |  | +                    try {
 | 
	
		
			
				|  |  | +                        cmder.streamByeCmd(device, channel.getDeviceId(), stream, null);
 | 
	
		
			
				|  |  | +                    } catch (InvalidArgumentException | ParseException | SipException | SsrcTransactionNotFoundException e) {
 | 
	
		
			
				|  |  | +                        log.error("[录像回放] 发送BYE失败 {}", e.getMessage());
 | 
	
		
			
				|  |  | +                    } finally {
 | 
	
		
			
				|  |  | +                        sessionManager.removeByStream(stream);
 | 
	
		
			
				|  |  | +                    }
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +        });
 | 
	
		
			
				|  |  | +        if (ssrcInfo == null || ssrcInfo.getPort() <= 0) {
 | 
	
		
			
				|  |  | +            log.info("[回放端口/SSRC]获取失败,deviceId={},channelId={},ssrcInfo={}", device.getDeviceId(), channel.getDeviceId(), ssrcInfo);
 | 
	
		
			
				|  |  | +            if (callback != null) {
 | 
	
		
			
				|  |  | +                callback.run(InviteErrorCode.ERROR_FOR_RESOURCE_EXHAUSTION.getCode(), "获取端口或者ssrc失败", null);
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +            sessionManager.removeByStream(stream);
 | 
	
		
			
				|  |  | +            inviteStreamService.call(InviteSessionType.PLAY, channel.getId(), null,
 | 
	
		
			
				|  |  | +                    InviteErrorCode.ERROR_FOR_RESOURCE_EXHAUSTION.getCode(),
 | 
	
		
			
				|  |  | +                    InviteErrorCode.ERROR_FOR_RESOURCE_EXHAUSTION.getMsg(),
 | 
	
		
			
				|  |  |                      null);
 | 
	
		
			
				|  |  |              return;
 | 
	
		
			
				|  |  |          }
 | 
	
	
		
			
				|  | @@ -799,70 +794,37 @@ public class PlayServiceImpl implements IPlayService {
 | 
	
		
			
				|  |  |                  mediaServerItem.getSdpIp(), ssrcInfo.getPort(), device.getStreamMode(), InviteSessionType.PLAYBACK,
 | 
	
		
			
				|  |  |                  InviteSessionStatus.ready);
 | 
	
		
			
				|  |  |          inviteStreamService.updateInviteInfo(inviteInfo);
 | 
	
		
			
				|  |  | -        String playBackTimeOutTaskKey = UUID.randomUUID().toString();
 | 
	
		
			
				|  |  | -        dynamicTask.startDelay(playBackTimeOutTaskKey, () -> {
 | 
	
		
			
				|  |  | -            log.warn("[录像回放] 超时,deviceId:{} ,channelId:{}", device.getDeviceId(), channel.getGbDeviceId());
 | 
	
		
			
				|  |  | -            inviteStreamService.removeInviteInfo(inviteInfo);
 | 
	
		
			
				|  |  | -            callback.run(InviteErrorCode.ERROR_FOR_SIGNALLING_TIMEOUT.getCode(), InviteErrorCode.ERROR_FOR_SIGNALLING_TIMEOUT.getMsg(), null);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -            try {
 | 
	
		
			
				|  |  | -                cmder.streamByeCmd(device, channel.getGbDeviceId(), ssrcInfo.getStream(), null);
 | 
	
		
			
				|  |  | -            } catch (InvalidArgumentException | ParseException | SipException e) {
 | 
	
		
			
				|  |  | -                log.error("[录像回放] 超时 发送BYE失败 {}", e.getMessage());
 | 
	
		
			
				|  |  | -            } catch (SsrcTransactionNotFoundException e) {
 | 
	
		
			
				|  |  | -                // 点播超时回复BYE 同时释放ssrc以及此次点播的资源
 | 
	
		
			
				|  |  | -                mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
 | 
	
		
			
				|  |  | -                mediaServerService.closeRTPServer(mediaServerItem, ssrcInfo.getStream());
 | 
	
		
			
				|  |  | -                sessionManager.removeByStream(ssrcInfo.getStream());
 | 
	
		
			
				|  |  | -            }
 | 
	
		
			
				|  |  | -        }, userSetting.getPlayTimeout());
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        SipSubscribe.Event errorEvent = event -> {
 | 
	
		
			
				|  |  | -            log.info("[录像回放] 失败,{} {}", event.statusCode, event.msg);
 | 
	
		
			
				|  |  | -            dynamicTask.stop(playBackTimeOutTaskKey);
 | 
	
		
			
				|  |  | -            callback.run(InviteErrorCode.ERROR_FOR_SIGNALLING_ERROR.getCode(),
 | 
	
		
			
				|  |  | -                    String.format("回放失败, 错误码: %s, %s", event.statusCode, event.msg), null);
 | 
	
		
			
				|  |  | -            mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
 | 
	
		
			
				|  |  | -            mediaServerService.closeRTPServer(mediaServerItem, ssrcInfo.getStream());
 | 
	
		
			
				|  |  | -            sessionManager.removeByStream(ssrcInfo.getStream());
 | 
	
		
			
				|  |  | -            inviteStreamService.removeInviteInfo(inviteInfo);
 | 
	
		
			
				|  |  | -        };
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        HookSubscribe.Event hookEvent = (hookData) -> {
 | 
	
		
			
				|  |  | -            log.info("收到回放订阅消息: " + hookData);
 | 
	
		
			
				|  |  | -            dynamicTask.stop(playBackTimeOutTaskKey);
 | 
	
		
			
				|  |  | -            StreamInfo streamInfo = onPublishHandlerForPlayback(hookData.getMediaServer(), hookData.getMediaInfo(), device, channel, startTime, endTime);
 | 
	
		
			
				|  |  | -            if (streamInfo == null) {
 | 
	
		
			
				|  |  | -                log.warn("设备回放API调用失败!");
 | 
	
		
			
				|  |  | -                callback.run(InviteErrorCode.ERROR_FOR_STREAM_PARSING_EXCEPTIONS.getCode(),
 | 
	
		
			
				|  |  | -                        InviteErrorCode.ERROR_FOR_STREAM_PARSING_EXCEPTIONS.getMsg(), null);
 | 
	
		
			
				|  |  | -                return;
 | 
	
		
			
				|  |  | -            }
 | 
	
		
			
				|  |  | -            callback.run(InviteErrorCode.SUCCESS.getCode(), InviteErrorCode.SUCCESS.getMsg(), streamInfo);
 | 
	
		
			
				|  |  | -            log.info("[录像回放] 成功 deviceId: {}, channelId: {},  开始时间: {}, 结束时间: {}", device.getDeviceId(), channel.getGbDeviceId(), startTime, endTime);
 | 
	
		
			
				|  |  | -        };
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          try {
 | 
	
		
			
				|  |  |              cmder.playbackStreamCmd(mediaServerItem, ssrcInfo, device, channel, startTime, endTime,
 | 
	
		
			
				|  |  | -                    hookEvent, eventResult -> {
 | 
	
		
			
				|  |  | +                    eventResult -> {
 | 
	
		
			
				|  |  |                          // 处理收到200ok后的TCP主动连接以及SSRC不一致的问题
 | 
	
		
			
				|  |  |                          InviteOKHandler(eventResult, ssrcInfo, mediaServerItem, device, channel,
 | 
	
		
			
				|  |  | -                                playBackTimeOutTaskKey, callback, inviteInfo, InviteSessionType.PLAYBACK);
 | 
	
		
			
				|  |  | -                    }, errorEvent);
 | 
	
		
			
				|  |  | +                                callback, inviteInfo, InviteSessionType.PLAYBACK);
 | 
	
		
			
				|  |  | +                    }, eventResult -> {
 | 
	
		
			
				|  |  | +                        log.info("[录像回放] 失败,{} {}", eventResult.statusCode, eventResult.msg);
 | 
	
		
			
				|  |  | +                        if (callback != null) {
 | 
	
		
			
				|  |  | +                            callback.run(eventResult.statusCode, eventResult.msg, null);
 | 
	
		
			
				|  |  | +                        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                        receiveRtpServerService.closeRTPServer(mediaServerItem, ssrcInfo);
 | 
	
		
			
				|  |  | +                        sessionManager.removeByStream(ssrcInfo.getStream());
 | 
	
		
			
				|  |  | +                        inviteStreamService.removeInviteInfo(inviteInfo);
 | 
	
		
			
				|  |  | +                    });
 | 
	
		
			
				|  |  |          } catch (InvalidArgumentException | SipException | ParseException e) {
 | 
	
		
			
				|  |  |              log.error("[命令发送失败] 录像回放: {}", e.getMessage());
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -            SipSubscribe.EventResult eventResult = new SipSubscribe.EventResult();
 | 
	
		
			
				|  |  | -            eventResult.type = SipSubscribe.EventResultType.cmdSendFailEvent;
 | 
	
		
			
				|  |  | -            eventResult.statusCode = -1;
 | 
	
		
			
				|  |  | -            eventResult.msg = "命令发送失败";
 | 
	
		
			
				|  |  | -            errorEvent.response(eventResult);
 | 
	
		
			
				|  |  | +            if (callback != null) {
 | 
	
		
			
				|  |  | +                callback.run(InviteErrorCode.FAIL.getCode(), e.getMessage(), null);
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +            receiveRtpServerService.closeRTPServer(mediaServerItem, ssrcInfo);
 | 
	
		
			
				|  |  | +            sessionManager.removeByStream(ssrcInfo.getStream());
 | 
	
		
			
				|  |  | +            inviteStreamService.removeInviteInfo(inviteInfo);
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      private void InviteOKHandler(SipSubscribe.EventResult eventResult, SSRCInfo ssrcInfo, MediaServer mediaServerItem,
 | 
	
		
			
				|  |  | -                                 Device device, DeviceChannel channel, String timeOutTaskKey, ErrorCallback<StreamInfo> callback,
 | 
	
		
			
				|  |  | +                                 Device device, DeviceChannel channel, ErrorCallback<StreamInfo> callback,
 | 
	
		
			
				|  |  |                                   InviteInfo inviteInfo, InviteSessionType inviteSessionType){
 | 
	
		
			
				|  |  |          inviteInfo.setStatus(InviteSessionStatus.ok);
 | 
	
		
			
				|  |  |          ResponseEvent responseEvent = (ResponseEvent) eventResult.event;
 | 
	
	
		
			
				|  | @@ -877,7 +839,7 @@ public class PlayServiceImpl implements IPlayService {
 | 
	
		
			
				|  |  |              if (mediaServerItem.isRtpEnable()) {
 | 
	
		
			
				|  |  |                  // 多端口
 | 
	
		
			
				|  |  |                  if (device.getStreamMode().equalsIgnoreCase("TCP-ACTIVE")) {
 | 
	
		
			
				|  |  | -                    tcpActiveHandler(device, channel, contentString, mediaServerItem, timeOutTaskKey, ssrcInfo, callback);
 | 
	
		
			
				|  |  | +                    tcpActiveHandler(device, channel, contentString, mediaServerItem, ssrcInfo, callback);
 | 
	
		
			
				|  |  |                  }
 | 
	
		
			
				|  |  |              }else {
 | 
	
		
			
				|  |  |                  // 单端口
 | 
	
	
		
			
				|  | @@ -906,7 +868,6 @@ public class PlayServiceImpl implements IPlayService {
 | 
	
		
			
				|  |  |                              log.error("[命令发送失败] 停止播放, 发送BYE: {}", e.getMessage());
 | 
	
		
			
				|  |  |                          }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -                        dynamicTask.stop(timeOutTaskKey);
 | 
	
		
			
				|  |  |                          // 释放ssrc
 | 
	
		
			
				|  |  |                          mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -924,7 +885,7 @@ public class PlayServiceImpl implements IPlayService {
 | 
	
		
			
				|  |  |                          inviteInfo.setStream(ssrcInfo.getStream());
 | 
	
		
			
				|  |  |                          if (device.getStreamMode().equalsIgnoreCase("TCP-ACTIVE")) {
 | 
	
		
			
				|  |  |                              if (mediaServerItem.isRtpEnable()) {
 | 
	
		
			
				|  |  | -                                tcpActiveHandler(device, channel, contentString, mediaServerItem, timeOutTaskKey, ssrcInfo, callback);
 | 
	
		
			
				|  |  | +                                tcpActiveHandler(device, channel, contentString, mediaServerItem,  ssrcInfo, callback);
 | 
	
		
			
				|  |  |                              }else {
 | 
	
		
			
				|  |  |                                  log.warn("[Invite 200OK] 单端口收流模式不支持tcp主动模式收流");
 | 
	
		
			
				|  |  |                              }
 | 
	
	
		
			
				|  | @@ -1026,10 +987,10 @@ public class PlayServiceImpl implements IPlayService {
 | 
	
		
			
				|  |  |          };
 | 
	
		
			
				|  |  |          try {
 | 
	
		
			
				|  |  |              cmder.downloadStreamCmd(mediaServerItem, ssrcInfo, device, channel, startTime, endTime, downloadSpeed,
 | 
	
		
			
				|  |  | -                    hookEvent, errorEvent, eventResult ->{
 | 
	
		
			
				|  |  | +                    errorEvent, eventResult ->{
 | 
	
		
			
				|  |  |                          // 处理收到200ok后的TCP主动连接以及SSRC不一致的问题
 | 
	
		
			
				|  |  |                          InviteOKHandler(eventResult, ssrcInfo, mediaServerItem, device, channel,
 | 
	
		
			
				|  |  | -                                downLoadTimeOutTaskKey, callback, inviteInfo, InviteSessionType.DOWNLOAD);
 | 
	
		
			
				|  |  | +                                 callback, inviteInfo, InviteSessionType.DOWNLOAD);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |                          // 注册录像回调事件,录像下载结束后写入下载地址
 | 
	
		
			
				|  |  |                          HookSubscribe.Event hookEventForRecord = (hookData) -> {
 |