From 446f729e559730b813291f072a6e33a012923018 Mon Sep 17 00:00:00 2001 From: 648540858 <648540858@qq.com> Date: Sat, 10 Jun 2023 00:32:42 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96sdp=E8=A7=A3=E6=9E=90?= =?UTF-8?q?=EF=BC=8C=E5=85=BC=E5=AE=B9=E5=B8=A6=E6=9C=89f=3D=E7=9A=84?= =?UTF-8?q?=E8=AE=BE=E5=A4=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../iot/vmp/gb28181/bean/Gb28181Sdp.java | 46 ++++++++++++++++ .../cmd/SIPRequestHeaderPlarformProvider.java | 4 +- .../transmit/cmd/impl/SIPCommander.java | 6 +-- .../request/impl/InviteRequestProcessor.java | 37 ++++--------- .../impl/InviteResponseProcessor.java | 17 ++---- .../iot/vmp/gb28181/utils/SipUtils.java | 52 +++++++++++++++++++ .../iot/vmp/service/impl/PlayServiceImpl.java | 33 ++++++------ 7 files changed, 129 insertions(+), 66 deletions(-) create mode 100644 src/main/java/com/genersoft/iot/vmp/gb28181/bean/Gb28181Sdp.java diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/Gb28181Sdp.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/Gb28181Sdp.java new file mode 100644 index 00000000..4b9e26a0 --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/Gb28181Sdp.java @@ -0,0 +1,46 @@ +package com.genersoft.iot.vmp.gb28181.bean; + +import javax.sdp.SessionDescription; + +/** + * 28181 的SDP解析器 + */ +public class Gb28181Sdp { + private SessionDescription baseSdb; + private String ssrc; + + private String mediaDescription; + + public static Gb28181Sdp getInstance(SessionDescription baseSdb, String ssrc, String mediaDescription) { + Gb28181Sdp gb28181Sdp = new Gb28181Sdp(); + gb28181Sdp.setBaseSdb(baseSdb); + gb28181Sdp.setSsrc(ssrc); + gb28181Sdp.setMediaDescription(mediaDescription); + return gb28181Sdp; + } + + + public SessionDescription getBaseSdb() { + return baseSdb; + } + + public void setBaseSdb(SessionDescription baseSdb) { + this.baseSdb = baseSdb; + } + + public String getSsrc() { + return ssrc; + } + + public void setSsrc(String ssrc) { + this.ssrc = ssrc; + } + + public String getMediaDescription() { + return mediaDescription; + } + + public void setMediaDescription(String mediaDescription) { + this.mediaDescription = mediaDescription; + } +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderPlarformProvider.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderPlarformProvider.java index 831897a7..22017df8 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderPlarformProvider.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderPlarformProvider.java @@ -54,8 +54,8 @@ public class SIPRequestHeaderPlarformProvider { parentPlatform.getServerIP() + ":" + parentPlatform.getServerPort()); //via ArrayList viaHeaders = new ArrayList(); - ViaHeader viaHeader = SipFactory.getInstance().createHeaderFactory().createViaHeader(parentPlatform.getServerIP(), - parentPlatform.getServerPort(), parentPlatform.getTransport(), SipUtils.getNewViaTag()); + ViaHeader viaHeader = SipFactory.getInstance().createHeaderFactory().createViaHeader(parentPlatform.getDeviceIp(), + Integer.parseInt(parentPlatform.getDevicePort()), parentPlatform.getTransport(), SipUtils.getNewViaTag()); viaHeader.setRPort(); viaHeaders.add(viaHeader); //from diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java index 6992a99b..1ce072fa 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java @@ -574,11 +574,7 @@ public class SIPCommander implements ISIPCommander { ResponseEvent responseEvent = (ResponseEvent) event.event; SIPResponse response = (SIPResponse) responseEvent.getResponse(); String contentString =new String(response.getRawContent()); - int ssrcIndex = contentString.indexOf("y="); - String ssrc=ssrcInfo.getSsrc(); - if (ssrcIndex >= 0) { - ssrc = contentString.substring(ssrcIndex + 2, ssrcIndex + 12); - } + String ssrc = SipUtils.getSsrcFromSdp(contentString); streamSession.put(device.getDeviceId(), channelId, response.getCallIdHeader().getCallId(), ssrcInfo.getStream(), ssrc, mediaServerItem.getId(), response, InviteSessionType.DOWNLOAD); okEvent.response(event); }); diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java index 07a1538e..e21dfd6d 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java @@ -241,18 +241,8 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements // 解析sdp消息, 使用jainsip 自带的sdp解析方式 String contentString = new String(request.getRawContent()); - // jainSip不支持y=字段, 移除以解析。 - // 检查是否有y字段 - int ssrcIndex = contentString.indexOf("y="); - - SessionDescription sdp; - if (ssrcIndex >= 0) { - //ssrc规定长度为10个字节,不取余下长度以避免后续还有“f=”字段 - String substring = contentString.substring(0, ssrcIndex); - sdp = SdpFactory.getInstance().createSessionDescription(substring); - } else { - sdp = SdpFactory.getInstance().createSessionDescription(contentString); - } + Gb28181Sdp gb28181Sdp = SipUtils.parseSDP(contentString); + SessionDescription sdp = gb28181Sdp.getBaseSdb(); String sessionName = sdp.getSessionName().getValue(); Long startTime = null; @@ -340,11 +330,11 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements } String ssrc; - if (userSetting.getUseCustomSsrcForParentInvite() || ssrcIndex < 0) { + if (userSetting.getUseCustomSsrcForParentInvite() || gb28181Sdp.getSsrc() == null) { // 上级平台点播时不使用上级平台指定的ssrc,使用自定义的ssrc,参考国标文档-点播外域设备媒体流SSRC处理方式 ssrc = "Play".equalsIgnoreCase(sessionName) ? ssrcFactory.getPlaySsrc(mediaServerItem.getId()) : ssrcFactory.getPlayBackSsrc(mediaServerItem.getId()); }else { - ssrc = contentString.substring(ssrcIndex + 2, ssrcIndex + 12); + ssrc = gb28181Sdp.getSsrc(); } String streamTypeStr = null; if (mediaTransmissionTCP) { @@ -513,11 +503,11 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements } else if (gbStream != null) { String ssrc; - if (userSetting.getUseCustomSsrcForParentInvite() || ssrcIndex < 0) { + if (userSetting.getUseCustomSsrcForParentInvite() || gb28181Sdp.getSsrc() == null) { // 上级平台点播时不使用上级平台指定的ssrc,使用自定义的ssrc,参考国标文档-点播外域设备媒体流SSRC处理方式 ssrc = "Play".equalsIgnoreCase(sessionName) ? ssrcFactory.getPlaySsrc(mediaServerItem.getId()) : ssrcFactory.getPlayBackSsrc(mediaServerItem.getId()); }else { - ssrc = contentString.substring(ssrcIndex + 2, ssrcIndex + 12); + ssrc = gb28181Sdp.getSsrc(); } if("push".equals(gbStream.getStreamType())) { @@ -891,20 +881,11 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements } String contentString = new String(request.getRawContent()); // jainSip不支持y=字段, 移除移除以解析。 - String substring = contentString; String ssrc = "0000000404"; - int ssrcIndex = contentString.indexOf("y="); - if (ssrcIndex > 0) { - substring = contentString.substring(0, ssrcIndex); - ssrc = contentString.substring(ssrcIndex + 2, ssrcIndex + 12); - } - ssrcIndex = substring.indexOf("f="); - if (ssrcIndex > 0) { - substring = contentString.substring(0, ssrcIndex); - } - SessionDescription sdp = null; + try { - sdp = SdpFactory.getInstance().createSessionDescription(substring); + Gb28181Sdp gb28181Sdp = SipUtils.parseSDP(contentString); + SessionDescription sdp = gb28181Sdp.getBaseSdb(); // 获取支持的格式 Vector mediaDescriptions = sdp.getMediaDescriptions(true); // 查看是否支持PS 负载96 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/response/impl/InviteResponseProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/response/impl/InviteResponseProcessor.java index f647b96b..436d2a43 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/response/impl/InviteResponseProcessor.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/response/impl/InviteResponseProcessor.java @@ -1,10 +1,12 @@ package com.genersoft.iot.vmp.gb28181.transmit.event.response.impl; import com.genersoft.iot.vmp.gb28181.SipLayer; +import com.genersoft.iot.vmp.gb28181.bean.Gb28181Sdp; import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver; import com.genersoft.iot.vmp.gb28181.transmit.SIPSender; import com.genersoft.iot.vmp.gb28181.transmit.cmd.SIPRequestHeaderProvider; import com.genersoft.iot.vmp.gb28181.transmit.event.response.SIPResponseProcessorAbstract; +import com.genersoft.iot.vmp.gb28181.utils.SipUtils; import gov.nist.javax.sip.ResponseEventExt; import gov.nist.javax.sip.message.SIPResponse; import org.slf4j.Logger; @@ -12,7 +14,6 @@ import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; -import javax.sdp.SdpFactory; import javax.sdp.SdpParseException; import javax.sdp.SessionDescription; import javax.sip.InvalidArgumentException; @@ -79,18 +80,8 @@ public class InviteResponseProcessor extends SIPResponseProcessorAbstract { ResponseEventExt event = (ResponseEventExt)evt; String contentString = new String(response.getRawContent()); - // jainSip不支持y=字段, 移除以解析。 - int ssrcIndex = contentString.indexOf("y="); - // 检查是否有y字段 - SessionDescription sdp; - if (ssrcIndex >= 0) { - //ssrc规定长度为10字节,不取余下长度以避免后续还有“f=”字段 - String substring = contentString.substring(0, contentString.indexOf("y=")); - sdp = SdpFactory.getInstance().createSessionDescription(substring); - } else { - sdp = SdpFactory.getInstance().createSessionDescription(contentString); - } - + Gb28181Sdp gb28181Sdp = SipUtils.parseSDP(contentString); + SessionDescription sdp = gb28181Sdp.getBaseSdb(); SipURI requestUri = SipFactory.getInstance().createAddressFactory().createSipURI(sdp.getOrigin().getUsername(), event.getRemoteIpAddress() + ":" + event.getRemotePort()); Request reqAck = headerProvider.createAckRequest(response.getLocalAddress().getHostAddress(), requestUri, response); diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/utils/SipUtils.java b/src/main/java/com/genersoft/iot/vmp/gb28181/utils/SipUtils.java index 29bf66fe..29f1654c 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/utils/SipUtils.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/utils/SipUtils.java @@ -1,6 +1,7 @@ package com.genersoft.iot.vmp.gb28181.utils; import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; +import com.genersoft.iot.vmp.gb28181.bean.Gb28181Sdp; import com.genersoft.iot.vmp.gb28181.bean.RemoteAddressInfo; import com.genersoft.iot.vmp.utils.GitUtil; import gov.nist.javax.sip.address.AddressImpl; @@ -10,6 +11,9 @@ import gov.nist.javax.sip.message.SIPRequest; import org.apache.commons.lang3.RandomStringUtils; import org.springframework.util.ObjectUtils; +import javax.sdp.SdpFactory; +import javax.sdp.SdpParseException; +import javax.sdp.SessionDescription; import javax.sip.PeerUnavailableException; import javax.sip.SipFactory; import javax.sip.header.FromHeader; @@ -190,4 +194,52 @@ public class SipUtils { } return deviceChannel; } + + public static Gb28181Sdp parseSDP(String sdpStr) throws SdpParseException { + + // jainSip不支持y= f=字段, 移除以解析。 + int ssrcIndex = sdpStr.indexOf("y="); + int mediaDescriptionIndex = sdpStr.indexOf("f="); + // 检查是否有y字段 + SessionDescription sdp; + String ssrc = null; + String mediaDescription = null; + if (mediaDescriptionIndex == 0 && ssrcIndex == 0) { + sdp = SdpFactory.getInstance().createSessionDescription(sdpStr); + }else { + int baseSdpIndex = Math.min(mediaDescriptionIndex, ssrcIndex); + //ssrc规定长度为10字节,不取余下长度以避免后续还有“f=”字段 + String substring = sdpStr.substring(0, baseSdpIndex); + sdp = SdpFactory.getInstance().createSessionDescription(substring); + + String lines[] = sdpStr.split("\\r?\\n"); + for (String line : lines) { + if (line.trim().startsWith("y=")) { + ssrc = line.substring(2); + }else if (line.trim().startsWith("f=")) { + mediaDescription = line.substring(2); + } + if (ssrc != null && mediaDescription != null) { + break; + } + } + } + return Gb28181Sdp.getInstance(sdp, ssrc, mediaDescription); + } + + public static String getSsrcFromSdp(String sdpStr) { + + // jainSip不支持y= f=字段, 移除以解析。 + int ssrcIndex = sdpStr.indexOf("y="); + if (ssrcIndex == 0) { + return null; + } + String lines[] = sdpStr.split("\\r?\\n"); + for (String line : lines) { + if (line.trim().startsWith("y=")) { + return line.substring(2); + } + } + return null; + } } diff --git a/src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java index efba170e..39078952 100644 --- a/src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java @@ -18,6 +18,7 @@ import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager; import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform; +import com.genersoft.iot.vmp.gb28181.utils.SipUtils; import com.genersoft.iot.vmp.media.zlm.AssistRESTfulUtils; import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils; import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory; @@ -297,17 +298,16 @@ public class PlayServiceImpl implements IPlayService { ResponseEvent responseEvent = (ResponseEvent) event.event; String contentString = new String(responseEvent.getResponse().getRawContent()); // 获取ssrc - int ssrcIndex = contentString.indexOf("y="); + String ssrcInResponse = SipUtils.getSsrcFromSdp(contentString); + // 检查是否有y字段 - if (ssrcIndex >= 0) { - //ssrc规定长度为10字节,不取余下长度以避免后续还有“f=”字段 TODO 后续对不规范的非10位ssrc兼容 - String ssrcInResponse = contentString.substring(ssrcIndex + 2, ssrcIndex + 12).trim(); + if (ssrcInResponse != null) { // 查询到ssrc不一致且开启了ssrc校验则需要针对处理 if (ssrcInfo.getSsrc().equals(ssrcInResponse)) { if (device.getStreamMode().equalsIgnoreCase("TCP-ACTIVE")) { - String substring = contentString.substring(0, contentString.indexOf("y=")); try { - SessionDescription sdp = SdpFactory.getInstance().createSessionDescription(substring); + Gb28181Sdp gb28181Sdp = SipUtils.parseSDP(contentString); + SessionDescription sdp = gb28181Sdp.getBaseSdb(); int port = -1; Vector mediaDescriptions = sdp.getMediaDescriptions(true); for (Object description : mediaDescriptions) { @@ -607,17 +607,16 @@ public class PlayServiceImpl implements IPlayService { ResponseEvent responseEvent = (ResponseEvent) eventResult.event; String contentString = new String(responseEvent.getResponse().getRawContent()); // 获取ssrc - int ssrcIndex = contentString.indexOf("y="); + String ssrcInResponse = SipUtils.getSsrcFromSdp(contentString); + // 检查是否有y字段 - if (ssrcIndex >= 0) { - //ssrc规定长度为10字节,不取余下长度以避免后续还有“f=”字段 TODO 后续对不规范的非10位ssrc兼容 - String ssrcInResponse = contentString.substring(ssrcIndex + 2, ssrcIndex + 12); + if (ssrcInResponse != null) { // 查询到ssrc不一致且开启了ssrc校验则需要针对处理 if (ssrcInfo.getSsrc().equals(ssrcInResponse)) { if (device.getStreamMode().equalsIgnoreCase("TCP-ACTIVE")) { - String substring = contentString.substring(0, contentString.indexOf("y=")); try { - SessionDescription sdp = SdpFactory.getInstance().createSessionDescription(substring); + Gb28181Sdp gb28181Sdp = SipUtils.parseSDP(contentString); + SessionDescription sdp = gb28181Sdp.getBaseSdb(); int port = -1; Vector mediaDescriptions = sdp.getMediaDescriptions(true); for (Object description : mediaDescriptions) { @@ -800,17 +799,15 @@ public class PlayServiceImpl implements IPlayService { ResponseEvent responseEvent = (ResponseEvent) eventResult.event; String contentString = new String(responseEvent.getResponse().getRawContent()); // 获取ssrc - int ssrcIndex = contentString.indexOf("y="); + String ssrcInResponse = SipUtils.getSsrcFromSdp(contentString); // 检查是否有y字段 - if (ssrcIndex >= 0) { - //ssrc规定长度为10字节,不取余下长度以避免后续还有“f=”字段 TODO 后续对不规范的非10位ssrc兼容 - String ssrcInResponse = contentString.substring(ssrcIndex + 2, ssrcIndex + 12); + if (ssrcInResponse != null) { // 查询到ssrc不一致且开启了ssrc校验则需要针对处理 if (ssrcInfo.getSsrc().equals(ssrcInResponse)) { if (device.getStreamMode().equalsIgnoreCase("TCP-ACTIVE")) { - String substring = contentString.substring(0, contentString.indexOf("y=")); try { - SessionDescription sdp = SdpFactory.getInstance().createSessionDescription(substring); + Gb28181Sdp gb28181Sdp = SipUtils.parseSDP(contentString); + SessionDescription sdp = gb28181Sdp.getBaseSdb(); int port = -1; Vector mediaDescriptions = sdp.getMediaDescriptions(true); for (Object description : mediaDescriptions) {