src/main/java/com/genersoft/iot/vmp/gb28181/bean/Gb28181Sdp.java
New file @@ -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; } } src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderPlarformProvider.java
@@ -54,8 +54,8 @@ parentPlatform.getServerIP() + ":" + parentPlatform.getServerPort()); //via ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>(); 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 src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java
@@ -574,11 +574,7 @@ 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); }); src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java
@@ -241,18 +241,8 @@ // 解析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 @@ } 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 @@ } 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 @@ } 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 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.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 @@ 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); 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 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 @@ } 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; } } src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java
@@ -18,6 +18,7 @@ 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 @@ 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 @@ 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 @@ 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) {