Commit 66210ec51ae0f20288585293cff5ac187a6d39da

Authored by 648540858
1 parent c8b0e66e

支持国标级联语音喊话TCP主动模式

src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java
@@ -978,8 +978,6 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -978,8 +978,6 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
978 return; 978 return;
979 } 979 }
980 String contentString = new String(request.getRawContent()); 980 String contentString = new String(request.getRawContent());
981 - // jainSip不支持y=字段, 移除移除以解析。  
982 - String ssrc = "0000000404";  
983 981
984 try { 982 try {
985 Gb28181Sdp gb28181Sdp = SipUtils.parseSDP(contentString); 983 Gb28181Sdp gb28181Sdp = SipUtils.parseSDP(contentString);
@@ -1027,7 +1025,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -1027,7 +1025,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
1027 return; 1025 return;
1028 } 1026 }
1029 String addressStr = sdp.getOrigin().getAddress(); 1027 String addressStr = sdp.getOrigin().getAddress();
1030 - logger.info("设备{}请求语音流,地址:{}:{},ssrc:{}, {}", requesterId, addressStr, port, ssrc, 1028 + logger.info("设备{}请求语音流,地址:{}:{},ssrc:{}, {}", requesterId, addressStr, port, gb28181Sdp.getSsrc(),
1031 mediaTransmissionTCP ? (tcpActive ? "TCP主动" : "TCP被动") : "UDP"); 1029 mediaTransmissionTCP ? (tcpActive ? "TCP主动" : "TCP被动") : "UDP");
1032 1030
1033 MediaServerItem mediaServerItem = broadcastCatch.getMediaServerItem(); 1031 MediaServerItem mediaServerItem = broadcastCatch.getMediaServerItem();
@@ -1041,11 +1039,11 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -1041,11 +1039,11 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
1041 } 1039 }
1042 return; 1040 return;
1043 } 1041 }
1044 - logger.info("设备{}请求语音流, 收流地址:{}:{},ssrc:{}, {}, 对讲方式:{}", requesterId, addressStr, port, ssrc, 1042 + logger.info("设备{}请求语音流, 收流地址:{}:{},ssrc:{}, {}, 对讲方式:{}", requesterId, addressStr, port, gb28181Sdp.getSsrc(),
1045 mediaTransmissionTCP ? (tcpActive ? "TCP主动" : "TCP被动") : "UDP", sdp.getSessionName().getValue()); 1043 mediaTransmissionTCP ? (tcpActive ? "TCP主动" : "TCP被动") : "UDP", sdp.getSessionName().getValue());
1046 CallIdHeader callIdHeader = (CallIdHeader) request.getHeader(CallIdHeader.NAME); 1044 CallIdHeader callIdHeader = (CallIdHeader) request.getHeader(CallIdHeader.NAME);
1047 1045
1048 - SendRtpItem sendRtpItem = zlmServerFactory.createSendRtpItem(mediaServerItem, addressStr, port, ssrc, requesterId, 1046 + SendRtpItem sendRtpItem = zlmServerFactory.createSendRtpItem(mediaServerItem, addressStr, port, gb28181Sdp.getSsrc(), requesterId,
1049 device.getDeviceId(), broadcastCatch.getChannelId(), 1047 device.getDeviceId(), broadcastCatch.getChannelId(),
1050 mediaTransmissionTCP, false); 1048 mediaTransmissionTCP, false);
1051 1049
@@ -1081,7 +1079,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -1081,7 +1079,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
1081 1079
1082 Boolean streamReady = zlmServerFactory.isStreamReady(mediaServerItem, broadcastCatch.getApp(), broadcastCatch.getStream()); 1080 Boolean streamReady = zlmServerFactory.isStreamReady(mediaServerItem, broadcastCatch.getApp(), broadcastCatch.getStream());
1083 if (streamReady) { 1081 if (streamReady) {
1084 - sendOk(device, sendRtpItem, sdp, request, mediaServerItem, mediaTransmissionTCP, ssrc); 1082 + sendOk(device, sendRtpItem, sdp, request, mediaServerItem, mediaTransmissionTCP, gb28181Sdp.getSsrc());
1085 } else { 1083 } else {
1086 logger.warn("[语音通话], 未发现待推送的流,app={},stream={}", broadcastCatch.getApp(), broadcastCatch.getStream()); 1084 logger.warn("[语音通话], 未发现待推送的流,app={},stream={}", broadcastCatch.getApp(), broadcastCatch.getStream());
1087 try { 1085 try {
src/main/java/com/genersoft/iot/vmp/service/impl/MediaServerServiceImpl.java
@@ -206,7 +206,7 @@ public class MediaServerServiceImpl implements IMediaServerService { @@ -206,7 +206,7 @@ public class MediaServerServiceImpl implements IMediaServerService {
206 @Override 206 @Override
207 public void closeRTPServer(String mediaServerId, String streamId) { 207 public void closeRTPServer(String mediaServerId, String streamId) {
208 MediaServerItem mediaServerItem = this.getOne(mediaServerId); 208 MediaServerItem mediaServerItem = this.getOne(mediaServerId);
209 - if (mediaServerItem.isRtpEnable()) { 209 + if (mediaServerItem != null && mediaServerItem.isRtpEnable()) {
210 closeRTPServer(mediaServerItem, streamId); 210 closeRTPServer(mediaServerItem, streamId);
211 } 211 }
212 zlmresTfulUtils.closeStreams(mediaServerItem, "rtp", streamId); 212 zlmresTfulUtils.closeStreams(mediaServerItem, "rtp", streamId);
src/main/java/com/genersoft/iot/vmp/service/impl/PlatformServiceImpl.java
1 package com.genersoft.iot.vmp.service.impl; 1 package com.genersoft.iot.vmp.service.impl;
2 2
  3 +import com.alibaba.fastjson2.JSONObject;
3 import com.genersoft.iot.vmp.common.InviteInfo; 4 import com.genersoft.iot.vmp.common.InviteInfo;
  5 +import com.genersoft.iot.vmp.common.InviteSessionStatus;
4 import com.genersoft.iot.vmp.common.InviteSessionType; 6 import com.genersoft.iot.vmp.common.InviteSessionType;
5 import com.baomidou.dynamic.datasource.annotation.DS; 7 import com.baomidou.dynamic.datasource.annotation.DS;
6 import com.genersoft.iot.vmp.conf.DynamicTask; 8 import com.genersoft.iot.vmp.conf.DynamicTask;
@@ -11,6 +13,7 @@ import com.genersoft.iot.vmp.gb28181.event.SipSubscribe; @@ -11,6 +13,7 @@ import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
11 import com.genersoft.iot.vmp.gb28181.session.SSRCFactory; 13 import com.genersoft.iot.vmp.gb28181.session.SSRCFactory;
12 import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager; 14 import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
13 import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform; 15 import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform;
  16 +import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
14 import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe; 17 import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe;
15 import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeFactory; 18 import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeFactory;
16 import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForStreamChange; 19 import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForStreamChange;
@@ -22,20 +25,20 @@ import com.genersoft.iot.vmp.service.IInviteStreamService; @@ -22,20 +25,20 @@ import com.genersoft.iot.vmp.service.IInviteStreamService;
22 import com.genersoft.iot.vmp.service.IMediaServerService; 25 import com.genersoft.iot.vmp.service.IMediaServerService;
23 import com.genersoft.iot.vmp.service.IPlatformService; 26 import com.genersoft.iot.vmp.service.IPlatformService;
24 import com.genersoft.iot.vmp.service.IPlayService; 27 import com.genersoft.iot.vmp.service.IPlayService;
25 -import com.genersoft.iot.vmp.service.bean.GPSMsgInfo;  
26 -import com.genersoft.iot.vmp.service.bean.InviteTimeOutCallback;  
27 -import com.genersoft.iot.vmp.service.bean.SSRCInfo; 28 +import com.genersoft.iot.vmp.service.bean.*;
28 import com.genersoft.iot.vmp.storager.IRedisCatchStorage; 29 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
29 import com.genersoft.iot.vmp.storager.dao.*; 30 import com.genersoft.iot.vmp.storager.dao.*;
30 import com.genersoft.iot.vmp.utils.DateUtil; 31 import com.genersoft.iot.vmp.utils.DateUtil;
31 import com.github.pagehelper.PageHelper; 32 import com.github.pagehelper.PageHelper;
32 import com.github.pagehelper.PageInfo; 33 import com.github.pagehelper.PageInfo;
33 import gov.nist.javax.sip.message.SIPRequest; 34 import gov.nist.javax.sip.message.SIPRequest;
  35 +import gov.nist.javax.sip.message.SIPResponse;
34 import org.slf4j.Logger; 36 import org.slf4j.Logger;
35 import org.slf4j.LoggerFactory; 37 import org.slf4j.LoggerFactory;
36 import org.springframework.beans.factory.annotation.Autowired; 38 import org.springframework.beans.factory.annotation.Autowired;
37 import org.springframework.stereotype.Service; 39 import org.springframework.stereotype.Service;
38 40
  41 +import javax.sdp.*;
39 import javax.sip.InvalidArgumentException; 42 import javax.sip.InvalidArgumentException;
40 import javax.sip.ResponseEvent; 43 import javax.sip.ResponseEvent;
41 import javax.sip.PeerUnavailableException; 44 import javax.sip.PeerUnavailableException;
@@ -109,6 +112,9 @@ public class PlatformServiceImpl implements IPlatformService { @@ -109,6 +112,9 @@ public class PlatformServiceImpl implements IPlatformService {
109 @Autowired 112 @Autowired
110 private IInviteStreamService inviteStreamService; 113 private IInviteStreamService inviteStreamService;
111 114
  115 + @Autowired
  116 + private ZLMRESTfulUtils zlmresTfulUtils;
  117 +
112 118
113 @Override 119 @Override
114 public ParentPlatform queryPlatformByServerGBId(String platformGbId) { 120 public ParentPlatform queryPlatformByServerGBId(String platformGbId) {
@@ -466,21 +472,21 @@ public class PlatformServiceImpl implements IPlatformService { @@ -466,21 +472,21 @@ public class PlatformServiceImpl implements IPlatformService {
466 logger.info("[国标级联] 语音喊话未找到可用的zlm. platform: {}", platform.getServerGBId()); 472 logger.info("[国标级联] 语音喊话未找到可用的zlm. platform: {}", platform.getServerGBId());
467 return; 473 return;
468 } 474 }
469 - InviteInfo inviteInfo = inviteStreamService.getInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, platform.getServerGBId(), channelId); 475 + InviteInfo inviteInfoForOld = inviteStreamService.getInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, platform.getServerGBId(), channelId);
470 476
471 - if (inviteInfo != null && inviteInfo.getStreamInfo() != null) { 477 + if (inviteInfoForOld != null && inviteInfoForOld.getStreamInfo() != null) {
472 // 如果zlm不存在这个流,则删除数据即可 478 // 如果zlm不存在这个流,则删除数据即可
473 - MediaServerItem mediaServerItemForStreamInfo = mediaServerService.getOne(inviteInfo.getStreamInfo().getMediaServerId()); 479 + MediaServerItem mediaServerItemForStreamInfo = mediaServerService.getOne(inviteInfoForOld.getStreamInfo().getMediaServerId());
474 if (mediaServerItemForStreamInfo != null) { 480 if (mediaServerItemForStreamInfo != null) {
475 - Boolean ready = zlmServerFactory.isStreamReady(mediaServerItemForStreamInfo, inviteInfo.getStreamInfo().getApp(), inviteInfo.getStreamInfo().getStream()); 481 + Boolean ready = zlmServerFactory.isStreamReady(mediaServerItemForStreamInfo, inviteInfoForOld.getStreamInfo().getApp(), inviteInfoForOld.getStreamInfo().getStream());
476 if (!ready) { 482 if (!ready) {
477 // 错误存在于redis中的数据 483 // 错误存在于redis中的数据
478 - inviteStreamService.removeInviteInfo(inviteInfo); 484 + inviteStreamService.removeInviteInfo(inviteInfoForOld);
479 }else { 485 }else {
480 // 流确实尚在推流,直接回调结果 486 // 流确实尚在推流,直接回调结果
481 OnStreamChangedHookParam hookParam = new OnStreamChangedHookParam(); 487 OnStreamChangedHookParam hookParam = new OnStreamChangedHookParam();
482 - hookParam.setApp(inviteInfo.getStreamInfo().getApp());  
483 - hookParam.setStream(inviteInfo.getStreamInfo().getStream()); 488 + hookParam.setApp(inviteInfoForOld.getStreamInfo().getApp());
  489 + hookParam.setStream(inviteInfoForOld.getStreamInfo().getStream());
484 490
485 hookEvent.response(mediaServerItemForStreamInfo, hookParam); 491 hookEvent.response(mediaServerItemForStreamInfo, hookParam);
486 return; 492 return;
@@ -515,6 +521,11 @@ public class PlatformServiceImpl implements IPlatformService { @@ -515,6 +521,11 @@ public class PlatformServiceImpl implements IPlatformService {
515 logger.info("[国标级联] 语音喊话,发起Invite消息 deviceId: {}, channelId: {},收流端口: {}, 收流模式:{}, SSRC: {}, SSRC校验:{}", 521 logger.info("[国标级联] 语音喊话,发起Invite消息 deviceId: {}, channelId: {},收流端口: {}, 收流模式:{}, SSRC: {}, SSRC校验:{}",
516 platform.getServerGBId(), channelId, ssrcInfo.getPort(), userSetting.getBroadcastForPlatform(), ssrcInfo.getSsrc(), ssrcCheck); 522 platform.getServerGBId(), channelId, ssrcInfo.getPort(), userSetting.getBroadcastForPlatform(), ssrcInfo.getSsrc(), ssrcCheck);
517 523
  524 + // 初始化redis中的invite消息状态
  525 + InviteInfo inviteInfo = InviteInfo.getInviteInfo(platform.getServerGBId(), channelId, ssrcInfo.getStream(), ssrcInfo,
  526 + mediaServerItem.getSdpIp(), ssrcInfo.getPort(), userSetting.getBroadcastForPlatform(), InviteSessionType.BROADCAST,
  527 + InviteSessionStatus.ready);
  528 + inviteStreamService.updateInviteInfo(inviteInfo);
518 String timeOutTaskKey = UUID.randomUUID().toString(); 529 String timeOutTaskKey = UUID.randomUUID().toString();
519 dynamicTask.startDelay(timeOutTaskKey, () -> { 530 dynamicTask.startDelay(timeOutTaskKey, () -> {
520 // 执行超时任务时查询是否已经成功,成功了则不执行超时任务,防止超时任务取消失败的情况 531 // 执行超时任务时查询是否已经成功,成功了则不执行超时任务,防止超时任务取消失败的情况
@@ -545,50 +556,206 @@ public class PlatformServiceImpl implements IPlatformService { @@ -545,50 +556,206 @@ public class PlatformServiceImpl implements IPlatformService {
545 hookEvent.response(mediaServerItem, hookParam); 556 hookEvent.response(mediaServerItem, hookParam);
546 } 557 }
547 }, event -> { 558 }, event -> {
548 - // 收到200OK 检测ssrc是否有变化,防止上级自定义了ssrc  
549 - ResponseEvent responseEvent = (ResponseEvent) event.event;  
550 - String contentString = new String(responseEvent.getResponse().getRawContent());  
551 - // 获取ssrc  
552 - int ssrcIndex = contentString.indexOf("y=");  
553 - // 检查是否有y字段  
554 - if (ssrcIndex >= 0) {  
555 - //ssrc规定长度为10字节,不取余下长度以避免后续还有“f=”字段 TODO 后续对不规范的非10位ssrc兼容  
556 - String ssrcInResponse = contentString.substring(ssrcIndex + 2, ssrcIndex + 12);  
557 - // 查询到ssrc不一致且开启了ssrc校验则需要针对处理  
558 - if (ssrcInfo.getSsrc().equals(ssrcInResponse) || ssrcCheck) {  
559 - return; 559 +
  560 + inviteOKHandler(event, ssrcInfo, tcpMode, ssrcCheck, mediaServerItem, platform, channelId, timeOutTaskKey,
  561 + null, inviteInfo, InviteSessionType.BROADCAST);
  562 +// // 收到200OK 检测ssrc是否有变化,防止上级自定义了ssrc
  563 +// ResponseEvent responseEvent = (ResponseEvent) event.event;
  564 +// String contentString = new String(responseEvent.getResponse().getRawContent());
  565 +// // 获取ssrc
  566 +// int ssrcIndex = contentString.indexOf("y=");
  567 +// // 检查是否有y字段
  568 +// if (ssrcIndex >= 0) {
  569 +// //ssrc规定长度为10字节,不取余下长度以避免后续还有“f=”字段 TODO 后续对不规范的非10位ssrc兼容
  570 +// String ssrcInResponse = contentString.substring(ssrcIndex + 2, ssrcIndex + 12);
  571 +// // 查询到ssrc不一致且开启了ssrc校验则需要针对处理
  572 +// if (ssrcInfo.getSsrc().equals(ssrcInResponse) || ssrcCheck) {
  573 +// tcpActiveHandler(platform, )
  574 +// return;
  575 +// }
  576 +// logger.info("[点播消息] 收到invite 200, 发现下级自定义了ssrc: {}", ssrcInResponse);
  577 +// if (!mediaServerItem.isRtpEnable()) {
  578 +// logger.info("[点播消息] SSRC修正 {}->{}", ssrcInfo.getSsrc(), ssrcInResponse);
  579 +// // 释放ssrc
  580 +// mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
  581 +// // 单端口模式streamId也有变化,需要重新设置监听
  582 +// if (!mediaServerItem.isRtpEnable()) {
  583 +// // 添加订阅
  584 +// HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", ssrcInfo.getStream(), true, "rtsp", mediaServerItem.getId());
  585 +// subscribe.removeSubscribe(hookSubscribe);
  586 +// hookSubscribe.getContent().put("stream", String.format("%08x", Integer.parseInt(ssrcInResponse)).toUpperCase());
  587 +// subscribe.addSubscribe(hookSubscribe, (mediaServerItemInUse, hookParam) -> {
  588 +// logger.info("[ZLM HOOK] ssrc修正后收到订阅消息: " + hookParam);
  589 +// dynamicTask.stop(timeOutTaskKey);
  590 +// // hook响应
  591 +// playService.onPublishHandlerForPlay(mediaServerItemInUse, hookParam, platform.getServerGBId(), channelId);
  592 +// hookEvent.response(mediaServerItemInUse, hookParam);
  593 +// });
  594 +// }
  595 +// // 关闭rtp server
  596 +// mediaServerService.closeRTPServer(mediaServerItem, ssrcInfo.getStream());
  597 +// // 重新开启ssrc server
  598 +// mediaServerService.openRTPServer(mediaServerItem, ssrcInfo.getStream(), ssrcInResponse, false, false, ssrcInfo.getPort(), true, false, tcpMode);
  599 +// }
  600 +// }
  601 + }, eventResult -> {
  602 + // 收到错误回复
  603 + if (errorEvent != null) {
  604 + errorEvent.response(eventResult);
  605 + }
  606 + });
  607 + }
  608 +
  609 + private void inviteOKHandler(SipSubscribe.EventResult eventResult, SSRCInfo ssrcInfo, int tcpMode, boolean ssrcCheck, MediaServerItem mediaServerItem,
  610 + ParentPlatform platform, String channelId, String timeOutTaskKey, ErrorCallback<Object> callback,
  611 + InviteInfo inviteInfo, InviteSessionType inviteSessionType){
  612 + inviteInfo.setStatus(InviteSessionStatus.ok);
  613 + ResponseEvent responseEvent = (ResponseEvent) eventResult.event;
  614 + String contentString = new String(responseEvent.getResponse().getRawContent());
  615 + System.out.println(1111);
  616 + System.out.println(contentString);
  617 + String ssrcInResponse = SipUtils.getSsrcFromSdp(contentString);
  618 + // 兼容回复的消息中缺少ssrc(y字段)的情况
  619 + if (ssrcInResponse == null) {
  620 + ssrcInResponse = ssrcInfo.getSsrc();
  621 + }
  622 + if (ssrcInfo.getSsrc().equals(ssrcInResponse)) {
  623 + // ssrc 一致
  624 + if (mediaServerItem.isRtpEnable()) {
  625 + // 多端口
  626 + if (tcpMode == 2) {
  627 + tcpActiveHandler(platform, channelId, contentString, mediaServerItem, tcpMode, ssrcCheck,
  628 + timeOutTaskKey, ssrcInfo, callback);
  629 + }
  630 + }else {
  631 + // 单端口
  632 + if (tcpMode == 2) {
  633 + logger.warn("[Invite 200OK] 单端口收流模式不支持tcp主动模式收流");
560 } 634 }
561 - logger.info("[点播消息] 收到invite 200, 发现下级自定义了ssrc: {}", ssrcInResponse);  
562 - if (!mediaServerItem.isRtpEnable()) {  
563 - logger.info("[点播消息] SSRC修正 {}->{}", ssrcInfo.getSsrc(), ssrcInResponse); 635 + }
  636 + }else {
  637 + logger.info("[Invite 200OK] 收到invite 200, 发现下级自定义了ssrc: {}", ssrcInResponse);
  638 + // ssrc 不一致
  639 + if (mediaServerItem.isRtpEnable()) {
  640 + // 多端口
  641 + if (ssrcCheck) {
  642 + // ssrc检验
  643 + // 更新ssrc
  644 + logger.info("[Invite 200OK] SSRC修正 {}->{}", ssrcInfo.getSsrc(), ssrcInResponse);
564 // 释放ssrc 645 // 释放ssrc
565 mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc()); 646 mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
566 - // 单端口模式streamId也有变化,需要重新设置监听  
567 - if (!mediaServerItem.isRtpEnable()) {  
568 - // 添加订阅  
569 - HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", ssrcInfo.getStream(), true, "rtsp", mediaServerItem.getId());  
570 - subscribe.removeSubscribe(hookSubscribe);  
571 - hookSubscribe.getContent().put("stream", String.format("%08x", Integer.parseInt(ssrcInResponse)).toUpperCase());  
572 - subscribe.addSubscribe(hookSubscribe, (mediaServerItemInUse, hookParam) -> {  
573 - logger.info("[ZLM HOOK] ssrc修正后收到订阅消息: " + hookParam);  
574 - dynamicTask.stop(timeOutTaskKey);  
575 - // hook响应  
576 - playService.onPublishHandlerForPlay(mediaServerItemInUse, hookParam, platform.getServerGBId(), channelId);  
577 - hookEvent.response(mediaServerItemInUse, hookParam);  
578 - }); 647 + Boolean result = mediaServerService.updateRtpServerSSRC(mediaServerItem, ssrcInfo.getStream(), ssrcInResponse);
  648 + if (!result) {
  649 + try {
  650 + logger.warn("[Invite 200OK] 更新ssrc失败,停止喊话 {}/{}", platform.getServerGBId(), channelId);
  651 + commanderForPlatform.streamByeCmd(platform, channelId, ssrcInfo.getStream(), null, null);
  652 + } catch (InvalidArgumentException | SipException | ParseException | SsrcTransactionNotFoundException e) {
  653 + logger.error("[命令发送失败] 停止播放, 发送BYE: {}", e.getMessage());
  654 + }
  655 +
  656 + dynamicTask.stop(timeOutTaskKey);
  657 + // 释放ssrc
  658 + mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
  659 +
  660 + streamSession.remove(platform.getServerGBId(), channelId, ssrcInfo.getStream());
  661 +
  662 + callback.run(InviteErrorCode.ERROR_FOR_RESET_SSRC.getCode(),
  663 + "下级自定义了ssrc,重新设置收流信息失败", null);
  664 + inviteStreamService.call(inviteSessionType, platform.getServerGBId(), channelId, null,
  665 + InviteErrorCode.ERROR_FOR_RESET_SSRC.getCode(),
  666 + "下级自定义了ssrc,重新设置收流信息失败", null);
  667 +
  668 + }else {
  669 + ssrcInfo.setSsrc(ssrcInResponse);
  670 + inviteInfo.setSsrcInfo(ssrcInfo);
  671 + inviteInfo.setStream(ssrcInfo.getStream());
  672 + if (tcpMode == 2) {
  673 + if (mediaServerItem.isRtpEnable()) {
  674 + tcpActiveHandler(platform, channelId, contentString, mediaServerItem, tcpMode, ssrcCheck,
  675 + timeOutTaskKey, ssrcInfo, callback);
  676 + }else {
  677 + logger.warn("[Invite 200OK] 单端口收流模式不支持tcp主动模式收流");
  678 + }
  679 + }
  680 + inviteStreamService.updateInviteInfo(inviteInfo);
579 } 681 }
580 - // 关闭rtp server  
581 - mediaServerService.closeRTPServer(mediaServerItem, ssrcInfo.getStream());  
582 - // 重新开启ssrc server  
583 - mediaServerService.openRTPServer(mediaServerItem, ssrcInfo.getStream(), ssrcInResponse, false, false, ssrcInfo.getPort(), true, false, tcpMode); 682 + }else {
  683 + ssrcInfo.setSsrc(ssrcInResponse);
  684 + inviteInfo.setSsrcInfo(ssrcInfo);
  685 + inviteInfo.setStream(ssrcInfo.getStream());
  686 + if (tcpMode == 2) {
  687 + if (mediaServerItem.isRtpEnable()) {
  688 + tcpActiveHandler(platform, channelId, contentString, mediaServerItem, tcpMode, ssrcCheck,
  689 + timeOutTaskKey, ssrcInfo, callback);
  690 + }else {
  691 + logger.warn("[Invite 200OK] 单端口收流模式不支持tcp主动模式收流");
  692 + }
  693 + }
  694 + inviteStreamService.updateInviteInfo(inviteInfo);
  695 + }
  696 + }else {
  697 + if (ssrcInResponse != null) {
  698 + // 单端口
  699 + // 重新订阅流上线
  700 + SsrcTransaction ssrcTransaction = streamSession.getSsrcTransaction(inviteInfo.getDeviceId(),
  701 + inviteInfo.getChannelId(), null, inviteInfo.getStream());
  702 + streamSession.remove(inviteInfo.getDeviceId(),
  703 + inviteInfo.getChannelId(), inviteInfo.getStream());
  704 + inviteStreamService.updateInviteInfoForSSRC(inviteInfo, ssrcInResponse);
  705 + streamSession.put(platform.getServerGBId(), channelId, ssrcTransaction.getCallId(),
  706 + inviteInfo.getStream(), ssrcInResponse, mediaServerItem.getId(), (SIPResponse) responseEvent.getResponse(), inviteSessionType);
584 } 707 }
585 } 708 }
586 - }, eventResult -> {  
587 - // 收到错误回复  
588 - if (errorEvent != null) {  
589 - errorEvent.response(eventResult); 709 + }
  710 + }
  711 +
  712 +
  713 + private void tcpActiveHandler(ParentPlatform platform, String channelId, String contentString,
  714 + MediaServerItem mediaServerItem, int tcpMode, boolean ssrcCheck,
  715 + String timeOutTaskKey, SSRCInfo ssrcInfo, ErrorCallback<Object> callback){
  716 + if (tcpMode != 2) {
  717 + return;
  718 + }
  719 +
  720 + String substring;
  721 + if (contentString.indexOf("y=") > 0) {
  722 + substring = contentString.substring(0, contentString.indexOf("y="));
  723 + }else {
  724 + substring = contentString;
  725 + }
  726 + try {
  727 + SessionDescription sdp = SdpFactory.getInstance().createSessionDescription(substring);
  728 + int port = -1;
  729 + Vector mediaDescriptions = sdp.getMediaDescriptions(true);
  730 + for (Object description : mediaDescriptions) {
  731 + MediaDescription mediaDescription = (MediaDescription) description;
  732 + Media media = mediaDescription.getMedia();
  733 +
  734 + Vector mediaFormats = media.getMediaFormats(false);
  735 + if (mediaFormats.contains("8") || mediaFormats.contains("0")) {
  736 + port = media.getMediaPort();
  737 + break;
  738 + }
590 } 739 }
591 - }); 740 + logger.info("[TCP主动连接对方] serverGbId: {}, channelId: {}, 连接对方的地址:{}:{}, SSRC: {}, SSRC校验:{}",
  741 + platform.getServerGBId(), channelId, sdp.getConnection().getAddress(), port, ssrcInfo.getSsrc(), ssrcCheck);
  742 + JSONObject jsonObject = zlmresTfulUtils.connectRtpServer(mediaServerItem, sdp.getConnection().getAddress(), port, ssrcInfo.getStream());
  743 + logger.info("[TCP主动连接对方] 结果: {}", jsonObject);
  744 + } catch (SdpException e) {
  745 + logger.error("[TCP主动连接对方] serverGbId: {}, channelId: {}, 解析200OK的SDP信息失败", platform.getServerGBId(), channelId, e);
  746 + dynamicTask.stop(timeOutTaskKey);
  747 + mediaServerService.closeRTPServer(mediaServerItem, ssrcInfo.getStream());
  748 + // 释放ssrc
  749 + mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
  750 +
  751 + streamSession.remove(platform.getServerGBId(), channelId, ssrcInfo.getStream());
  752 +
  753 + callback.run(InviteErrorCode.ERROR_FOR_SDP_PARSING_EXCEPTIONS.getCode(),
  754 + InviteErrorCode.ERROR_FOR_SDP_PARSING_EXCEPTIONS.getMsg(), null);
  755 + inviteStreamService.call(InviteSessionType.PLAY, platform.getServerGBId(), channelId, null,
  756 + InviteErrorCode.ERROR_FOR_SDP_PARSING_EXCEPTIONS.getCode(),
  757 + InviteErrorCode.ERROR_FOR_SDP_PARSING_EXCEPTIONS.getMsg(), null);
  758 + }
592 } 759 }
593 760
594 @Override 761 @Override
src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStorageImpl.java
@@ -18,7 +18,6 @@ import com.genersoft.iot.vmp.vmanager.gb28181.platform.bean.ChannelReduce; @@ -18,7 +18,6 @@ import com.genersoft.iot.vmp.vmanager.gb28181.platform.bean.ChannelReduce;
18 import com.genersoft.iot.vmp.web.gb28181.dto.DeviceChannelExtend; 18 import com.genersoft.iot.vmp.web.gb28181.dto.DeviceChannelExtend;
19 import com.github.pagehelper.PageHelper; 19 import com.github.pagehelper.PageHelper;
20 import com.github.pagehelper.PageInfo; 20 import com.github.pagehelper.PageInfo;
21 -import com.sun.org.apache.xml.internal.resolver.Catalog;  
22 import org.slf4j.Logger; 21 import org.slf4j.Logger;
23 import org.slf4j.LoggerFactory; 22 import org.slf4j.LoggerFactory;
24 import org.springframework.beans.factory.annotation.Autowired; 23 import org.springframework.beans.factory.annotation.Autowired;