Kaynağa Gözat

优化sdp解析,兼容带有f=的设备

648540858 2 yıl önce
ebeveyn
işleme
446f729e55

+ 46 - 0
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;
+    }
+}

+ 2 - 2
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<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

+ 1 - 5
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);
         });

+ 9 - 28
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

+ 4 - 13
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);
 

+ 52 - 0
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;
+    }
 }

+ 15 - 18
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) {