diff --git a/gb28181-service/src/main/java/cn/skcks/docking/gb28181/core/sip/gb28181/sdp/GB28181Description.java b/gb28181-service/src/main/java/cn/skcks/docking/gb28181/core/sip/gb28181/sdp/GB28181Description.java deleted file mode 100644 index f8de8c0..0000000 --- a/gb28181-service/src/main/java/cn/skcks/docking/gb28181/core/sip/gb28181/sdp/GB28181Description.java +++ /dev/null @@ -1,65 +0,0 @@ -package cn.skcks.docking.gb28181.core.sip.gb28181.sdp; - -import gov.nist.javax.sdp.SessionDescriptionImpl; -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.SneakyThrows; -import org.mapstruct.Mapper; -import org.mapstruct.factory.Mappers; - -import javax.sdp.*; -import java.util.Optional; - -@EqualsAndHashCode(callSuper = false) -@Data -public class GB28181Description extends SessionDescriptionImpl implements SessionDescription { - - - public static class Convertor { - @SneakyThrows - public static GB28181Description convert(SessionDescriptionImpl sessionDescription){ - GB28181Description gb28181Description = new GB28181Description(); - SessionName sessionName = sessionDescription.getSessionName(); - if(sessionName != null){ - gb28181Description.setSessionName(sessionName); - } - gb28181Description.setMediaDescriptions(sessionDescription.getMediaDescriptions(true)); - gb28181Description.setBandwidths(sessionDescription.getBandwidths(true)); - - Connection connection = sessionDescription.getConnection(); - if (connection != null){ - gb28181Description.setConnection(connection); - } - - gb28181Description.setEmails(sessionDescription.getEmails(true)); - - gb28181Description.setTimeDescriptions(sessionDescription.getTimeDescriptions(true)); - - Origin origin = sessionDescription.getOrigin(); - if(origin != null){ - gb28181Description.setOrigin(origin); - } - - gb28181Description.setAttributes(sessionDescription.getAttributes(true)); - - URI uri = sessionDescription.getURI(); - if(uri != null){ - gb28181Description.setURI(uri); - } - return gb28181Description; - } - } - - private SsrcField ssrcField; - - GB28181Description(){ - super(); - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(super.toString()); - sb.append(getSsrcField() == null ? "" : getSsrcField().toString()); - return sb.toString(); - } -} diff --git a/gb28181-service/src/main/java/cn/skcks/docking/gb28181/core/sip/gb28181/sdp/Gb28181Sdp.java b/gb28181-service/src/main/java/cn/skcks/docking/gb28181/core/sip/gb28181/sdp/Gb28181Sdp.java deleted file mode 100644 index feeef96..0000000 --- a/gb28181-service/src/main/java/cn/skcks/docking/gb28181/core/sip/gb28181/sdp/Gb28181Sdp.java +++ /dev/null @@ -1,16 +0,0 @@ -package cn.skcks.docking.gb28181.core.sip.gb28181.sdp; - -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; - -import javax.sdp.SessionDescription; - -@Builder -@Data -public class Gb28181Sdp { - private SessionDescription baseSdb; - private String ssrc; - private String mediaDescription; -} diff --git a/gb28181-service/src/main/java/cn/skcks/docking/gb28181/core/sip/gb28181/sdp/MediaSdpHelper.java b/gb28181-service/src/main/java/cn/skcks/docking/gb28181/core/sip/gb28181/sdp/MediaSdpHelper.java deleted file mode 100644 index e42d85e..0000000 --- a/gb28181-service/src/main/java/cn/skcks/docking/gb28181/core/sip/gb28181/sdp/MediaSdpHelper.java +++ /dev/null @@ -1,127 +0,0 @@ -package cn.skcks.docking.gb28181.core.sip.gb28181.sdp; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonValue; -import gov.nist.core.Separators; -import gov.nist.javax.sdp.fields.AttributeField; -import gov.nist.javax.sdp.fields.ConnectionField; -import gov.nist.javax.sdp.fields.TimeField; -import gov.nist.javax.sdp.fields.URIField; -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.SneakyThrows; -import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.ArrayUtils; -import org.apache.commons.lang3.StringUtils; - -import javax.sdp.*; -import java.util.*; - -@Slf4j -public class MediaSdpHelper { - public final static String SEPARATOR = "_"; - public static String getStreamId(String prefix,String... ids){ - return StringUtils.joinWith(SEPARATOR, (Object[]) ArrayUtils.addFirst(ids,prefix)); - } - - public static final Map RTPMAP = new HashMap<>() {{ - put("96", "PS/90000"); - put("126", "H264/90000"); - put("125", "H264S/90000"); - put("99", "H265/90000"); - put("98", "H264/90000"); - put("97", "MPEG4/90000"); - }}; - public static final Map FMTP = new HashMap<>() {{ - put("126", "profile-level-id=42e01e"); - put("125", "profile-level-id=42e01e"); - }}; - - @AllArgsConstructor - @Getter - public enum Action { - PLAY("Play"), - PLAY_BACK("Playback"), - DOWNLOAD("Download"); - - @JsonValue - private final String action; - - @JsonCreator - public static Action fromCode(String action) { - for (Action a : values()) { - if (a.getAction().equalsIgnoreCase(action)) { - return a; - } - } - return null; - } - } - - @SneakyThrows - public static GB28181Description build(Action action, String deviceId, String channelId, String netType, String rtpIp, int rtpPort, String ssrc, StreamMode streamMode, TimeDescription timeDescription){ - log.debug("{} {} {} {} {} {} {} {} {}",action, deviceId, channelId, netType, rtpIp, rtpPort, ssrc, streamMode, timeDescription); - GB28181Description description = new GB28181Description(); - description.setSessionName(SdpFactory.getInstance().createSessionName(action.getAction())); - - Version version = SdpFactory.getInstance().createVersion(0); - description.setVersion(version); - - Connection connectionField = SdpFactory.getInstance().createConnection(ConnectionField.IN, netType, rtpIp); - description.setConnection(connectionField); - - MediaDescription mediaDescription = SdpFactory.getInstance().createMediaDescription("video", rtpPort, 0, SdpConstants.RTP_AVP, MediaSdpHelper.RTPMAP.keySet().toArray(new String[0])); - mediaDescription.addAttribute((AttributeField)SdpFactory.getInstance().createAttribute("recvonly",null)); - MediaSdpHelper.RTPMAP.forEach((k, v)->{ - Optional.ofNullable(MediaSdpHelper.FMTP.get(k)).ifPresent((f)->{ - mediaDescription.addAttribute((AttributeField) SdpFactory.getInstance().createAttribute(SdpConstants.FMTP.toLowerCase(), StringUtils.joinWith(Separators.SP,k,f))); - }); - mediaDescription.addAttribute((AttributeField) SdpFactory.getInstance().createAttribute(SdpConstants.RTPMAP, StringUtils.joinWith(Separators.SP,k,v))); - }); - - if(streamMode == StreamMode.TCP_PASSIVE){ - // TCP-PASSIVE - mediaDescription.addAttribute((AttributeField)SdpFactory.getInstance().createAttribute("setup","passive")); - mediaDescription.addAttribute((AttributeField)SdpFactory.getInstance().createAttribute("connection","new")); - } else if(streamMode == StreamMode.TCP_ACTIVE){ - // TCP-ACTIVE - mediaDescription.addAttribute((AttributeField)SdpFactory.getInstance().createAttribute("setup","active")); - mediaDescription.addAttribute((AttributeField)SdpFactory.getInstance().createAttribute("connection","new")); - } - - description.setMediaDescriptions(new Vector<>() {{ - add(mediaDescription); - }}); - - description.setTimeDescriptions(new Vector<>(){{ - add(timeDescription); - }}); - - Origin origin = SdpFactory.getInstance().createOrigin(channelId, 0, 0, ConnectionField.IN, netType, rtpIp); - description.setOrigin(origin); - - description.setSsrcField(new SsrcField(ssrc)); - return description; - } - - @SneakyThrows - public static GB28181Description play(String deviceId, String channelId, String netType, String rtpIp, int rtpPort, String ssrc, StreamMode streamMode){ - TimeDescription timeDescription = SdpFactory.getInstance().createTimeDescription(); - return build(Action.PLAY, deviceId, channelId, netType, rtpIp, rtpPort, ssrc, streamMode, timeDescription); - } - - @SneakyThrows - public static GB28181Description playback(String deviceId, String channelId, String netType, String rtpIp, int rtpPort, String ssrc, StreamMode streamMode, Date start, Date end) { - TimeField timeField = new TimeField(); - timeField.setStartTime(start.toInstant().getEpochSecond()); - timeField.setStopTime(end.toInstant().getEpochSecond()); - TimeDescription timeDescription = SdpFactory.getInstance().createTimeDescription(timeField); - - GB28181Description description = build(Action.PLAY_BACK, deviceId, channelId, netType, rtpIp, rtpPort, ssrc, streamMode, timeDescription); - - URIField uriField = new URIField(); - uriField.setURI(StringUtils.joinWith(":", channelId, "0")); - description.setURI(uriField); - return description; - } -} diff --git a/gb28181-service/src/main/java/cn/skcks/docking/gb28181/core/sip/gb28181/sdp/SsrcField.java b/gb28181-service/src/main/java/cn/skcks/docking/gb28181/core/sip/gb28181/sdp/SsrcField.java deleted file mode 100644 index cdecc3d..0000000 --- a/gb28181-service/src/main/java/cn/skcks/docking/gb28181/core/sip/gb28181/sdp/SsrcField.java +++ /dev/null @@ -1,28 +0,0 @@ -package cn.skcks.docking.gb28181.core.sip.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(); - } -} diff --git a/gb28181-service/src/main/java/cn/skcks/docking/gb28181/core/sip/gb28181/sdp/StreamMode.java b/gb28181-service/src/main/java/cn/skcks/docking/gb28181/core/sip/gb28181/sdp/StreamMode.java deleted file mode 100644 index 41096fd..0000000 --- a/gb28181-service/src/main/java/cn/skcks/docking/gb28181/core/sip/gb28181/sdp/StreamMode.java +++ /dev/null @@ -1,27 +0,0 @@ -package cn.skcks.docking.gb28181.core.sip.gb28181.sdp; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonValue; -import lombok.AllArgsConstructor; -import lombok.Getter; - -@AllArgsConstructor -@Getter -public enum StreamMode { - UDP("UDP"), - TCP_ACTIVE("TCP-ACTIVE"), - TCP_PASSIVE("TCP-PASSIVE"); - - @JsonValue - private final String mode; - - @JsonCreator - public static StreamMode of(String mode) { - for (StreamMode m : values()) { - if (m.getMode().equalsIgnoreCase(mode)) { - return m; - } - } - return null; - } -} diff --git a/gb28181-service/src/main/java/cn/skcks/docking/gb28181/core/sip/message/processor/message/response/InviteResponseProcessor.java b/gb28181-service/src/main/java/cn/skcks/docking/gb28181/core/sip/message/processor/message/response/InviteResponseProcessor.java index 030ee44..8ec5efb 100644 --- a/gb28181-service/src/main/java/cn/skcks/docking/gb28181/core/sip/message/processor/message/response/InviteResponseProcessor.java +++ b/gb28181-service/src/main/java/cn/skcks/docking/gb28181/core/sip/message/processor/message/response/InviteResponseProcessor.java @@ -1,13 +1,14 @@ package cn.skcks.docking.gb28181.core.sip.message.processor.message.response; -import cn.skcks.docking.gb28181.core.sip.gb28181.sdp.Gb28181Sdp; + import cn.skcks.docking.gb28181.core.sip.listener.SipListener; import cn.skcks.docking.gb28181.core.sip.message.processor.MessageProcessor; import cn.skcks.docking.gb28181.core.sip.message.request.SipRequestBuilder; import cn.skcks.docking.gb28181.core.sip.message.sender.SipMessageSender; import cn.skcks.docking.gb28181.core.sip.message.subscribe.GenericSubscribe; import cn.skcks.docking.gb28181.core.sip.message.subscribe.SipSubscribe; -import cn.skcks.docking.gb28181.core.sip.utils.SipUtil; +import cn.skcks.docking.gb28181.sdp.GB28181Description; +import cn.skcks.docking.gb28181.sdp.parser.GB28181DescriptionParser; import gov.nist.javax.sip.ResponseEventExt; import gov.nist.javax.sip.message.SIPResponse; import jakarta.annotation.PostConstruct; @@ -16,7 +17,6 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; import javax.sdp.SdpParseException; -import javax.sdp.SessionDescription; import javax.sip.InvalidArgumentException; import javax.sip.ResponseEvent; import javax.sip.SipException; @@ -65,8 +65,8 @@ public class InviteResponseProcessor implements MessageProcessor { ResponseEventExt event = (ResponseEventExt) requestEvent; String contentString = new String(response.getRawContent()); - Gb28181Sdp gb28181Sdp = SipUtil.parseSDP(contentString); - SessionDescription sdp = gb28181Sdp.getBaseSdb(); + GB28181DescriptionParser gb28181DescriptionParser = new GB28181DescriptionParser(contentString); + GB28181Description sdp = gb28181DescriptionParser.parse(); SipURI requestUri = SipFactory.getInstance().createAddressFactory().createSipURI(sdp.getOrigin().getUsername(), event.getRemoteIpAddress() + ":" + event.getRemotePort()); Request reqAck = SipRequestBuilder.createAckRequest(response.getLocalAddress().getHostAddress(), requestUri, response); diff --git a/gb28181-service/src/main/java/cn/skcks/docking/gb28181/core/sip/utils/SipUtil.java b/gb28181-service/src/main/java/cn/skcks/docking/gb28181/core/sip/utils/SipUtil.java index 9be6580..7a9d1d0 100644 --- a/gb28181-service/src/main/java/cn/skcks/docking/gb28181/core/sip/utils/SipUtil.java +++ b/gb28181-service/src/main/java/cn/skcks/docking/gb28181/core/sip/utils/SipUtil.java @@ -5,7 +5,6 @@ import cn.hutool.core.date.LocalDateTimeUtil; import cn.hutool.core.util.IdUtil; import cn.skcks.docking.gb28181.common.config.ProjectConfig; import cn.skcks.docking.gb28181.core.sip.dto.RemoteInfo; -import cn.skcks.docking.gb28181.core.sip.gb28181.sdp.Gb28181Sdp; import gov.nist.javax.sip.address.AddressImpl; import gov.nist.javax.sip.address.SipUri; import gov.nist.javax.sip.header.Subject; @@ -19,9 +18,6 @@ import org.springframework.context.ApplicationContextAware; import org.springframework.stereotype.Component; 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; @@ -166,37 +162,6 @@ public class SipUtil implements ApplicationContextAware { return builder.toString(); } - 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 { - String[] lines = sdpStr.split("\\r?\\n"); - StringBuilder sdpBuffer = new StringBuilder(); - for (String line : lines) { - if (line.trim().startsWith("y=")) { - ssrc = line.substring(2); - }else if (line.trim().startsWith("f=")) { - mediaDescription = line.substring(2); - }else { - sdpBuffer.append(line.trim()).append("\r\n"); - } - } - sdp = SdpFactory.getInstance().createSessionDescription(sdpBuffer.toString()); - } - return Gb28181Sdp.builder() - .baseSdb(sdp) - .ssrc(ssrc) - .mediaDescription(mediaDescription) - .build(); - } - public static String getSsrcFromSdp(String sdpStr) { // jainSip不支持y= f=字段, 移除以解析。 diff --git a/gb28181-service/src/test/java/cn/skcks/docking/gb28181/core/sip/message/event/SipEventTest.java b/gb28181-service/src/test/java/cn/skcks/docking/gb28181/core/sip/message/event/SipEventTest.java index c7903e8..693aa34 100644 --- a/gb28181-service/src/test/java/cn/skcks/docking/gb28181/core/sip/message/event/SipEventTest.java +++ b/gb28181-service/src/test/java/cn/skcks/docking/gb28181/core/sip/message/event/SipEventTest.java @@ -1,23 +1,24 @@ package cn.skcks.docking.gb28181.core.sip.message.event; import cn.hutool.core.util.RandomUtil; -import cn.skcks.docking.gb28181.core.sip.gb28181.sdp.GB28181Description; -import cn.skcks.docking.gb28181.core.sip.gb28181.sdp.MediaSdpHelper; -import cn.skcks.docking.gb28181.core.sip.gb28181.sdp.SsrcField; -import cn.skcks.docking.gb28181.core.sip.gb28181.sdp.StreamMode; -import gov.nist.core.NameValue; +import cn.skcks.docking.gb28181.sdp.GB28181Description; +import cn.skcks.docking.gb28181.sdp.GB28181SDPBuilder; +import cn.skcks.docking.gb28181.sdp.field.ssrc.SsrcField; +import cn.skcks.docking.gb28181.sdp.media.MediaStreamMode; import gov.nist.core.Separators; -import gov.nist.javax.sdp.MediaDescriptionImpl; -import gov.nist.javax.sdp.SessionDescriptionImpl; -import gov.nist.javax.sdp.fields.*; +import gov.nist.javax.sdp.fields.AttributeField; +import gov.nist.javax.sdp.fields.ConnectionField; +import gov.nist.javax.sdp.fields.URIField; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.junit.jupiter.api.Test; import javax.sdp.*; -import java.net.URL; -import java.util.*; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.Vector; import java.util.concurrent.*; import java.util.concurrent.atomic.AtomicInteger; @@ -124,7 +125,8 @@ public class SipEventTest { @Test @SneakyThrows public void sdpTest() { - GB28181Description description = GB28181Description.Convertor.convert((SessionDescriptionImpl) SdpFactory.getInstance().createSessionDescription("Play")); + + GB28181Description description = new GB28181Description(SdpFactory.getInstance().createSessionDescription("Play")); Version version = SdpFactory.getInstance().createVersion(0); description.setVersion(version); @@ -132,10 +134,10 @@ public class SipEventTest { Connection connectionField = SdpFactory.getInstance().createConnection(ConnectionField.IN, Connection.IP4, "10.10.10.20"); description.setConnection(connectionField); - MediaDescription mediaDescription = SdpFactory.getInstance().createMediaDescription("video", 6666, 0, SdpConstants.RTP_AVP, MediaSdpHelper.RTPMAP.keySet().toArray(new String[0])); + MediaDescription mediaDescription = SdpFactory.getInstance().createMediaDescription("video", 6666, 0, SdpConstants.RTP_AVP, GB28181SDPBuilder.RTPMAP.keySet().toArray(new String[0])); mediaDescription.addAttribute((AttributeField)SdpFactory.getInstance().createAttribute("recvonly",null)); - MediaSdpHelper.RTPMAP.forEach((k, v)->{ - Optional.ofNullable(MediaSdpHelper.FMTP.get(k)).ifPresent((f)->{ + GB28181SDPBuilder.RTPMAP.forEach((k, v)->{ + Optional.ofNullable(GB28181SDPBuilder.FMTP.get(k)).ifPresent((f)->{ mediaDescription.addAttribute((AttributeField) SdpFactory.getInstance().createAttribute(SdpConstants.FMTP.toLowerCase(), StringUtils.joinWith(Separators.SP,k,f))); }); mediaDescription.addAttribute((AttributeField) SdpFactory.getInstance().createAttribute(SdpConstants.RTPMAP, StringUtils.joinWith(Separators.SP,k,v))); @@ -181,7 +183,7 @@ public class SipEventTest { int rtpPort = 5080; String rtpIp = "10.10.10.20"; long ssrc = RandomUtil.randomLong(10000000,100000000); - GB28181Description description = MediaSdpHelper.build(MediaSdpHelper.Action.PLAY, deviceId, channel, Connection.IP4, rtpIp, rtpPort, String.valueOf(ssrc), StreamMode.UDP, SdpFactory.getInstance().createTimeDescription()); - log.info("\n{}", description); + GB28181Description gb28181Description = GB28181SDPBuilder.Sender.build(GB28181SDPBuilder.Action.PLAY, deviceId, channel, Connection.IP4, rtpIp, rtpPort, String.valueOf(ssrc), MediaStreamMode.UDP, SdpFactory.getInstance().createTimeDescription()); + log.info("\n{}", gb28181Description); } } diff --git a/gb28181-sip/src/main/java/cn/skcks/docking/gb28181/sdp/field/ssrc/parser/FormatFieldParser.java b/gb28181-sip/src/main/java/cn/skcks/docking/gb28181/sdp/field/ssrc/parser/FormatFieldParser.java index bee4b30..a343092 100644 --- a/gb28181-sip/src/main/java/cn/skcks/docking/gb28181/sdp/field/ssrc/parser/FormatFieldParser.java +++ b/gb28181-sip/src/main/java/cn/skcks/docking/gb28181/sdp/field/ssrc/parser/FormatFieldParser.java @@ -34,7 +34,7 @@ public class FormatFieldParser extends SDPParser { log.info("{}", (Object) split); String video = split[0]; String[] videoParams = StringUtils.split(video,"/"); - log.info("{}", (Object) videoParams); + log.info("videoParams {}", (Object) videoParams); if(videoParams.length > 1){ formatField.setVideoFormat(videoParams[1]); } @@ -55,6 +55,7 @@ public class FormatFieldParser extends SDPParser { } String audio = split[1]; String[] audioParams = audio.split("/"); + log.info("audioParams {}", (Object) audioParams); if(audioParams.length > 0){ formatField.setAudioFormat(audioParams[0]); } diff --git a/gb28181-sip/src/main/java/cn/skcks/docking/gb28181/sip/method/notify/request/NotifyRequestBuilder.java b/gb28181-sip/src/main/java/cn/skcks/docking/gb28181/sip/method/notify/request/NotifyRequestBuilder.java index 4f29d34..ee8c0b4 100644 --- a/gb28181-sip/src/main/java/cn/skcks/docking/gb28181/sip/method/notify/request/NotifyRequestBuilder.java +++ b/gb28181-sip/src/main/java/cn/skcks/docking/gb28181/sip/method/notify/request/NotifyRequestBuilder.java @@ -27,7 +27,7 @@ public class NotifyRequestBuilder extends RequestBuilder implements NotifyBuilde int expires = sipRequest.getExpires().getExpires(); return createNotifyRequest(callId, cSeq, event, content, toTag, expires); } - @SneakyThrows + @SneakyThrows public Request createNotifyRequest(String callId, long cSeq, String event, byte[] content, String toTag, int expire) { SIPRequest notifyRequest = (SIPRequest) createNotifyRequest(callId, cSeq, event, content, toTag); SubscriptionState subscriptionState = (SubscriptionState) notifyRequest.getHeader(SubscriptionState.NAME);