Commit 66210ec51ae0f20288585293cff5ac187a6d39da
1 parent
c8b0e66e
支持国标级联语音喊话TCP主动模式
Showing
4 changed files
with
219 additions
and
55 deletions
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 | 978 | return; |
| 979 | 979 | } |
| 980 | 980 | String contentString = new String(request.getRawContent()); |
| 981 | - // jainSip不支持y=字段, 移除移除以解析。 | |
| 982 | - String ssrc = "0000000404"; | |
| 983 | 981 | |
| 984 | 982 | try { |
| 985 | 983 | Gb28181Sdp gb28181Sdp = SipUtils.parseSDP(contentString); |
| ... | ... | @@ -1027,7 +1025,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements |
| 1027 | 1025 | return; |
| 1028 | 1026 | } |
| 1029 | 1027 | String addressStr = sdp.getOrigin().getAddress(); |
| 1030 | - logger.info("设备{}请求语音流,地址:{}:{},ssrc:{}, {}", requesterId, addressStr, port, ssrc, | |
| 1028 | + logger.info("设备{}请求语音流,地址:{}:{},ssrc:{}, {}", requesterId, addressStr, port, gb28181Sdp.getSsrc(), | |
| 1031 | 1029 | mediaTransmissionTCP ? (tcpActive ? "TCP主动" : "TCP被动") : "UDP"); |
| 1032 | 1030 | |
| 1033 | 1031 | MediaServerItem mediaServerItem = broadcastCatch.getMediaServerItem(); |
| ... | ... | @@ -1041,11 +1039,11 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements |
| 1041 | 1039 | } |
| 1042 | 1040 | return; |
| 1043 | 1041 | } |
| 1044 | - logger.info("设备{}请求语音流, 收流地址:{}:{},ssrc:{}, {}, 对讲方式:{}", requesterId, addressStr, port, ssrc, | |
| 1042 | + logger.info("设备{}请求语音流, 收流地址:{}:{},ssrc:{}, {}, 对讲方式:{}", requesterId, addressStr, port, gb28181Sdp.getSsrc(), | |
| 1045 | 1043 | mediaTransmissionTCP ? (tcpActive ? "TCP主动" : "TCP被动") : "UDP", sdp.getSessionName().getValue()); |
| 1046 | 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 | 1047 | device.getDeviceId(), broadcastCatch.getChannelId(), |
| 1050 | 1048 | mediaTransmissionTCP, false); |
| 1051 | 1049 | |
| ... | ... | @@ -1081,7 +1079,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements |
| 1081 | 1079 | |
| 1082 | 1080 | Boolean streamReady = zlmServerFactory.isStreamReady(mediaServerItem, broadcastCatch.getApp(), broadcastCatch.getStream()); |
| 1083 | 1081 | if (streamReady) { |
| 1084 | - sendOk(device, sendRtpItem, sdp, request, mediaServerItem, mediaTransmissionTCP, ssrc); | |
| 1082 | + sendOk(device, sendRtpItem, sdp, request, mediaServerItem, mediaTransmissionTCP, gb28181Sdp.getSsrc()); | |
| 1085 | 1083 | } else { |
| 1086 | 1084 | logger.warn("[语音通话], 未发现待推送的流,app={},stream={}", broadcastCatch.getApp(), broadcastCatch.getStream()); |
| 1087 | 1085 | try { | ... | ... |
src/main/java/com/genersoft/iot/vmp/service/impl/MediaServerServiceImpl.java
| ... | ... | @@ -206,7 +206,7 @@ public class MediaServerServiceImpl implements IMediaServerService { |
| 206 | 206 | @Override |
| 207 | 207 | public void closeRTPServer(String mediaServerId, String streamId) { |
| 208 | 208 | MediaServerItem mediaServerItem = this.getOne(mediaServerId); |
| 209 | - if (mediaServerItem.isRtpEnable()) { | |
| 209 | + if (mediaServerItem != null && mediaServerItem.isRtpEnable()) { | |
| 210 | 210 | closeRTPServer(mediaServerItem, streamId); |
| 211 | 211 | } |
| 212 | 212 | zlmresTfulUtils.closeStreams(mediaServerItem, "rtp", streamId); | ... | ... |
src/main/java/com/genersoft/iot/vmp/service/impl/PlatformServiceImpl.java
| 1 | 1 | package com.genersoft.iot.vmp.service.impl; |
| 2 | 2 | |
| 3 | +import com.alibaba.fastjson2.JSONObject; | |
| 3 | 4 | import com.genersoft.iot.vmp.common.InviteInfo; |
| 5 | +import com.genersoft.iot.vmp.common.InviteSessionStatus; | |
| 4 | 6 | import com.genersoft.iot.vmp.common.InviteSessionType; |
| 5 | 7 | import com.baomidou.dynamic.datasource.annotation.DS; |
| 6 | 8 | import com.genersoft.iot.vmp.conf.DynamicTask; |
| ... | ... | @@ -11,6 +13,7 @@ import com.genersoft.iot.vmp.gb28181.event.SipSubscribe; |
| 11 | 13 | import com.genersoft.iot.vmp.gb28181.session.SSRCFactory; |
| 12 | 14 | import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager; |
| 13 | 15 | import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform; |
| 16 | +import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils; | |
| 14 | 17 | import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe; |
| 15 | 18 | import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeFactory; |
| 16 | 19 | import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForStreamChange; |
| ... | ... | @@ -22,20 +25,20 @@ import com.genersoft.iot.vmp.service.IInviteStreamService; |
| 22 | 25 | import com.genersoft.iot.vmp.service.IMediaServerService; |
| 23 | 26 | import com.genersoft.iot.vmp.service.IPlatformService; |
| 24 | 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 | 29 | import com.genersoft.iot.vmp.storager.IRedisCatchStorage; |
| 29 | 30 | import com.genersoft.iot.vmp.storager.dao.*; |
| 30 | 31 | import com.genersoft.iot.vmp.utils.DateUtil; |
| 31 | 32 | import com.github.pagehelper.PageHelper; |
| 32 | 33 | import com.github.pagehelper.PageInfo; |
| 33 | 34 | import gov.nist.javax.sip.message.SIPRequest; |
| 35 | +import gov.nist.javax.sip.message.SIPResponse; | |
| 34 | 36 | import org.slf4j.Logger; |
| 35 | 37 | import org.slf4j.LoggerFactory; |
| 36 | 38 | import org.springframework.beans.factory.annotation.Autowired; |
| 37 | 39 | import org.springframework.stereotype.Service; |
| 38 | 40 | |
| 41 | +import javax.sdp.*; | |
| 39 | 42 | import javax.sip.InvalidArgumentException; |
| 40 | 43 | import javax.sip.ResponseEvent; |
| 41 | 44 | import javax.sip.PeerUnavailableException; |
| ... | ... | @@ -109,6 +112,9 @@ public class PlatformServiceImpl implements IPlatformService { |
| 109 | 112 | @Autowired |
| 110 | 113 | private IInviteStreamService inviteStreamService; |
| 111 | 114 | |
| 115 | + @Autowired | |
| 116 | + private ZLMRESTfulUtils zlmresTfulUtils; | |
| 117 | + | |
| 112 | 118 | |
| 113 | 119 | @Override |
| 114 | 120 | public ParentPlatform queryPlatformByServerGBId(String platformGbId) { |
| ... | ... | @@ -466,21 +472,21 @@ public class PlatformServiceImpl implements IPlatformService { |
| 466 | 472 | logger.info("[国标级联] 语音喊话未找到可用的zlm. platform: {}", platform.getServerGBId()); |
| 467 | 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 | 478 | // 如果zlm不存在这个流,则删除数据即可 |
| 473 | - MediaServerItem mediaServerItemForStreamInfo = mediaServerService.getOne(inviteInfo.getStreamInfo().getMediaServerId()); | |
| 479 | + MediaServerItem mediaServerItemForStreamInfo = mediaServerService.getOne(inviteInfoForOld.getStreamInfo().getMediaServerId()); | |
| 474 | 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 | 482 | if (!ready) { |
| 477 | 483 | // 错误存在于redis中的数据 |
| 478 | - inviteStreamService.removeInviteInfo(inviteInfo); | |
| 484 | + inviteStreamService.removeInviteInfo(inviteInfoForOld); | |
| 479 | 485 | }else { |
| 480 | 486 | // 流确实尚在推流,直接回调结果 |
| 481 | 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 | 491 | hookEvent.response(mediaServerItemForStreamInfo, hookParam); |
| 486 | 492 | return; |
| ... | ... | @@ -515,6 +521,11 @@ public class PlatformServiceImpl implements IPlatformService { |
| 515 | 521 | logger.info("[国标级联] 语音喊话,发起Invite消息 deviceId: {}, channelId: {},收流端口: {}, 收流模式:{}, SSRC: {}, SSRC校验:{}", |
| 516 | 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 | 529 | String timeOutTaskKey = UUID.randomUUID().toString(); |
| 519 | 530 | dynamicTask.startDelay(timeOutTaskKey, () -> { |
| 520 | 531 | // 执行超时任务时查询是否已经成功,成功了则不执行超时任务,防止超时任务取消失败的情况 |
| ... | ... | @@ -545,50 +556,206 @@ public class PlatformServiceImpl implements IPlatformService { |
| 545 | 556 | hookEvent.response(mediaServerItem, hookParam); |
| 546 | 557 | } |
| 547 | 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 | 645 | // 释放ssrc |
| 565 | 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 | 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 | 18 | import com.genersoft.iot.vmp.web.gb28181.dto.DeviceChannelExtend; |
| 19 | 19 | import com.github.pagehelper.PageHelper; |
| 20 | 20 | import com.github.pagehelper.PageInfo; |
| 21 | -import com.sun.org.apache.xml.internal.resolver.Catalog; | |
| 22 | 21 | import org.slf4j.Logger; |
| 23 | 22 | import org.slf4j.LoggerFactory; |
| 24 | 23 | import org.springframework.beans.factory.annotation.Autowired; | ... | ... |