|  |  |  | 
|---|
|  |  |  | 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.DateUtil; | 
|---|
|  |  |  | import com.genersoft.iot.vmp.utils.GitUtil; | 
|---|
|  |  |  | import gov.nist.javax.sip.address.AddressImpl; | 
|---|
|  |  |  | import gov.nist.javax.sip.address.SipUri; | 
|---|
|  |  |  | import gov.nist.javax.sip.header.Subject; | 
|---|
|  |  |  | import gov.nist.javax.sip.message.SIPRequest; | 
|---|
|  |  |  | import org.apache.commons.lang3.RandomStringUtils; | 
|---|
|  |  |  | import org.slf4j.Logger; | 
|---|
|  |  |  | import org.slf4j.LoggerFactory; | 
|---|
|  |  |  | 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; | 
|---|
|  |  |  | import javax.sip.header.Header; | 
|---|
|  |  |  | import javax.sip.header.UserAgentHeader; | 
|---|
|  |  |  | import javax.sip.message.Request; | 
|---|
|  |  |  | import java.text.ParseException; | 
|---|
|  |  |  | import java.time.LocalDateTime; | 
|---|
|  |  |  | import java.time.format.DateTimeParseException; | 
|---|
|  |  |  | import java.util.ArrayList; | 
|---|
|  |  |  | import java.util.List; | 
|---|
|  |  |  | import java.util.UUID; | 
|---|
|  |  |  |  | 
|---|
|  |  |  | /** | 
|---|
|  |  |  | * @author panlinlin | 
|---|
|  |  |  | 
|---|
|  |  |  | */ | 
|---|
|  |  |  | public class SipUtils { | 
|---|
|  |  |  |  | 
|---|
|  |  |  | private final static Logger logger = LoggerFactory.getLogger(SipUtils.class); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | public static String getUserIdFromFromHeader(Request request) { | 
|---|
|  |  |  | FromHeader fromHeader = (FromHeader)request.getHeader(FromHeader.NAME); | 
|---|
|  |  |  | return getUserIdFromFromHeader(fromHeader); | 
|---|
|  |  |  | 
|---|
|  |  |  | /** | 
|---|
|  |  |  | * 从subject读取channelId | 
|---|
|  |  |  | * */ | 
|---|
|  |  |  | public static String getChannelIdFromHeader(Request request) { | 
|---|
|  |  |  | public static String getChannelIdFromRequest(Request request) { | 
|---|
|  |  |  | Header subject = request.getHeader("subject"); | 
|---|
|  |  |  | if (subject == null) { | 
|---|
|  |  |  | // 如果缺失subject | 
|---|
|  |  |  | return null; | 
|---|
|  |  |  | } | 
|---|
|  |  |  | return ((Subject) subject).getSubject().split(":")[0]; | 
|---|
|  |  |  | 
|---|
|  |  |  | return uri.getUser(); | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | } | 
|---|
|  |  |  | public static  String getNewViaTag() { | 
|---|
|  |  |  | return "z9hG4bK" + RandomStringUtils.randomNumeric(10); | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | public static UserAgentHeader createUserAgentHeader(GitUtil gitUtil) throws PeerUnavailableException, ParseException { | 
|---|
|  |  |  | List<String> agentParam = new ArrayList<>(); | 
|---|
|  |  |  | agentParam.add("WVP-Pro "); | 
|---|
|  |  |  | if (gitUtil != null ) { | 
|---|
|  |  |  | if (!ObjectUtils.isEmpty(gitUtil.getBuildVersion())) { | 
|---|
|  |  |  | agentParam.add("v"); | 
|---|
|  |  |  | agentParam.add(gitUtil.getBuildVersion() + "."); | 
|---|
|  |  |  | } | 
|---|
|  |  |  | if (!ObjectUtils.isEmpty(gitUtil.getCommitTime())) { | 
|---|
|  |  |  | agentParam.add(gitUtil.getCommitTime()); | 
|---|
|  |  |  | } | 
|---|
|  |  |  | } | 
|---|
|  |  |  | return SipFactory.getInstance().createHeaderFactory().createUserAgentHeader(agentParam); | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | public static String getNewFromTag(){ | 
|---|
|  |  |  | return UUID.randomUUID().toString().replace("-", ""); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | //        return getNewTag(); | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | public static String getNewTag(){ | 
|---|
|  |  |  | return String.valueOf(System.currentTimeMillis()); | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  |  | 
|---|
|  |  |  | /** | 
|---|
|  |  |  | * 云台指令码计算 | 
|---|
|  |  |  | * | 
|---|
|  |  |  | * @param leftRight  镜头左移右移 0:停止 1:左移 2:右移 | 
|---|
|  |  |  | * @param upDown     镜头上移下移 0:停止 1:上移 2:下移 | 
|---|
|  |  |  | * @param inOut      镜头放大缩小 0:停止 1:缩小 2:放大 | 
|---|
|  |  |  | * @param moveSpeed  镜头移动速度 默认 0XFF (0-255) | 
|---|
|  |  |  | * @param zoomSpeed  镜头缩放速度 默认 0X1 (0-255) | 
|---|
|  |  |  | */ | 
|---|
|  |  |  | public static String cmdString(int leftRight, int upDown, int inOut, int moveSpeed, int zoomSpeed) { | 
|---|
|  |  |  | int cmdCode = 0; | 
|---|
|  |  |  | if (leftRight == 2) { | 
|---|
|  |  |  | cmdCode|=0x01;      // 右移 | 
|---|
|  |  |  | } else if(leftRight == 1) { | 
|---|
|  |  |  | cmdCode|=0x02;      // 左移 | 
|---|
|  |  |  | } | 
|---|
|  |  |  | if (upDown == 2) { | 
|---|
|  |  |  | cmdCode|=0x04;      // 下移 | 
|---|
|  |  |  | } else if(upDown == 1) { | 
|---|
|  |  |  | cmdCode|=0x08;      // 上移 | 
|---|
|  |  |  | } | 
|---|
|  |  |  | if (inOut == 2) { | 
|---|
|  |  |  | cmdCode |= 0x10;   // 放大 | 
|---|
|  |  |  | } else if(inOut == 1) { | 
|---|
|  |  |  | cmdCode |= 0x20;   // 缩小 | 
|---|
|  |  |  | } | 
|---|
|  |  |  | StringBuilder builder = new StringBuilder("A50F01"); | 
|---|
|  |  |  | String strTmp; | 
|---|
|  |  |  | strTmp = String.format("%02X", cmdCode); | 
|---|
|  |  |  | builder.append(strTmp, 0, 2); | 
|---|
|  |  |  | strTmp = String.format("%02X", moveSpeed); | 
|---|
|  |  |  | builder.append(strTmp, 0, 2); | 
|---|
|  |  |  | builder.append(strTmp, 0, 2); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | //优化zoom低倍速下的变倍速率 | 
|---|
|  |  |  | if ((zoomSpeed > 0) && (zoomSpeed <16)) | 
|---|
|  |  |  | { | 
|---|
|  |  |  | zoomSpeed = 16; | 
|---|
|  |  |  | } | 
|---|
|  |  |  | strTmp = String.format("%X", zoomSpeed); | 
|---|
|  |  |  | builder.append(strTmp, 0, 1).append("0"); | 
|---|
|  |  |  | //计算校验码 | 
|---|
|  |  |  | int checkCode = (0XA5 + 0X0F + 0X01 + cmdCode + moveSpeed + moveSpeed + (zoomSpeed /*<< 4*/ & 0XF0)) % 0X100; | 
|---|
|  |  |  | strTmp = String.format("%02X", checkCode); | 
|---|
|  |  |  | builder.append(strTmp, 0, 2); | 
|---|
|  |  |  | return builder.toString(); | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | /** | 
|---|
|  |  |  | * 从请求中获取设备ip地址和端口号 | 
|---|
|  |  |  | * @param request 请求 | 
|---|
|  |  |  | * @param sipUseSourceIpAsRemoteAddress  false 从via中获取地址, true 直接获取远程地址 | 
|---|
|  |  |  | * @return 地址信息 | 
|---|
|  |  |  | */ | 
|---|
|  |  |  | public static RemoteAddressInfo getRemoteAddressFromRequest(SIPRequest request, boolean sipUseSourceIpAsRemoteAddress) { | 
|---|
|  |  |  |  | 
|---|
|  |  |  | String remoteAddress; | 
|---|
|  |  |  | int remotePort; | 
|---|
|  |  |  | if (sipUseSourceIpAsRemoteAddress) { | 
|---|
|  |  |  | remoteAddress = request.getPeerPacketSourceAddress().getHostAddress(); | 
|---|
|  |  |  | remotePort = request.getPeerPacketSourcePort(); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | }else { | 
|---|
|  |  |  | // 判断RPort是否改变,改变则说明路由nat信息变化,修改设备信息 | 
|---|
|  |  |  | // 获取到通信地址等信息 | 
|---|
|  |  |  | remoteAddress = request.getTopmostViaHeader().getReceived(); | 
|---|
|  |  |  | remotePort = request.getTopmostViaHeader().getRPort(); | 
|---|
|  |  |  | // 解析本地地址替代 | 
|---|
|  |  |  | if (ObjectUtils.isEmpty(remoteAddress) || remotePort == -1) { | 
|---|
|  |  |  | remoteAddress = request.getPeerPacketSourceAddress().getHostAddress(); | 
|---|
|  |  |  | remotePort = request.getPeerPacketSourcePort(); | 
|---|
|  |  |  | } | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | return new RemoteAddressInfo(remoteAddress, remotePort); | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | public static DeviceChannel updateGps(DeviceChannel deviceChannel, String geoCoordSys) { | 
|---|
|  |  |  | if (deviceChannel.getLongitude()*deviceChannel.getLatitude() > 0) { | 
|---|
|  |  |  |  | 
|---|
|  |  |  | if (geoCoordSys == null) { | 
|---|
|  |  |  | geoCoordSys = "WGS84"; | 
|---|
|  |  |  | } | 
|---|
|  |  |  | if ("WGS84".equals(geoCoordSys)) { | 
|---|
|  |  |  | deviceChannel.setLongitudeWgs84(deviceChannel.getLongitude()); | 
|---|
|  |  |  | deviceChannel.setLatitudeWgs84(deviceChannel.getLatitude()); | 
|---|
|  |  |  | Double[] position = Coordtransform.WGS84ToGCJ02(deviceChannel.getLongitude(), deviceChannel.getLatitude()); | 
|---|
|  |  |  | deviceChannel.setLongitudeGcj02(position[0]); | 
|---|
|  |  |  | deviceChannel.setLatitudeGcj02(position[1]); | 
|---|
|  |  |  | }else if ("GCJ02".equals(geoCoordSys)) { | 
|---|
|  |  |  | deviceChannel.setLongitudeGcj02(deviceChannel.getLongitude()); | 
|---|
|  |  |  | deviceChannel.setLatitudeGcj02(deviceChannel.getLatitude()); | 
|---|
|  |  |  | Double[] position = Coordtransform.GCJ02ToWGS84(deviceChannel.getLongitude(), deviceChannel.getLatitude()); | 
|---|
|  |  |  | deviceChannel.setLongitudeWgs84(position[0]); | 
|---|
|  |  |  | deviceChannel.setLatitudeWgs84(position[1]); | 
|---|
|  |  |  | }else { | 
|---|
|  |  |  | deviceChannel.setLongitudeGcj02(0.00); | 
|---|
|  |  |  | deviceChannel.setLatitudeGcj02(0.00); | 
|---|
|  |  |  | deviceChannel.setLongitudeWgs84(0.00); | 
|---|
|  |  |  | deviceChannel.setLatitudeWgs84(0.00); | 
|---|
|  |  |  | } | 
|---|
|  |  |  | }else { | 
|---|
|  |  |  | deviceChannel.setLongitudeGcj02(deviceChannel.getLongitude()); | 
|---|
|  |  |  | deviceChannel.setLatitudeGcj02(deviceChannel.getLatitude()); | 
|---|
|  |  |  | deviceChannel.setLongitudeWgs84(deviceChannel.getLongitude()); | 
|---|
|  |  |  | deviceChannel.setLatitudeWgs84(deviceChannel.getLatitude()); | 
|---|
|  |  |  | } | 
|---|
|  |  |  | 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 { | 
|---|
|  |  |  | 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.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; | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | public static String parseTime(String timeStr) { | 
|---|
|  |  |  | if (ObjectUtils.isEmpty(timeStr)){ | 
|---|
|  |  |  | return null; | 
|---|
|  |  |  | } | 
|---|
|  |  |  | LocalDateTime localDateTime; | 
|---|
|  |  |  | try { | 
|---|
|  |  |  | localDateTime = LocalDateTime.parse(timeStr); | 
|---|
|  |  |  | }catch (DateTimeParseException e) { | 
|---|
|  |  |  | try { | 
|---|
|  |  |  | localDateTime = LocalDateTime.parse(timeStr, DateUtil.formatterISO8601); | 
|---|
|  |  |  | }catch (DateTimeParseException e2) { | 
|---|
|  |  |  | logger.error("[格式化时间] 无法格式化时间: {}", timeStr); | 
|---|
|  |  |  | return null; | 
|---|
|  |  |  | } | 
|---|
|  |  |  | } | 
|---|
|  |  |  | return localDateTime.format(DateUtil.formatterISO8601); | 
|---|
|  |  |  | } | 
|---|
|  |  |  | } | 
|---|