Merge remote-tracking branch 'origin/wvp-28181-2.0' into wvp-28181-2.0
# Conflicts: # src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java # src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java # src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/play/PlayController.java
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.genersoft.iot.vmp.gb28181.session;
|
||||
|
||||
import com.genersoft.iot.vmp.conf.SipConfig;
|
||||
import com.genersoft.iot.vmp.conf.UserSetting;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
import org.springframework.stereotype.Component;
|
||||
@@ -31,10 +32,13 @@ public class SSRCFactory {
|
||||
@Autowired
|
||||
private SipConfig sipConfig;
|
||||
|
||||
@Autowired
|
||||
private UserSetting userSetting;
|
||||
|
||||
|
||||
public void initMediaServerSSRC(String mediaServerId, Set<String> usedSet) {
|
||||
String ssrcPrefix = sipConfig.getDomain().substring(3, 8);
|
||||
String redisKey = SSRC_INFO_KEY + mediaServerId;
|
||||
String redisKey = SSRC_INFO_KEY + userSetting.getServerId() + "_" + mediaServerId;
|
||||
List<String> ssrcList = new ArrayList<>();
|
||||
for (int i = 1; i < MAX_STREAM_COUNT; i++) {
|
||||
String ssrc = String.format("%s%04d", ssrcPrefix, i);
|
||||
@@ -77,7 +81,7 @@ public class SSRCFactory {
|
||||
return;
|
||||
}
|
||||
String sn = ssrc.substring(1);
|
||||
String redisKey = SSRC_INFO_KEY + mediaServerId;
|
||||
String redisKey = SSRC_INFO_KEY + userSetting.getServerId() + "_" + mediaServerId;
|
||||
redisTemplate.opsForSet().add(redisKey, sn);
|
||||
}
|
||||
|
||||
@@ -86,7 +90,7 @@ public class SSRCFactory {
|
||||
*/
|
||||
private String getSN(String mediaServerId) {
|
||||
String sn = null;
|
||||
String redisKey = SSRC_INFO_KEY + mediaServerId;
|
||||
String redisKey = SSRC_INFO_KEY + userSetting.getServerId() + "_" + mediaServerId;
|
||||
Long size = redisTemplate.opsForSet().size(redisKey);
|
||||
if (size == null || size == 0) {
|
||||
throw new RuntimeException("ssrc已经用完");
|
||||
@@ -113,20 +117,8 @@ public class SSRCFactory {
|
||||
* @param mediaServerId 流媒体服务ID
|
||||
*/
|
||||
public boolean hasMediaServerSSRC(String mediaServerId) {
|
||||
String redisKey = SSRC_INFO_KEY + mediaServerId;
|
||||
String redisKey = SSRC_INFO_KEY + userSetting.getServerId() + "_" + mediaServerId;
|
||||
return redisTemplate.opsForSet().members(redisKey) != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询ssrc是否可用
|
||||
*
|
||||
* @param mediaServerId
|
||||
* @param ssrc
|
||||
* @return
|
||||
*/
|
||||
public boolean checkSsrc(String mediaServerId, String ssrc) {
|
||||
String sn = ssrc.substring(1);
|
||||
String redisKey = SSRC_INFO_KEY + mediaServerId;
|
||||
return redisTemplate.opsForSet().isMember(redisKey, sn) != null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,11 +39,13 @@ public class DeferredResultHolder {
|
||||
|
||||
public static final String CALLBACK_CMD_DOWNLOAD = "CALLBACK_DOWNLOAD";
|
||||
|
||||
public static final String CALLBACK_CMD_PROXY = "CALLBACK_PROXY";
|
||||
|
||||
public static final String CALLBACK_CMD_STOP = "CALLBACK_STOP";
|
||||
|
||||
public static final String UPLOAD_FILE_CHANNEL = "UPLOAD_FILE_CHANNEL";
|
||||
|
||||
public static final String CALLBACK_CMD_MOBILEPOSITION = "CALLBACK_MOBILEPOSITION";
|
||||
public static final String CALLBACK_CMD_MOBILE_POSITION = "CALLBACK_CMD_MOBILE_POSITION";
|
||||
|
||||
public static final String CALLBACK_CMD_PRESETQUERY = "CALLBACK_PRESETQUERY";
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -472,7 +472,7 @@ public class SIPCommander implements ISIPCommander {
|
||||
}
|
||||
subscribe.removeSubscribe(hookSubscribe);
|
||||
});
|
||||
Request request = headerProvider.createPlaybackInviteRequest(device, channelId, content.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()), ssrcInfo.getSsrc());
|
||||
Request request = headerProvider.createPlaybackInviteRequest(device, channelId, content.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()), ssrcInfo.getSsrc());
|
||||
|
||||
sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent, event -> {
|
||||
ResponseEvent responseEvent = (ResponseEvent) event.event;
|
||||
@@ -588,17 +588,13 @@ public class SIPCommander implements ISIPCommander {
|
||||
});
|
||||
});
|
||||
|
||||
Request request = headerProvider.createPlaybackInviteRequest(device, channelId, content.toString(), null, SipUtils.getNewFromTag(), null,newCallIdHeader, ssrcInfo.getSsrc());
|
||||
Request request = headerProvider.createPlaybackInviteRequest(device, channelId, content.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,newCallIdHeader, ssrcInfo.getSsrc());
|
||||
|
||||
sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent, event -> {
|
||||
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);
|
||||
});
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -175,6 +175,11 @@ public class NotifyRequestForCatalogProcessor extends SIPRequestProcessorParent
|
||||
}
|
||||
}else {
|
||||
addChannelMap.put(channel.getChannelId(), channel);
|
||||
if (userSetting.getDeviceStatusNotify()) {
|
||||
// 发送redis消息
|
||||
redisCatchStorage.sendChannelAddOrDelete(device.getDeviceId(), channel.getChannelId(), true);
|
||||
}
|
||||
|
||||
if (addChannelMap.keySet().size() > 300) {
|
||||
executeSaveForAdd();
|
||||
}
|
||||
@@ -185,6 +190,10 @@ public class NotifyRequestForCatalogProcessor extends SIPRequestProcessorParent
|
||||
// 删除
|
||||
logger.info("[收到删除通道通知] 来自设备: {}, 通道 {}", device.getDeviceId(), channel.getChannelId());
|
||||
deleteChannelList.add(channel);
|
||||
if (userSetting.getDeviceStatusNotify()) {
|
||||
// 发送redis消息
|
||||
redisCatchStorage.sendChannelAddOrDelete(device.getDeviceId(), channel.getChannelId(), false);
|
||||
}
|
||||
if (deleteChannelList.size() > 300) {
|
||||
executeSaveForDelete();
|
||||
}
|
||||
@@ -205,6 +214,10 @@ public class NotifyRequestForCatalogProcessor extends SIPRequestProcessorParent
|
||||
if (addChannelMap.keySet().size() > 300) {
|
||||
executeSaveForAdd();
|
||||
}
|
||||
if (userSetting.getDeviceStatusNotify()) {
|
||||
// 发送redis消息
|
||||
redisCatchStorage.sendChannelAddOrDelete(device.getDeviceId(), channel.getChannelId(), true);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
||||
@@ -192,7 +192,12 @@ public class NotifyRequestProcessor extends SIPRequestProcessorParent implements
|
||||
mobilePosition.setDeviceId(device.getDeviceId());
|
||||
mobilePosition.setChannelId(channelId);
|
||||
String time = XmlUtil.getText(rootElement, "Time");
|
||||
mobilePosition.setTime(time);
|
||||
if (ObjectUtils.isEmpty(time)){
|
||||
mobilePosition.setTime(DateUtil.getNow());
|
||||
}else {
|
||||
mobilePosition.setTime(SipUtils.parseTime(time));
|
||||
}
|
||||
|
||||
mobilePosition.setLongitude(Double.parseDouble(XmlUtil.getText(rootElement, "Longitude")));
|
||||
mobilePosition.setLatitude(Double.parseDouble(XmlUtil.getText(rootElement, "Latitude")));
|
||||
if (NumericUtil.isDouble(XmlUtil.getText(rootElement, "Speed"))) {
|
||||
@@ -237,7 +242,7 @@ public class NotifyRequestProcessor extends SIPRequestProcessorParent implements
|
||||
|
||||
// 发送redis消息。 通知位置信息的变化
|
||||
JSONObject jsonObject = new JSONObject();
|
||||
jsonObject.put("time", time);
|
||||
jsonObject.put("time", DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(mobilePosition.getTime()));
|
||||
jsonObject.put("serial", deviceId);
|
||||
jsonObject.put("code", channelId);
|
||||
jsonObject.put("longitude", mobilePosition.getLongitude());
|
||||
@@ -339,7 +344,7 @@ public class NotifyRequestProcessor extends SIPRequestProcessorParent implements
|
||||
storager.updateChannelPosition(deviceChannel);
|
||||
// 发送redis消息。 通知位置信息的变化
|
||||
JSONObject jsonObject = new JSONObject();
|
||||
jsonObject.put("time", mobilePosition.getTime());
|
||||
jsonObject.put("time", DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(mobilePosition.getTime()));
|
||||
jsonObject.put("serial", deviceChannel.getDeviceId());
|
||||
jsonObject.put("code", deviceChannel.getChannelId());
|
||||
jsonObject.put("longitude", mobilePosition.getLongitude());
|
||||
|
||||
@@ -164,7 +164,7 @@ public class AlarmNotifyMessageHandler extends SIPRequestProcessorParent impleme
|
||||
|
||||
// 发送redis消息。 通知位置信息的变化
|
||||
JSONObject jsonObject = new JSONObject();
|
||||
jsonObject.put("time", mobilePosition.getTime());
|
||||
jsonObject.put("time", DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(mobilePosition.getTime()));
|
||||
jsonObject.put("serial", deviceChannel.getDeviceId());
|
||||
jsonObject.put("code", deviceChannel.getChannelId());
|
||||
jsonObject.put("longitude", mobilePosition.getLongitude());
|
||||
|
||||
@@ -7,6 +7,7 @@ import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorP
|
||||
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler;
|
||||
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.notify.NotifyMessageHandler;
|
||||
import com.genersoft.iot.vmp.gb28181.utils.NumericUtil;
|
||||
import com.genersoft.iot.vmp.gb28181.utils.SipUtils;
|
||||
import com.genersoft.iot.vmp.service.IDeviceChannelService;
|
||||
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
|
||||
import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
|
||||
@@ -95,7 +96,12 @@ public class MobilePositionNotifyMessageHandler extends SIPRequestProcessorParen
|
||||
}
|
||||
mobilePosition.setDeviceId(sipMsgInfo.getDevice().getDeviceId());
|
||||
mobilePosition.setChannelId(getText(rootElementAfterCharset, "DeviceID"));
|
||||
mobilePosition.setTime(getText(rootElementAfterCharset, "Time"));
|
||||
String time = getText(rootElementAfterCharset, "Time");
|
||||
if (ObjectUtils.isEmpty(time)){
|
||||
mobilePosition.setTime(DateUtil.getNow());
|
||||
}else {
|
||||
mobilePosition.setTime(SipUtils.parseTime(time));
|
||||
}
|
||||
mobilePosition.setLongitude(Double.parseDouble(getText(rootElementAfterCharset, "Longitude")));
|
||||
mobilePosition.setLatitude(Double.parseDouble(getText(rootElementAfterCharset, "Latitude")));
|
||||
if (NumericUtil.isDouble(getText(rootElementAfterCharset, "Speed"))) {
|
||||
@@ -138,7 +144,7 @@ public class MobilePositionNotifyMessageHandler extends SIPRequestProcessorParen
|
||||
|
||||
// 发送redis消息。 通知位置信息的变化
|
||||
JSONObject jsonObject = new JSONObject();
|
||||
jsonObject.put("time", mobilePosition.getTime());
|
||||
jsonObject.put("time", DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(mobilePosition.getTime()));
|
||||
jsonObject.put("serial", deviceChannel.getDeviceId());
|
||||
jsonObject.put("code", deviceChannel.getChannelId());
|
||||
jsonObject.put("longitude", mobilePosition.getLongitude());
|
||||
|
||||
@@ -2,17 +2,21 @@ package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.respon
|
||||
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.genersoft.iot.vmp.conf.UserSetting;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.*;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.Device;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.MobilePosition;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
|
||||
import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
|
||||
import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
|
||||
import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
|
||||
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler;
|
||||
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.ResponseMessageHandler;
|
||||
import com.genersoft.iot.vmp.gb28181.utils.Coordtransform;
|
||||
import com.genersoft.iot.vmp.gb28181.utils.NumericUtil;
|
||||
import com.genersoft.iot.vmp.gb28181.utils.SipUtils;
|
||||
import com.genersoft.iot.vmp.service.IDeviceChannelService;
|
||||
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
|
||||
import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
|
||||
import com.genersoft.iot.vmp.utils.DateUtil;
|
||||
import com.genersoft.iot.vmp.utils.GpsUtil;
|
||||
import gov.nist.javax.sip.message.SIPRequest;
|
||||
import org.dom4j.DocumentException;
|
||||
import org.dom4j.Element;
|
||||
@@ -56,6 +60,9 @@ public class MobilePositionResponseMessageHandler extends SIPRequestProcessorPar
|
||||
@Autowired
|
||||
private IDeviceChannelService deviceChannelService;
|
||||
|
||||
@Autowired
|
||||
private DeferredResultHolder resultHolder;
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
responseMessageHandler.addHandler(cmdType, this);
|
||||
@@ -83,7 +90,13 @@ public class MobilePositionResponseMessageHandler extends SIPRequestProcessorPar
|
||||
}
|
||||
mobilePosition.setDeviceId(device.getDeviceId());
|
||||
mobilePosition.setChannelId(getText(rootElement, "DeviceID"));
|
||||
mobilePosition.setTime(getText(rootElement, "Time"));
|
||||
//兼容ISO 8601格式时间
|
||||
String time = getText(rootElement, "Time");
|
||||
if (ObjectUtils.isEmpty(time)){
|
||||
mobilePosition.setTime(DateUtil.getNow());
|
||||
}else {
|
||||
mobilePosition.setTime(SipUtils.parseTime(time));
|
||||
}
|
||||
mobilePosition.setLongitude(Double.parseDouble(getText(rootElement, "Longitude")));
|
||||
mobilePosition.setLatitude(Double.parseDouble(getText(rootElement, "Latitude")));
|
||||
if (NumericUtil.isDouble(getText(rootElement, "Speed"))) {
|
||||
@@ -121,11 +134,18 @@ public class MobilePositionResponseMessageHandler extends SIPRequestProcessorPar
|
||||
if (userSetting.getSavePositionHistory()) {
|
||||
storager.insertMobilePosition(mobilePosition);
|
||||
}
|
||||
|
||||
storager.updateChannelPosition(deviceChannel);
|
||||
|
||||
String key = DeferredResultHolder.CALLBACK_CMD_MOBILE_POSITION + device.getDeviceId();
|
||||
RequestMessage msg = new RequestMessage();
|
||||
msg.setKey(key);
|
||||
msg.setData(mobilePosition);
|
||||
resultHolder.invokeAllResult(msg);
|
||||
|
||||
// 发送redis消息。 通知位置信息的变化
|
||||
JSONObject jsonObject = new JSONObject();
|
||||
jsonObject.put("time", mobilePosition.getTime());
|
||||
jsonObject.put("time", DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(mobilePosition.getTime()));
|
||||
jsonObject.put("serial", deviceChannel.getDeviceId());
|
||||
jsonObject.put("code", deviceChannel.getChannelId());
|
||||
jsonObject.put("longitude", mobilePosition.getLongitude());
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -1,14 +1,22 @@
|
||||
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;
|
||||
@@ -16,6 +24,8 @@ 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;
|
||||
@@ -28,6 +38,8 @@ import java.util.UUID;
|
||||
*/
|
||||
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);
|
||||
@@ -51,7 +63,7 @@ public class SipUtils {
|
||||
}
|
||||
|
||||
public static String getNewViaTag() {
|
||||
return "z9hG4bK" + System.currentTimeMillis();
|
||||
return "z9hG4bK" + RandomStringUtils.randomNumeric(10);
|
||||
}
|
||||
|
||||
public static UserAgentHeader createUserAgentHeader(GitUtil gitUtil) throws PeerUnavailableException, ParseException {
|
||||
@@ -189,4 +201,67 @@ 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 {
|
||||
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;
|
||||
}
|
||||
System.out.println(timeStr);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user