分离 gb28181-sip 模块

重新封装 sdp 解析部分
This commit is contained in:
shikong 2023-09-23 20:50:49 +08:00
parent dc030c6844
commit f3ae4156d1
18 changed files with 552 additions and 8 deletions

View File

@ -28,7 +28,7 @@ public class XmlUtils {
// 大驼峰 (首字母大写)
mapper.setPropertyNamingStrategy(new PropertyNamingStrategies.UpperCamelCaseStrategy());
// 添加 xml 头部声明
mapper.configure(ToXmlGenerator.Feature.WRITE_XML_DECLARATION, true);
mapper.configure(ToXmlGenerator.Feature.WRITE_XML_DECLARATION, false);
}
public static String toXml(Object obj) {

View File

@ -46,13 +46,6 @@
<version>1.3.0-91</version>
</dependency>
<!-- xml解析库 -->
<dependency>
<groupId>org.dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>2.1.4</version>
</dependency>
<!--MapStruct-->
<dependency>
<groupId>org.mapstruct</groupId>

38
gb28181-sip/.gitignore vendored Normal file
View File

@ -0,0 +1,38 @@
target/
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**/target/
!**/src/test/**/target/
### IntelliJ IDEA ###
.idea/modules.xml
.idea/jarRepositories.xml
.idea/compiler.xml
.idea/libraries/
*.iws
*.iml
*.ipr
### Eclipse ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
build/
!**/src/main/**/build/
!**/src/test/**/build/
### VS Code ###
.vscode/
### Mac OS ###
.DS_Store

44
gb28181-sip/pom.xml Normal file
View File

@ -0,0 +1,44 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>cn.skcks.docking</groupId>
<artifactId>gb28181</artifactId>
<version>0.1.0-SNAPSHOT</version>
</parent>
<groupId>cn.skcks.docking.gb28181</groupId>
<artifactId>gb28181-sip</artifactId>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>cn.skcks.docking.gb28181</groupId>
<artifactId>common</artifactId>
</dependency>
<!-- sip协议栈 -->
<dependency>
<groupId>javax.sip</groupId>
<artifactId>jain-sip-ri</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,39 @@
package cn.skcks.docking.gb28181.sdp;
import gov.nist.javax.sdp.SessionDescriptionImpl;
import lombok.Getter;
import lombok.Setter;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import javax.sdp.SdpException;
import javax.sdp.SessionDescription;
@Slf4j
@Setter
@Getter
public class GB28181Description extends SessionDescriptionImpl implements SessionDescription {
private SsrcField ssrcField;
private SessionDescriptionImpl sessionDescription;
public GB28181Description(){
super();
}
public GB28181Description(SessionDescription sessionDescription) throws SdpException {
super(sessionDescription);
}
@SneakyThrows
public static GB28181Description build(SessionDescription sessionDescription){
return new GB28181Description(sessionDescription);
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder(super.toString());
sb.append(getSsrcField() == null ? "" : getSsrcField().toString());
// return "+";
return sb.toString();
}
}

View File

@ -0,0 +1,88 @@
package cn.skcks.docking.gb28181.sdp;
import gov.nist.core.ParserCore;
import gov.nist.javax.sdp.SessionDescriptionImpl;
import gov.nist.javax.sdp.fields.SDPField;
import gov.nist.javax.sdp.parser.Lexer;
import gov.nist.javax.sdp.parser.SDPParser;
import java.text.ParseException;
import java.util.Vector;
@SuppressWarnings("all")
public class GB28181DescriptionParser extends ParserCore {
protected Lexer lexer;
protected Vector sdpMessage;
public GB28181DescriptionParser(Vector sdpMessage) {
this.sdpMessage = sdpMessage;
}
public GB28181DescriptionParser(String message) {
int start = 0;
String line = null;
// Return trivially if there is no sdp announce message
// to be parsed. Bruno Konik noticed this bug.
if (message == null) return;
sdpMessage = new Vector();
// Strip off leading and trailing junk.
String sdpAnnounce = message.trim() + "\r\n";
// Bug fix by Andreas Bystrom.
while (start < sdpAnnounce.length()) {
// Major re-write by Ricardo Borba.
int lfPos = sdpAnnounce.indexOf("\n", start);
int crPos = sdpAnnounce.indexOf("\r", start);
if (lfPos >= 0 && crPos < 0) {
// there are only "\n" separators
line = sdpAnnounce.substring(start, lfPos);
start = lfPos + 1;
} else if (lfPos < 0 && crPos >= 0) {
//bug fix: there are only "\r" separators
line = sdpAnnounce.substring(start, crPos);
start = crPos + 1;
} else if (lfPos >= 0 && crPos >= 0) {
// there are "\r\n" or "\n\r" (if exists) separators
if (lfPos > crPos) {
// assume "\r\n" for now
line = sdpAnnounce.substring(start, crPos);
// Check if the "\r" and "\n" are close together
if (lfPos == crPos + 1) {
start = lfPos + 1; // "\r\n"
} else {
start = crPos + 1; // "\r" followed by the next record and a "\n" further away
}
} else {
// assume "\n\r" for now
line = sdpAnnounce.substring(start, lfPos);
// Check if the "\n" and "\r" are close together
if (crPos == lfPos + 1) {
start = crPos + 1; // "\n\r"
} else {
start = lfPos + 1; // "\n" followed by the next record and a "\r" further away
}
}
} else if (lfPos < 0 && crPos < 0) { // end
break;
}
sdpMessage.addElement(line);
}
}
public GB28181Description parse() throws ParseException {
GB28181Description retval = new GB28181Description();
for (int i = 0; i < sdpMessage.size(); i++) {
String field = (String) sdpMessage.elementAt(i);
SDPParser sdpParser = GB28181DescriptionParserFactory.createParser(field);
SDPField sdpField = null;
if (sdpParser != null) {
sdpField = sdpParser.parse();
}
retval.addField(sdpField);
if (sdpField instanceof SsrcField ssrc) {
retval.setSsrcField(ssrc);
}
}
return retval;
}
}

View File

@ -0,0 +1,17 @@
package cn.skcks.docking.gb28181.sdp;
import gov.nist.javax.sdp.parser.Lexer;
import gov.nist.javax.sdp.parser.ParserFactory;
import gov.nist.javax.sdp.parser.SDPParser;
import java.text.ParseException;
public class GB28181DescriptionParserFactory {
public static SDPParser createParser(String field) throws ParseException {
String fieldName = Lexer.getFieldName(field);
if(fieldName.equalsIgnoreCase("y")){
return new SsrcFieldParser(field);
}
return ParserFactory.createParser(field);
}
}

View File

@ -0,0 +1,14 @@
package cn.skcks.docking.gb28181.sdp;
import lombok.Builder;
import lombok.Data;
import javax.sdp.SessionDescription;
@Builder
@Data
public class Gb28181Sdp {
private SessionDescription baseSdb;
private String ssrc;
private String mediaDescription;
}

View File

@ -0,0 +1,28 @@
package cn.skcks.docking.gb28181.sdp;
import gov.nist.core.Separators;
import gov.nist.javax.sdp.fields.SDPField;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
@EqualsAndHashCode(callSuper = true)
@Data
@AllArgsConstructor
public class SsrcField extends SDPField {
private static final String SSRC_FIELD = "y=";
public SsrcField() {
super(SSRC_FIELD);
}
private String ssrc;
@Override
public String encode() {
return SSRC_FIELD + ssrc + Separators.NEWLINE;
}
public String toString(){
return encode();
}
}

View File

@ -0,0 +1,33 @@
package cn.skcks.docking.gb28181.sdp;
import gov.nist.javax.sdp.fields.SDPField;
import gov.nist.javax.sdp.parser.Lexer;
import gov.nist.javax.sdp.parser.SDPParser;
import java.text.ParseException;
public class SsrcFieldParser extends SDPParser {
public SsrcFieldParser(String ssrcField) {
this.lexer = new Lexer("charLexer", ssrcField);
}
public SsrcField ssrcField() throws ParseException {
try {
this.lexer.match('y');
this.lexer.SPorHT();
this.lexer.match('=');
this.lexer.SPorHT();
SsrcField ssrcField = new SsrcField();
String rest = lexer.getRest().trim();
ssrcField.setSsrc(rest);
return ssrcField;
} catch (Exception e) {
throw lexer.createParseException();
}
}
public SDPField parse() throws ParseException {
return this.ssrcField();
}
}

View File

@ -0,0 +1,109 @@
package cn.skcks.docking.gb28181.sip.generic;
import cn.skcks.docking.gb28181.sip.header.XGBVerHeader;
import cn.skcks.docking.gb28181.sip.header.impl.XGBVerHeaderImpl;
import lombok.SneakyThrows;
import org.apache.commons.lang3.StringUtils;
import javax.sip.SipFactory;
import javax.sip.address.Address;
import javax.sip.address.AddressFactory;
import javax.sip.address.SipURI;
import javax.sip.header.*;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class SipBuilder {
public static SipFactory getSipFactory(){
return SipFactory.getInstance();
}
@SneakyThrows
public static AddressFactory createAddressFactory() {
return getSipFactory().createAddressFactory();
}
@SneakyThrows
public static HeaderFactory createHeaderFactory() {
return getSipFactory().createHeaderFactory();
}
@SneakyThrows
public static String createHostAddress(String ip, int port) {
return StringUtils.joinWith(":", ip, port);
}
@SneakyThrows
public static SipURI createSipURI(String id, String address) {
return createAddressFactory().createSipURI(id, address);
}
@SneakyThrows
public static Address createAddress(SipURI uri) {
return createAddressFactory().createAddress(uri);
}
@SneakyThrows
public static ToHeader createToHeader(Address toAddress, String toTag) {
return createHeaderFactory().createToHeader(toAddress, toTag);
}
@SneakyThrows
public static FromHeader createFromHeader(Address fromAddress, String fromTag) {
return createHeaderFactory().createFromHeader(fromAddress, fromTag);
}
@SneakyThrows
public static CSeqHeader createCSeqHeader(long cSeq, String method){
return createHeaderFactory().createCSeqHeader(cSeq, method);
}
@SneakyThrows
public static MaxForwardsHeader createMaxForwardsHeader(int maxForwards) {
return createHeaderFactory().createMaxForwardsHeader(maxForwards);
}
@SneakyThrows
public static ViaHeader createViaHeader(String ip, int port, String transport, String viaTag){
ViaHeader viaHeader = createHeaderFactory().createViaHeader(ip, port, transport, viaTag);
viaHeader.setRPort();
return viaHeader;
}
@SneakyThrows
public static List<ViaHeader> createViaHeaders(String ip, int port, String transport, String viaTag) {
return Collections.singletonList(createViaHeader(ip, port, transport, viaTag));
}
@SneakyThrows
public static ContactHeader createContactHeader(Address address){
return createHeaderFactory().createContactHeader(address);
};
@SneakyThrows
public static ContentTypeHeader createContentTypeHeader(String contentType, String subType){
return createHeaderFactory().createContentTypeHeader(contentType, subType);
}
@SneakyThrows
public static ContentTypeHeader createSDPContentTypeHeader(){
return createHeaderFactory().createContentTypeHeader("APPLICATION", "SDP");
}
public static UserAgentHeader createUserAgentHeader(String userAgent){
return createUserAgentHeader(Arrays.stream(StringUtils.split(userAgent, StringUtils.SPACE)).toList());
}
@SneakyThrows
public static UserAgentHeader createUserAgentHeader(List<String> product){
return createHeaderFactory().createUserAgentHeader(product);
}
@SneakyThrows
public static XGBVerHeader createUserAgentHeader(int m,int n){
return new XGBVerHeaderImpl(m,n);
}
}

View File

@ -0,0 +1,11 @@
package cn.skcks.docking.gb28181.sip.header;
import javax.sip.header.Header;
public interface XGBVerHeader extends Header {
public void setVersion(int m, int n);
public String getVersion();
public final static String NAME = "X-GB-Ver";
}

View File

@ -0,0 +1,31 @@
package cn.skcks.docking.gb28181.sip.header.impl;
import cn.skcks.docking.gb28181.sip.header.XGBVerHeader;
import gov.nist.javax.sip.header.SIPHeader;
public class XGBVerHeaderImpl extends SIPHeader implements XGBVerHeader {
private String version;
@Override
public void setVersion(int m, int n) {
this.version = String.format("%d.%d", m, n);
}
@Override
public String getVersion() {
return version;
}
public XGBVerHeaderImpl(int m, int n) {
super(NAME);
setVersion(m, n);
}
public XGBVerHeaderImpl() {
super(NAME);
}
protected StringBuilder encodeBody(StringBuilder buffer) {
return buffer.append(version);
}
}

View File

@ -0,0 +1,7 @@
package cn.skcks.docking.gb28181.sip.request;
import javax.sip.SipFactory;
public class SipRequestBuilder {
}

View File

@ -0,0 +1,7 @@
package cn.skcks.docking.gb28181.sip.response;
import javax.sip.SipFactory;
public class SipResponseBuilder {
}

View File

@ -0,0 +1,46 @@
package cn.skcks.docking.gb28181.sdp;
import gov.nist.javax.sdp.SessionDescriptionImpl;
import gov.nist.javax.sdp.fields.TimeField;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import javax.sdp.SdpFactory;
import javax.sdp.TimeDescription;
import java.util.Vector;
@Slf4j
public class SdpTest {
@Test
@SneakyThrows
public void test(){
String domain = "4405010000";
TimeField timeField = new TimeField();
timeField.setZero();
TimeDescription timeDescription = SdpFactory.getInstance().createTimeDescription(timeField);
GB28181Description gb28181Description = new GB28181Description();
gb28181Description.setTimeDescriptions(new Vector<>() {{
add(timeDescription);
}});
gb28181Description.setSsrcField(new SsrcField(String.format("%s%04d", domain.substring(3, 8), 1)));
log.info("gb28181 sdp \n{}", gb28181Description);
GB28181DescriptionParser gb28181DescriptionParser = new GB28181DescriptionParser(gb28181Description.toString());
GB28181Description parse = gb28181DescriptionParser.parse();
log.info("gb28181 sdp 解析\n{}",parse);
SessionDescriptionImpl sessionDescription = gb28181Description;
sessionDescription.setTimeDescriptions(new Vector<>() {{
add(timeDescription);
}});
gb28181Description = new GB28181Description(sessionDescription);
gb28181Description.setTimeDescriptions(new Vector<>() {{
add(timeDescription);
}});
log.info("从 SessionDescriptionImpl 转换为 gb28181 sdp \n{}", gb28181Description);
gb28181DescriptionParser = new GB28181DescriptionParser(gb28181Description.toString());
parse = gb28181DescriptionParser.parse();
log.info("从 SessionDescriptionImpl 转换为 gb28181 sdp 解析\n{}",parse);
}
}

View File

@ -0,0 +1,23 @@
package cn.skcks.docking.gb28181.sip;
import cn.skcks.docking.gb28181.sip.generic.SipBuilder;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import javax.sip.address.Address;
import javax.sip.address.SipURI;
@Slf4j
public class SipTest {
@Test
public void test(){
String localIp = "127.0.0.1";
int localPort = 5060;
String localId = "12345678901234567890";
String localHostAddress = SipBuilder.createHostAddress(localIp,localPort);
SipURI localSipUri = SipBuilder.createSipURI(localId, localHostAddress);
Address localAddress = SipBuilder.createAddress(localSipUri);
log.info("{}", localAddress);
}
}

16
pom.xml
View File

@ -22,6 +22,7 @@
<module>gb28181-service</module>
<module>orm</module>
<module>zlmediakit-service</module>
<module>gb28181-sip</module>
</modules>
<properties>
@ -59,6 +60,8 @@
<!-- <docker.registry.username>XXX</docker.registry.username>-->
<!-- <docker.registry.password>XXX</docker.registry.password>-->
<docker.maven.plugin.version>1.4.13</docker.maven.plugin.version>
<jain-sip.version>1.3.0-91</jain-sip.version>
</properties>
<profiles>
@ -97,6 +100,12 @@
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>cn.skcks.docking.gb28181</groupId>
<artifactId>gb28181-sip</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>cn.skcks.docking.gb28181</groupId>
<artifactId>annotation</artifactId>
@ -121,6 +130,13 @@
<version>${project.version}</version>
</dependency>
<!-- sip协议栈 -->
<dependency>
<groupId>javax.sip</groupId>
<artifactId>jain-sip-ri</artifactId>
<version>${jain-sip.version}</version>
</dependency>
<!--MapStruct-->
<dependency>
<groupId>org.mapstruct</groupId>