648540858
2023-06-10 446f729e559730b813291f072a6e33a012923018
优化sdp解析,兼容带有f=的设备
6个文件已修改
1个文件已添加
195 ■■■■■ 已修改文件
src/main/java/com/genersoft/iot/vmp/gb28181/bean/Gb28181Sdp.java 46 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderPlarformProvider.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java 37 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/response/impl/InviteResponseProcessor.java 17 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/utils/SipUtils.java 52 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java 33 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
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) {