From b79a49fa76116fbc2be1de7465d933209b0c99ee Mon Sep 17 00:00:00 2001 From: 648540858 <648540858@qq.com> Date: Fri, 23 Sep 2022 22:45:23 +0800 Subject: [PATCH 1/2] =?UTF-8?q?dialog=E5=8E=BB=E9=99=A4=E4=BB=A5=E5=8F=8A?= =?UTF-8?q?=E5=BC=82=E5=B8=B8=E6=83=85=E5=86=B5=E5=A4=84=E7=90=86=E4=BC=98?= =?UTF-8?q?=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../genersoft/iot/vmp/conf/MediaConfig.java | 7 +- .../SsrcTransactionNotFoundException.java | 51 + .../genersoft/iot/vmp/gb28181/SipLayer.java | 4 +- .../vmp/gb28181/bean/CmdSendFailEvent.java | 27 + .../vmp/gb28181/bean/DeviceNotFoundEvent.java | 10 +- .../vmp/gb28181/bean/SipTransactionInfo.java | 11 +- .../iot/vmp/gb28181/bean/SsrcTransaction.java | 29 +- .../iot/vmp/gb28181/bean/SubscribeInfo.java | 5 - .../iot/vmp/gb28181/event/SipSubscribe.java | 13 +- .../event/device/RequestTimeoutEventImpl.java | 1 + .../subscribe/catalog/CatalogEventLister.java | 31 +- .../session/VideoStreamSessionManager.java | 58 +- .../task/impl/CatalogSubscribeTask.java | 72 +- .../impl/MobilePositionSubscribeTask.java | 71 +- .../gb28181/transmit/cmd/ISIPCommander.java | 99 +- .../cmd/ISIPCommanderForPlatform.java | 35 +- .../cmd/SIPRequestHeaderProvider.java | 110 +- .../transmit/cmd/impl/SIPCommander.java | 3149 ++++++++--------- .../cmd/impl/SIPCommanderFroPlatform.java | 616 ++-- .../request/SIPRequestProcessorParent.java | 17 +- .../request/impl/AckRequestProcessor.java | 13 +- .../request/impl/ByeRequestProcessor.java | 36 +- .../request/impl/InviteRequestProcessor.java | 6 +- .../impl/info/InfoRequestProcessor.java | 4 +- .../impl/message/MessageRequestProcessor.java | 6 +- .../cmd/DeviceControlQueryMessageHandler.java | 102 +- .../cmd/MediaStatusNotifyMessageHandler.java | 14 +- .../cmd/DeviceInfoQueryMessageHandler.java | 14 +- .../cmd/DeviceStatusQueryMessageHandler.java | 14 +- .../cmd/RecordInfoQueryMessageHandler.java | 66 +- .../cmd/CatalogResponseMessageHandler.java | 148 +- .../PresetQueryResponseMessageHandler.java | 45 +- .../impl/InviteResponseProcessor.java | 57 +- .../impl/RegisterResponseProcessor.java | 9 +- .../iot/vmp/gb28181/utils/SipUtils.java | 43 + .../vmp/media/zlm/ZLMHttpHookListener.java | 49 +- .../vmp/media/zlm/ZLMMediaListManager.java | 23 +- .../vmp/service/impl/DeviceServiceImpl.java | 43 +- .../vmp/service/impl/PlatformServiceImpl.java | 118 +- .../iot/vmp/service/impl/PlayServiceImpl.java | 364 +- .../redisMsg/RedisAlarmMsgListener.java | 21 +- .../MobilePositionController.java | 23 +- .../gb28181/alarm/AlarmController.java | 22 +- .../vmanager/gb28181/device/DeviceConfig.java | 47 +- .../gb28181/device/DeviceControl.java | 143 +- .../vmanager/gb28181/device/DeviceQuery.java | 43 +- .../gb28181/platform/PlatformController.java | 56 +- .../vmanager/gb28181/play/PlayController.java | 46 +- .../gb28181/playback/PlaybackController.java | 40 +- .../vmanager/gb28181/ptz/PtzController.java | 38 +- .../gb28181/record/GBRecordController.java | 46 +- .../vmp/web/gb28181/ApiControlController.java | 20 +- .../vmp/web/gb28181/ApiStreamController.java | 23 +- 53 files changed, 3106 insertions(+), 3052 deletions(-) create mode 100644 src/main/java/com/genersoft/iot/vmp/conf/exception/SsrcTransactionNotFoundException.java create mode 100644 src/main/java/com/genersoft/iot/vmp/gb28181/bean/CmdSendFailEvent.java diff --git a/src/main/java/com/genersoft/iot/vmp/conf/MediaConfig.java b/src/main/java/com/genersoft/iot/vmp/conf/MediaConfig.java index 03498fd0..35ff08ee 100644 --- a/src/main/java/com/genersoft/iot/vmp/conf/MediaConfig.java +++ b/src/main/java/com/genersoft/iot/vmp/conf/MediaConfig.java @@ -2,6 +2,9 @@ package com.genersoft.iot.vmp.conf; import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; import com.genersoft.iot.vmp.utils.DateUtil; +import com.genersoft.iot.vmp.vmanager.gb28181.device.DeviceQuery; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Configuration; import org.springframework.util.ObjectUtils; @@ -15,6 +18,8 @@ import java.util.regex.Pattern; @Configuration("mediaConfig") public class MediaConfig{ + private final static Logger logger = LoggerFactory.getLogger(MediaConfig.class); + // 修改必须配置,不再支持自动获取 @Value("${media.id}") private String id; @@ -174,7 +179,7 @@ public class MediaConfig{ try { hostAddress = InetAddress.getByName(sdpIp).getHostAddress(); } catch (UnknownHostException e) { - throw new RuntimeException(e); + logger.error("[获取SDP IP]: 域名解析失败"); } return hostAddress; } diff --git a/src/main/java/com/genersoft/iot/vmp/conf/exception/SsrcTransactionNotFoundException.java b/src/main/java/com/genersoft/iot/vmp/conf/exception/SsrcTransactionNotFoundException.java new file mode 100644 index 00000000..4038cd11 --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/conf/exception/SsrcTransactionNotFoundException.java @@ -0,0 +1,51 @@ +package com.genersoft.iot.vmp.conf.exception; + +import com.sun.javafx.binding.StringFormatter; + +/** + * @author lin + */ +public class SsrcTransactionNotFoundException extends Exception{ + private String deviceId; + private String channelId; + private String callId; + private String stream; + + + + public SsrcTransactionNotFoundException(String deviceId, String channelId, String callId, String stream) { + this.deviceId = deviceId; + this.channelId = channelId; + this.callId = callId; + this.stream = stream; + } + + public String getDeviceId() { + return deviceId; + } + + public String getChannelId() { + return channelId; + } + + public String getCallId() { + return callId; + } + + public String getStream() { + return stream; + } + + @Override + public String getMessage() { + StringBuffer msg = new StringBuffer(); + msg.append(StringFormatter.format("缓存事务信息未找到,device:%s channel: %s ", deviceId, channelId)); + if (callId != null) { + msg.append("callId: " + callId); + } + if (stream != null) { + msg.append("stream: " + stream); + } + return msg.toString(); + } +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/SipLayer.java b/src/main/java/com/genersoft/iot/vmp/gb28181/SipLayer.java index cd8b5d76..6cd19245 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/SipLayer.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/SipLayer.java @@ -41,7 +41,7 @@ public class SipLayer{ @Bean("sipStack") @DependsOn({"sipFactory"}) - SipStack createSipStack() throws PeerUnavailableException { + SipStackImpl createSipStack() throws PeerUnavailableException { sipStack = ( SipStackImpl )sipFactory.createSipStack(DefaultProperties.getProperties(sipConfig.getMonitorIp(), false)); return sipStack; } @@ -56,7 +56,6 @@ public class SipLayer{ tcpSipProvider = (SipProviderImpl)sipStack.createSipProvider(tcpListeningPoint); tcpSipProvider.setDialogErrorsAutomaticallyHandled(); tcpSipProvider.addSipListener(sipProcessorObserver); -// tcpSipProvider.setAutomaticDialogSupportEnabled(false); logger.info("[Sip Server] TCP 启动成功 {}:{}", sipConfig.getMonitorIp(), sipConfig.getPort()); } catch (TransportNotSupportedException e) { e.printStackTrace(); @@ -80,7 +79,6 @@ public class SipLayer{ udpListeningPoint = sipStack.createListeningPoint(sipConfig.getMonitorIp(), sipConfig.getPort(), "UDP"); udpSipProvider = (SipProviderImpl)sipStack.createSipProvider(udpListeningPoint); udpSipProvider.addSipListener(sipProcessorObserver); -// udpSipProvider.setAutomaticDialogSupportEnabled(false); } catch (TransportNotSupportedException e) { e.printStackTrace(); } catch (InvalidArgumentException e) { diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/CmdSendFailEvent.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/CmdSendFailEvent.java new file mode 100644 index 00000000..0cd4086e --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/CmdSendFailEvent.java @@ -0,0 +1,27 @@ +package com.genersoft.iot.vmp.gb28181.bean; + +import javax.sip.Dialog; +import java.util.EventObject; + +public class CmdSendFailEvent extends EventObject { + + private String callId; + + /** + * Constructs a prototypical Event. + * + * @param dialog + * @throws IllegalArgumentException if source is null. + */ + public CmdSendFailEvent(Dialog dialog) { + super(dialog); + } + + public String getCallId() { + return callId; + } + + public void setCallId(String callId) { + this.callId = callId; + } +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/DeviceNotFoundEvent.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/DeviceNotFoundEvent.java index 4e55011f..c782c3c1 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/DeviceNotFoundEvent.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/DeviceNotFoundEvent.java @@ -4,6 +4,9 @@ import javax.sip.Dialog; import java.util.EventObject; public class DeviceNotFoundEvent extends EventObject { + + private String callId; + /** * Constructs a prototypical Event. * @@ -14,8 +17,11 @@ public class DeviceNotFoundEvent extends EventObject { super(dialog); } + public String getCallId() { + return callId; + } - public Dialog getDialog() { - return (Dialog)super.getSource(); + public void setCallId(String callId) { + this.callId = callId; } } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/SipTransactionInfo.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/SipTransactionInfo.java index c68be129..c04a6959 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/SipTransactionInfo.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/SipTransactionInfo.java @@ -1,6 +1,7 @@ package com.genersoft.iot.vmp.gb28181.bean; import gov.nist.javax.sip.message.SIPRequest; +import gov.nist.javax.sip.message.SIPResponse; public class SipTransactionInfo { @@ -9,11 +10,11 @@ public class SipTransactionInfo { private String toTag; private String viaBranch; - public SipTransactionInfo(SIPRequest request) { - this.callId = request.getCallIdHeader().getCallId(); - this.fromTag = request.getFromTag(); - this.toTag = request.getToTag(); - this.viaBranch = request.getTopmostViaHeader().getBranch(); + public SipTransactionInfo(SIPResponse response) { + this.callId = response.getCallIdHeader().getCallId(); + this.fromTag = response.getFromTag(); + this.toTag = response.getToTag(); + this.viaBranch = response.getTopmostViaHeader().getBranch(); } public SipTransactionInfo() { diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/SsrcTransaction.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/SsrcTransaction.java index 87d26359..d27ce262 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/SsrcTransaction.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/SsrcTransaction.java @@ -8,10 +8,11 @@ public class SsrcTransaction { private String channelId; private String callId; private String stream; - private byte[] transaction; - private byte[] dialog; private String mediaServerId; private String ssrc; + + private SipTransactionInfo sipTransactionInfo; + private VideoStreamSessionManager.SessionType type; public String getDeviceId() { @@ -46,22 +47,6 @@ public class SsrcTransaction { this.stream = stream; } - public byte[] getTransaction() { - return transaction; - } - - public void setTransaction(byte[] transaction) { - this.transaction = transaction; - } - - public byte[] getDialog() { - return dialog; - } - - public void setDialog(byte[] dialog) { - this.dialog = dialog; - } - public String getMediaServerId() { return mediaServerId; } @@ -85,4 +70,12 @@ public class SsrcTransaction { public void setType(VideoStreamSessionManager.SessionType type) { this.type = type; } + + public SipTransactionInfo getSipTransactionInfo() { + return sipTransactionInfo; + } + + public void setSipTransactionInfo(SipTransactionInfo sipTransactionInfo) { + this.sipTransactionInfo = sipTransactionInfo; + } } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/SubscribeInfo.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/SubscribeInfo.java index 2c80c62b..e971c7a4 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/SubscribeInfo.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/SubscribeInfo.java @@ -1,15 +1,10 @@ package com.genersoft.iot.vmp.gb28181.bean; -import com.genersoft.iot.vmp.utils.SerializeUtils; import gov.nist.javax.sip.message.SIPRequest; import gov.nist.javax.sip.message.SIPResponse; -import javax.sip.ClientTransaction; -import javax.sip.Dialog; -import javax.sip.RequestEvent; import javax.sip.ServerTransaction; import javax.sip.header.*; -import javax.sip.message.Request; public class SubscribeInfo { diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/event/SipSubscribe.java b/src/main/java/com/genersoft/iot/vmp/gb28181/event/SipSubscribe.java index 69529b06..e5b995e4 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/event/SipSubscribe.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/event/SipSubscribe.java @@ -10,6 +10,7 @@ import org.springframework.stereotype.Component; import javax.sip.*; import javax.sip.header.CallIdHeader; import javax.sip.message.Response; +import java.text.ParseException; import java.time.Instant; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -56,8 +57,7 @@ public class SipSubscribe { logger.debug("errorSubscribes.size:{}",errorSubscribes.size()); } - public interface Event { - void response(EventResult eventResult); + public interface Event { void response(EventResult eventResult) ; } /** @@ -81,18 +81,13 @@ public class SipSubscribe { public EventResultType type; public String msg; public String callId; - public Dialog dialog; public EventObject event; - public EventResult() { - } - public EventResult(EventObject event) { this.event = event; if (event instanceof ResponseEvent) { ResponseEvent responseEvent = (ResponseEvent)event; Response response = responseEvent.getResponse(); - this.dialog = responseEvent.getDialog(); this.type = EventResultType.response; if (response != null) { this.msg = response.getReasonPhrase(); @@ -127,12 +122,10 @@ public class SipSubscribe { this.statusCode = -1024; this.callId = dialogTerminatedEvent.getDialog().getCallId().getCallId(); }else if (event instanceof DeviceNotFoundEvent) { - DeviceNotFoundEvent deviceNotFoundEvent = (DeviceNotFoundEvent)event; this.type = EventResultType.deviceNotFoundEvent; this.msg = "设备未找到"; this.statusCode = -1024; - this.dialog = deviceNotFoundEvent.getDialog(); - this.callId = this.dialog != null ?deviceNotFoundEvent.getDialog().getCallId().getCallId() : null; + this.callId = ((DeviceNotFoundEvent) event).getCallId(); } } } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/event/device/RequestTimeoutEventImpl.java b/src/main/java/com/genersoft/iot/vmp/gb28181/event/device/RequestTimeoutEventImpl.java index 9382c2f6..bffa4cb9 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/event/device/RequestTimeoutEventImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/event/device/RequestTimeoutEventImpl.java @@ -36,6 +36,7 @@ public class RequestTimeoutEventImpl implements ApplicationListener { } if (deviceChannelList.size() > 0) { logger.info("[Catalog事件: {}]平台:{},影响通道{}个", event.getType(), event.getPlatformId(), deviceChannelList.size()); - sipCommanderFroPlatform.sendNotifyForCatalogOther(event.getType(), parentPlatform, deviceChannelList, subscribe, null); + try { + sipCommanderFroPlatform.sendNotifyForCatalogOther(event.getType(), parentPlatform, deviceChannelList, subscribe, null); + } catch (InvalidArgumentException | ParseException | NoSuchFieldException | SipException | + IllegalAccessException e) { + logger.error("[命令发送失败] 国标级联 Catalog通知: {}", e.getMessage()); + } } }else if (parentPlatformMap.keySet().size() > 0) { for (String gbId : parentPlatformMap.keySet()) { @@ -112,7 +120,12 @@ public class CatalogEventLister implements ApplicationListener { DeviceChannel deviceChannel = new DeviceChannel(); deviceChannel.setChannelId(gbId); deviceChannelList.add(deviceChannel); - sipCommanderFroPlatform.sendNotifyForCatalogOther(event.getType(), platform, deviceChannelList, subscribeInfo, null); + try { + sipCommanderFroPlatform.sendNotifyForCatalogOther(event.getType(), platform, deviceChannelList, subscribeInfo, null); + } catch (InvalidArgumentException | ParseException | NoSuchFieldException | SipException | + IllegalAccessException e) { + logger.error("[命令发送失败] 国标级联 Catalog通知: {}", e.getMessage()); + } } } } @@ -137,7 +150,12 @@ public class CatalogEventLister implements ApplicationListener { } if (deviceChannelList.size() > 0) { logger.info("[Catalog事件: {}]平台:{},影响通道{}个", event.getType(), event.getPlatformId(), deviceChannelList.size()); - sipCommanderFroPlatform.sendNotifyForCatalogAddOrUpdate(event.getType(), parentPlatform, deviceChannelList, subscribe, null); + try { + sipCommanderFroPlatform.sendNotifyForCatalogAddOrUpdate(event.getType(), parentPlatform, deviceChannelList, subscribe, null); + } catch (InvalidArgumentException | ParseException | NoSuchFieldException | SipException | + IllegalAccessException e) { + logger.error("[命令发送失败] 国标级联 Catalog通知: {}", e.getMessage()); + } } }else if (parentPlatformMap.keySet().size() > 0) { for (String gbId : parentPlatformMap.keySet()) { @@ -157,7 +175,12 @@ public class CatalogEventLister implements ApplicationListener { DeviceChannel deviceChannelByStream = gbStreamService.getDeviceChannelListByStreamWithStatus(gbStream, gbStream.getCatalogId(), platform); deviceChannelList.add(deviceChannelByStream); } - sipCommanderFroPlatform.sendNotifyForCatalogAddOrUpdate(event.getType(), platform, deviceChannelList, subscribeInfo, null); + try { + sipCommanderFroPlatform.sendNotifyForCatalogAddOrUpdate(event.getType(), platform, deviceChannelList, subscribeInfo, null); + } catch (InvalidArgumentException | ParseException | NoSuchFieldException | + SipException | IllegalAccessException e) { + logger.error("[命令发送失败] 国标级联 Catalog通知: {}", e.getMessage()); + } } } } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/session/VideoStreamSessionManager.java b/src/main/java/com/genersoft/iot/vmp/gb28181/session/VideoStreamSessionManager.java index b4d254ab..6e7b3dcc 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/session/VideoStreamSessionManager.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/session/VideoStreamSessionManager.java @@ -8,9 +8,13 @@ import javax.sip.Dialog; import com.genersoft.iot.vmp.common.VideoManagerConstants; import com.genersoft.iot.vmp.conf.UserSetting; +import com.genersoft.iot.vmp.gb28181.bean.SipMsgInfo; +import com.genersoft.iot.vmp.gb28181.bean.SipTransactionInfo; import com.genersoft.iot.vmp.gb28181.bean.SsrcTransaction; import com.genersoft.iot.vmp.utils.SerializeUtils; import com.genersoft.iot.vmp.utils.redis.RedisUtil; +import gov.nist.javax.sip.message.SIPRequest; +import gov.nist.javax.sip.message.SIPResponse; import gov.nist.javax.sip.stack.SIPDialog; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -42,15 +46,14 @@ public class VideoStreamSessionManager { * @param callId 一次请求的CallID * @param stream 流名称 * @param mediaServerId 所使用的流媒体ID - * @param transaction 事务 + * @param response 回复 */ - public void put(String deviceId, String channelId, String callId, String stream, String ssrc, String mediaServerId, ClientTransaction transaction, SessionType type){ + public void put(String deviceId, String channelId, String callId, String stream, String ssrc, String mediaServerId, SIPResponse response, SessionType type){ SsrcTransaction ssrcTransaction = new SsrcTransaction(); ssrcTransaction.setDeviceId(deviceId); ssrcTransaction.setChannelId(channelId); ssrcTransaction.setStream(stream); - byte[] transactionByteArray = SerializeUtils.serialize(transaction); - ssrcTransaction.setTransaction(transactionByteArray); + ssrcTransaction.setSipTransactionInfo(new SipTransactionInfo(response)); ssrcTransaction.setCallId(callId); ssrcTransaction.setSsrc(ssrc); ssrcTransaction.setMediaServerId(mediaServerId); @@ -62,53 +65,6 @@ public class VideoStreamSessionManager { + "_" + deviceId + "_" + channelId + "_" + callId + "_" + stream, ssrcTransaction); } - public void put(String deviceId, String channelId, String callId, Dialog dialog){ - SsrcTransaction ssrcTransaction = getSsrcTransaction(deviceId, channelId, callId, null); - if (ssrcTransaction != null) { - byte[] dialogByteArray = SerializeUtils.serialize(dialog); - ssrcTransaction.setDialog(dialogByteArray); - } - RedisUtil.set(VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX + userSetting.getServerId() - + "_" + deviceId + "_" + channelId + "_" + ssrcTransaction.getCallId() + "_" - + ssrcTransaction.getStream(), ssrcTransaction); - } - - - public ClientTransaction getTransaction(String deviceId, String channelId, String stream, String callId){ - SsrcTransaction ssrcTransaction = getSsrcTransaction(deviceId, channelId, callId, stream); - if (ssrcTransaction == null) { - return null; - } - byte[] transactionByteArray = ssrcTransaction.getTransaction(); - ClientTransaction clientTransaction = (ClientTransaction)SerializeUtils.deSerialize(transactionByteArray); - return clientTransaction; - } - - public SIPDialog getDialogByStream(String deviceId, String channelId, String stream){ - SsrcTransaction ssrcTransaction = getSsrcTransaction(deviceId, channelId, null, stream); - if (ssrcTransaction == null) { - return null; - } - byte[] dialogByteArray = ssrcTransaction.getDialog(); - if (dialogByteArray == null) { - return null; - } - SIPDialog dialog = (SIPDialog)SerializeUtils.deSerialize(dialogByteArray); - return dialog; - } - - public SIPDialog getDialogByCallId(String deviceId, String channelId, String callId){ - SsrcTransaction ssrcTransaction = getSsrcTransaction(deviceId, channelId, callId, null); - if (ssrcTransaction == null) { - return null; - } - byte[] dialogByteArray = ssrcTransaction.getDialog(); - if (dialogByteArray == null) { - return null; - } - return (SIPDialog)SerializeUtils.deSerialize(dialogByteArray); - } - public SsrcTransaction getSsrcTransaction(String deviceId, String channelId, String callId, String stream){ if (ObjectUtils.isEmpty(deviceId)) { diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/task/impl/CatalogSubscribeTask.java b/src/main/java/com/genersoft/iot/vmp/gb28181/task/impl/CatalogSubscribeTask.java index bfa900a9..39dff931 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/task/impl/CatalogSubscribeTask.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/task/impl/CatalogSubscribeTask.java @@ -10,9 +10,7 @@ import org.slf4j.LoggerFactory; import org.springframework.scheduling.annotation.Async; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; -import javax.sip.Dialog; -import javax.sip.DialogState; -import javax.sip.ResponseEvent; +import javax.sip.*; import javax.sip.header.ToHeader; import java.text.ParseException; import java.util.Timer; @@ -44,23 +42,29 @@ public class CatalogSubscribeTask implements ISubscribeTask { if (dynamicTask.get(taskKey) != null) { dynamicTask.stop(taskKey); } - SIPRequest sipRequest = sipCommander.catalogSubscribe(device, request, eventResult -> { - ResponseEvent event = (ResponseEvent) eventResult.event; - // 成功 - logger.info("[目录订阅]成功: {}", device.getDeviceId()); - ToHeader toHeader = (ToHeader)event.getResponse().getHeader(ToHeader.NAME); - try { - this.request.getToHeader().setTag(toHeader.getTag()); - } catch (ParseException e) { - logger.info("[目录订阅]成功: 但为request设置ToTag失败"); + SIPRequest sipRequest = null; + try { + sipRequest = sipCommander.catalogSubscribe(device, request, eventResult -> { + ResponseEvent event = (ResponseEvent) eventResult.event; + // 成功 + logger.info("[目录订阅]成功: {}", device.getDeviceId()); + ToHeader toHeader = (ToHeader)event.getResponse().getHeader(ToHeader.NAME); + try { + this.request.getToHeader().setTag(toHeader.getTag()); + } catch (ParseException e) { + logger.info("[目录订阅]成功: 但为request设置ToTag失败"); + this.request = null; + } + },eventResult -> { this.request = null; - } - },eventResult -> { - this.request = null; - // 失败 - logger.warn("[目录订阅]失败,信令发送失败: {}-{} ", device.getDeviceId(), eventResult.msg); - dynamicTask.startDelay(taskKey, CatalogSubscribeTask.this, 2000); - }); + // 失败 + logger.warn("[目录订阅]失败,信令发送失败: {}-{} ", device.getDeviceId(), eventResult.msg); + dynamicTask.startDelay(taskKey, CatalogSubscribeTask.this, 2000); + }); + } catch (InvalidArgumentException | SipException | ParseException e) { + logger.error("[命令发送失败] 目录订阅: {}", e.getMessage()); + + } if (sipRequest != null) { this.request = sipRequest; } @@ -80,18 +84,22 @@ public class CatalogSubscribeTask implements ISubscribeTask { dynamicTask.stop(taskKey); } device.setSubscribeCycleForCatalog(0); - sipCommander.catalogSubscribe(device, request, eventResult -> { - ResponseEvent event = (ResponseEvent) eventResult.event; - if (event.getResponse().getRawContent() != null) { - // 成功 - logger.info("[取消目录订阅订阅]成功: {}", device.getDeviceId()); - }else { - // 成功 - logger.info("[取消目录订阅订阅]成功: {}", device.getDeviceId()); - } - },eventResult -> { - // 失败 - logger.warn("[取消目录订阅订阅]失败,信令发送失败: {}-{} ", device.getDeviceId(), eventResult.msg); - }); + try { + sipCommander.catalogSubscribe(device, request, eventResult -> { + ResponseEvent event = (ResponseEvent) eventResult.event; + if (event.getResponse().getRawContent() != null) { + // 成功 + logger.info("[取消目录订阅订阅]成功: {}", device.getDeviceId()); + }else { + // 成功 + logger.info("[取消目录订阅订阅]成功: {}", device.getDeviceId()); + } + },eventResult -> { + // 失败 + logger.warn("[取消目录订阅订阅]失败,信令发送失败: {}-{} ", device.getDeviceId(), eventResult.msg); + }); + } catch (InvalidArgumentException | SipException | ParseException e) { + logger.error("[命令发送失败] 取消目录订阅订阅: {}", e.getMessage()); + } } } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/task/impl/MobilePositionSubscribeTask.java b/src/main/java/com/genersoft/iot/vmp/gb28181/task/impl/MobilePositionSubscribeTask.java index 5dbdbe64..0abd3cae 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/task/impl/MobilePositionSubscribeTask.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/task/impl/MobilePositionSubscribeTask.java @@ -11,9 +11,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.scheduling.annotation.Async; -import javax.sip.Dialog; -import javax.sip.DialogState; -import javax.sip.ResponseEvent; +import javax.sip.*; import javax.sip.header.ToHeader; import java.text.ParseException; import java.util.Timer; @@ -43,23 +41,28 @@ public class MobilePositionSubscribeTask implements ISubscribeTask { if (dynamicTask.get(taskKey) != null) { dynamicTask.stop(taskKey); } - SIPRequest sipRequest = sipCommander.mobilePositionSubscribe(device, request, eventResult -> { - // 成功 - logger.info("[移动位置订阅]成功: {}", device.getDeviceId()); - ResponseEvent event = (ResponseEvent) eventResult.event; - ToHeader toHeader = (ToHeader)event.getResponse().getHeader(ToHeader.NAME); - try { - this.request.getToHeader().setTag(toHeader.getTag()); - } catch (ParseException e) { - logger.info("[移动位置订阅]成功: 为request设置ToTag失败"); + SIPRequest sipRequest = null; + try { + sipRequest = sipCommander.mobilePositionSubscribe(device, request, eventResult -> { + // 成功 + logger.info("[移动位置订阅]成功: {}", device.getDeviceId()); + ResponseEvent event = (ResponseEvent) eventResult.event; + ToHeader toHeader = (ToHeader)event.getResponse().getHeader(ToHeader.NAME); + try { + this.request.getToHeader().setTag(toHeader.getTag()); + } catch (ParseException e) { + logger.info("[移动位置订阅]成功: 为request设置ToTag失败"); + this.request = null; + } + },eventResult -> { this.request = null; - } - },eventResult -> { - this.request = null; - // 失败 - logger.warn("[移动位置订阅]失败,信令发送失败: {}-{} ", device.getDeviceId(), eventResult.msg); - dynamicTask.startDelay(taskKey, MobilePositionSubscribeTask.this, 2000); - }); + // 失败 + logger.warn("[移动位置订阅]失败,信令发送失败: {}-{} ", device.getDeviceId(), eventResult.msg); + dynamicTask.startDelay(taskKey, MobilePositionSubscribeTask.this, 2000); + }); + } catch (InvalidArgumentException | SipException | ParseException e) { + logger.error("[命令发送失败] 移动位置订阅: {}", e.getMessage()); + } if (sipRequest != null) { this.request = sipRequest; } @@ -79,18 +82,22 @@ public class MobilePositionSubscribeTask implements ISubscribeTask { dynamicTask.stop(taskKey); } device.setSubscribeCycleForMobilePosition(0); - sipCommander.mobilePositionSubscribe(device, request, eventResult -> { - ResponseEvent event = (ResponseEvent) eventResult.event; - if (event.getResponse().getRawContent() != null) { - // 成功 - logger.info("[取消移动位置订阅]成功: {}", device.getDeviceId()); - }else { - // 成功 - logger.info("[取消移动位置订阅]成功: {}", device.getDeviceId()); - } - },eventResult -> { - // 失败 - logger.warn("[取消移动位置订阅]失败,信令发送失败: {}-{} ", device.getDeviceId(), eventResult.msg); - }); + try { + sipCommander.mobilePositionSubscribe(device, request, eventResult -> { + ResponseEvent event = (ResponseEvent) eventResult.event; + if (event.getResponse().getRawContent() != null) { + // 成功 + logger.info("[取消移动位置订阅]成功: {}", device.getDeviceId()); + }else { + // 成功 + logger.info("[取消移动位置订阅]成功: {}", device.getDeviceId()); + } + },eventResult -> { + // 失败 + logger.warn("[取消移动位置订阅]失败,信令发送失败: {}-{} ", device.getDeviceId(), eventResult.msg); + }); + } catch (InvalidArgumentException | SipException | ParseException e) { + logger.error("[命令发送失败] 取消移动位置订阅: {}", e.getMessage()); + } } } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java index c7f6385e..2410e6d0 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java @@ -1,6 +1,7 @@ package com.genersoft.iot.vmp.gb28181.transmit.cmd; import com.genersoft.iot.vmp.common.StreamInfo; +import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException; import com.genersoft.iot.vmp.gb28181.bean.*; import com.genersoft.iot.vmp.gb28181.event.SipSubscribe; import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe; @@ -9,6 +10,11 @@ import com.genersoft.iot.vmp.service.bean.SSRCInfo; import gov.nist.javax.sip.message.SIPRequest; import javax.sip.Dialog; +import javax.sip.InvalidArgumentException; +import javax.sip.PeerUnavailableException; +import javax.sip.SipException; +import javax.sip.message.Request; +import java.text.ParseException; /** * @description:设备能力接口,用于定义设备的控制、查询能力 @@ -25,7 +31,7 @@ public interface ISIPCommander { * @param leftRight 镜头左移右移 0:停止 1:左移 2:右移 * @param upDown 镜头上移下移 0:停止 1:上移 2:下移 */ - boolean ptzdirectCmd(Device device,String channelId,int leftRight, int upDown); + void ptzdirectCmd(Device device,String channelId,int leftRight, int upDown) throws InvalidArgumentException, ParseException, SipException; /** * 云台方向放控制 @@ -36,7 +42,7 @@ public interface ISIPCommander { * @param upDown 镜头上移下移 0:停止 1:上移 2:下移 * @param moveSpeed 镜头移动速度 */ - boolean ptzdirectCmd(Device device,String channelId,int leftRight, int upDown, int moveSpeed); + void ptzdirectCmd(Device device,String channelId,int leftRight, int upDown, int moveSpeed) throws InvalidArgumentException, ParseException, SipException; /** * 云台缩放控制,使用配置文件中的默认镜头缩放速度 @@ -45,7 +51,7 @@ public interface ISIPCommander { * @param channelId 预览通道 * @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大 */ - boolean ptzZoomCmd(Device device,String channelId,int inOut); + void ptzZoomCmd(Device device,String channelId,int inOut) throws InvalidArgumentException, ParseException, SipException; /** * 云台缩放控制 @@ -54,7 +60,7 @@ public interface ISIPCommander { * @param channelId 预览通道 * @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大 */ - boolean ptzZoomCmd(Device device,String channelId,int inOut, int moveSpeed); + void ptzZoomCmd(Device device,String channelId,int inOut, int moveSpeed) throws InvalidArgumentException, ParseException, SipException; /** * 云台控制,支持方向与缩放控制 @@ -67,7 +73,7 @@ public interface ISIPCommander { * @param moveSpeed 镜头移动速度 * @param zoomSpeed 镜头缩放速度 */ - boolean ptzCmd(Device device,String channelId,int leftRight, int upDown, int inOut, int moveSpeed, int zoomSpeed); + void ptzCmd(Device device,String channelId,int leftRight, int upDown, int inOut, int moveSpeed, int zoomSpeed) throws InvalidArgumentException, SipException, ParseException; /** * 前端控制,包括PTZ指令、FI指令、预置位指令、巡航指令、扫描指令和辅助开关指令 @@ -79,7 +85,7 @@ public interface ISIPCommander { * @param parameter2 数据2 * @param combineCode2 组合码2 */ - boolean frontEndCmd(Device device, String channelId, int cmdCode, int parameter1, int parameter2, int combineCode2); + void frontEndCmd(Device device, String channelId, int cmdCode, int parameter1, int parameter2, int combineCode2) throws SipException, InvalidArgumentException, ParseException; /** * 前端控制指令(用于转发上级指令) @@ -87,14 +93,14 @@ public interface ISIPCommander { * @param channelId 预览通道 * @param cmdString 前端控制指令串 */ - boolean fronEndCmd(Device device, String channelId, String cmdString, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent); + void fronEndCmd(Device device, String channelId, String cmdString, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException; /** * 请求预览视频流 * @param device 视频设备 * @param channelId 预览通道 */ - void playStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, ZlmHttpHookSubscribe.Event event, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent); + void playStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, ZlmHttpHookSubscribe.Event event, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException; /** * 请求回放视频流 @@ -104,7 +110,7 @@ public interface ISIPCommander { * @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss */ - void playbackStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInf, Device device, String channelId, String startTime, String endTime,InviteStreamCallback inviteStreamCallback, InviteStreamCallback event, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent); + void playbackStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInf, Device device, String channelId, String startTime, String endTime,InviteStreamCallback inviteStreamCallback, InviteStreamCallback event, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException; /** * 请求历史媒体下载 @@ -117,33 +123,33 @@ public interface ISIPCommander { */ void downloadStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, String startTime, String endTime, int downloadSpeed, InviteStreamCallback inviteStreamCallback, InviteStreamCallback hookEvent, - SipSubscribe.Event errorEvent); + SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException; /** * 视频流停止 */ - void streamByeCmd(String deviceId, String channelId, String stream, String callId, SipSubscribe.Event okEvent); - void streamByeCmd(String deviceId, String channelId, String stream, String callId); + void streamByeCmd(Device device, String channelId, String stream, String callId, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException, SsrcTransactionNotFoundException; + void streamByeCmd(Device device, String channelId, String stream, String callId) throws InvalidArgumentException, ParseException, SipException, SsrcTransactionNotFoundException; /** * 回放暂停 */ - void playPauseCmd(Device device, StreamInfo streamInfo); + void playPauseCmd(Device device, StreamInfo streamInfo) throws InvalidArgumentException, ParseException, SipException; /** * 回放恢复 */ - void playResumeCmd(Device device, StreamInfo streamInfo); + void playResumeCmd(Device device, StreamInfo streamInfo) throws InvalidArgumentException, ParseException, SipException; /** * 回放拖动播放 */ - void playSeekCmd(Device device, StreamInfo streamInfo, long seekTime); + void playSeekCmd(Device device, StreamInfo streamInfo, long seekTime) throws InvalidArgumentException, ParseException, SipException; /** * 回放倍速播放 */ - void playSpeedCmd(Device device, StreamInfo streamInfo, Double speed); + void playSpeedCmd(Device device, StreamInfo streamInfo, Double speed) throws InvalidArgumentException, ParseException, SipException; /** * 回放控制 @@ -151,23 +157,24 @@ public interface ISIPCommander { * @param streamInfo * @param content */ - void playbackControlCmd(Device device, StreamInfo streamInfo, String content,SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent); + void playbackControlCmd(Device device, StreamInfo streamInfo, String content,SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws SipException, InvalidArgumentException, ParseException; - /** + + /** * 语音广播 * * @param device 视频设备 * @param channelId 预览通道 */ - boolean audioBroadcastCmd(Device device,String channelId); + void audioBroadcastCmd(Device device,String channelId); /** * 语音广播 * * @param device 视频设备 */ - void audioBroadcastCmd(Device device, SipSubscribe.Event okEvent); - boolean audioBroadcastCmd(Device device); + void audioBroadcastCmd(Device device, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException; + void audioBroadcastCmd(Device device) throws InvalidArgumentException, SipException, ParseException; /** * 音视频录像控制 @@ -176,21 +183,21 @@ public interface ISIPCommander { * @param channelId 预览通道 * @param recordCmdStr 录像命令:Record / StopRecord */ - boolean recordCmd(Device device, String channelId, String recordCmdStr, SipSubscribe.Event errorEvent); + void recordCmd(Device device, String channelId, String recordCmdStr, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException; /** * 远程启动控制命令 * * @param device 视频设备 */ - boolean teleBootCmd(Device device); + void teleBootCmd(Device device) throws InvalidArgumentException, SipException, ParseException; /** * 报警布防/撤防命令 * * @param device 视频设备 */ - boolean guardCmd(Device device, String guardCmdStr, SipSubscribe.Event errorEvent); + void guardCmd(Device device, String guardCmdStr, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException; /** * 报警复位命令 @@ -199,7 +206,7 @@ public interface ISIPCommander { * @param alarmMethod 报警方式(可选) * @param alarmType 报警类型(可选) */ - boolean alarmCmd(Device device, String alarmMethod, String alarmType, SipSubscribe.Event errorEvent); + void alarmCmd(Device device, String alarmMethod, String alarmType, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException; /** * 强制关键帧命令,设备收到此命令应立刻发送一个IDR帧 @@ -207,7 +214,7 @@ public interface ISIPCommander { * @param device 视频设备 * @param channelId 预览通道 */ - boolean iFrameCmd(Device device, String channelId); + void iFrameCmd(Device device, String channelId) throws InvalidArgumentException, SipException, ParseException; /** * 看守位控制命令 @@ -217,14 +224,14 @@ public interface ISIPCommander { * @param resetTime 自动归位时间间隔,开启看守位时使用,单位:秒(s) * @param presetIndex 调用预置位编号,开启看守位时使用,取值范围0~255 */ - boolean homePositionCmd(Device device, String channelId, String enabled, String resetTime, String presetIndex, SipSubscribe.Event errorEvent); + void homePositionCmd(Device device, String channelId, String enabled, String resetTime, String presetIndex, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException; /** * 设备配置命令 * * @param device 视频设备 */ - boolean deviceConfigCmd(Device device); + void deviceConfigCmd(Device device); /** * 设备配置命令:basicParam @@ -236,14 +243,14 @@ public interface ISIPCommander { * @param heartBeatInterval 心跳间隔时间(可选) * @param heartBeatCount 心跳超时次数(可选) */ - boolean deviceBasicConfigCmd(Device device, String channelId, String name, String expiration, String heartBeatInterval, String heartBeatCount, SipSubscribe.Event errorEvent); + void deviceBasicConfigCmd(Device device, String channelId, String name, String expiration, String heartBeatInterval, String heartBeatCount, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException; /** * 查询设备状态 * * @param device 视频设备 */ - boolean deviceStatusQuery(Device device, SipSubscribe.Event errorEvent); + void deviceStatusQuery(Device device, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException; /** * 查询设备信息 @@ -251,14 +258,14 @@ public interface ISIPCommander { * @param device 视频设备 * @return */ - boolean deviceInfoQuery(Device device); + void deviceInfoQuery(Device device) throws InvalidArgumentException, SipException, ParseException; /** * 查询目录列表 * * @param device 视频设备 */ - boolean catalogQuery(Device device, int sn, SipSubscribe.Event errorEvent); + void catalogQuery(Device device, int sn, SipSubscribe.Event errorEvent) throws SipException, InvalidArgumentException, ParseException; /** * 查询录像信息 @@ -268,7 +275,7 @@ public interface ISIPCommander { * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss * @param sn */ - boolean recordInfoQuery(Device device, String channelId, String startTime, String endTime, int sn, Integer Secrecy, String type, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent); + void recordInfoQuery(Device device, String channelId, String startTime, String endTime, int sn, Integer Secrecy, String type, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException; /** * 查询报警信息 @@ -282,8 +289,8 @@ public interface ISIPCommander { * @param endTime 报警发生终止时间(可选) * @return true = 命令发送成功 */ - boolean alarmInfoQuery(Device device, String startPriority, String endPriority, String alarmMethod, - String alarmType, String startTime, String endTime, SipSubscribe.Event errorEvent); + void alarmInfoQuery(Device device, String startPriority, String endPriority, String alarmMethod, + String alarmType, String startTime, String endTime, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException; /** * 查询设备配置 @@ -292,21 +299,21 @@ public interface ISIPCommander { * @param channelId 通道编码(可选) * @param configType 配置类型: */ - boolean deviceConfigQuery(Device device, String channelId, String configType, SipSubscribe.Event errorEvent); + void deviceConfigQuery(Device device, String channelId, String configType, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException; /** * 查询设备预置位置 * * @param device 视频设备 */ - boolean presetQuery(Device device, String channelId, SipSubscribe.Event errorEvent); + void presetQuery(Device device, String channelId, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException; /** * 查询移动设备位置数据 * * @param device 视频设备 */ - boolean mobilePostitionQuery(Device device, SipSubscribe.Event errorEvent); + void mobilePostitionQuery(Device device, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException; /** * 订阅、取消订阅移动位置 @@ -314,7 +321,7 @@ public interface ISIPCommander { * @param device 视频设备 * @return true = 命令发送成功 */ - SIPRequest mobilePositionSubscribe(Device device, SIPRequest request, SipSubscribe.Event okEvent , SipSubscribe.Event errorEvent); + SIPRequest mobilePositionSubscribe(Device device, SIPRequest request, SipSubscribe.Event okEvent , SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException; /** * 订阅、取消订阅报警信息 @@ -327,14 +334,14 @@ public interface ISIPCommander { * @param endTime 报警发生终止时间(可选) * @return true = 命令发送成功 */ - boolean alarmSubscribe(Device device, int expires, String startPriority, String endPriority, String alarmMethod, String alarmType, String startTime, String endTime); + void alarmSubscribe(Device device, int expires, String startPriority, String endPriority, String alarmMethod, String alarmType, String startTime, String endTime) throws InvalidArgumentException, SipException, ParseException; /** * 订阅、取消订阅目录信息 * @param device 视频设备 * @return true = 命令发送成功 */ - SIPRequest catalogSubscribe(Device device, SIPRequest request, SipSubscribe.Event okEvent ,SipSubscribe.Event errorEvent); + SIPRequest catalogSubscribe(Device device, SIPRequest request, SipSubscribe.Event okEvent ,SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException; /** * 拉框控制命令 @@ -343,7 +350,7 @@ public interface ISIPCommander { * @param channelId 通道id * @param cmdString 前端控制指令串 */ - boolean dragZoomCmd(Device device, String channelId, String cmdString); + void dragZoomCmd(Device device, String channelId, String cmdString) throws InvalidArgumentException, SipException, ParseException; /** @@ -352,5 +359,11 @@ public interface ISIPCommander { * @param deviceAlarm 报警信息信息 * @return */ - boolean sendAlarmMessage(Device device, DeviceAlarm deviceAlarm); + void sendAlarmMessage(Device device, DeviceAlarm deviceAlarm) throws InvalidArgumentException, SipException, ParseException; + + void transmitRequest(String transport, Request request) throws SipException, ParseException ; + + void transmitRequest(String transport, Request request, SipSubscribe.Event errorEvent) throws SipException, ParseException; + + void transmitRequest(String transport, Request request, SipSubscribe.Event errorEvent , SipSubscribe.Event okEvent) throws SipException, ParseException; } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommanderForPlatform.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommanderForPlatform.java index ab229bd5..13a36d7b 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommanderForPlatform.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommanderForPlatform.java @@ -4,7 +4,10 @@ import com.genersoft.iot.vmp.gb28181.bean.*; import com.genersoft.iot.vmp.gb28181.event.SipSubscribe; import com.genersoft.iot.vmp.service.bean.GPSMsgInfo; +import javax.sip.InvalidArgumentException; +import javax.sip.SipException; import javax.sip.header.WWWAuthenticateHeader; +import java.text.ParseException; import java.util.List; public interface ISIPCommanderForPlatform { @@ -14,15 +17,15 @@ public interface ISIPCommanderForPlatform { * @param parentPlatform * @return */ - boolean register(ParentPlatform parentPlatform, SipSubscribe.Event errorEvent , SipSubscribe.Event okEvent); - boolean register(ParentPlatform parentPlatform, String callId, WWWAuthenticateHeader www, SipSubscribe.Event errorEvent , SipSubscribe.Event okEvent, boolean registerAgain, boolean isRegister); + void register(ParentPlatform parentPlatform, SipSubscribe.Event errorEvent , SipSubscribe.Event okEvent) throws InvalidArgumentException, ParseException, SipException; + void register(ParentPlatform parentPlatform, String callId, WWWAuthenticateHeader www, SipSubscribe.Event errorEvent , SipSubscribe.Event okEvent, boolean registerAgain, boolean isRegister) throws SipException, InvalidArgumentException, ParseException; /** * 向上级平台注销 * @param parentPlatform * @return */ - boolean unregister(ParentPlatform parentPlatform, SipSubscribe.Event errorEvent , SipSubscribe.Event okEvent); + void unregister(ParentPlatform parentPlatform, SipSubscribe.Event errorEvent , SipSubscribe.Event okEvent) throws InvalidArgumentException, ParseException, SipException; /** @@ -30,7 +33,7 @@ public interface ISIPCommanderForPlatform { * @param parentPlatform * @return callId(作为接受回复的判定) */ - String keepalive(ParentPlatform parentPlatform,SipSubscribe.Event errorEvent , SipSubscribe.Event okEvent); + String keepalive(ParentPlatform parentPlatform,SipSubscribe.Event errorEvent , SipSubscribe.Event okEvent) throws SipException, InvalidArgumentException, ParseException; /** @@ -42,8 +45,8 @@ public interface ISIPCommanderForPlatform { * @param size * @return */ - boolean catalogQuery(DeviceChannel channel, ParentPlatform parentPlatform, String sn, String fromTag, int size); - boolean catalogQuery(List channels, ParentPlatform parentPlatform, String sn, String fromTag); + void catalogQuery(DeviceChannel channel, ParentPlatform parentPlatform, String sn, String fromTag, int size) throws SipException, InvalidArgumentException, ParseException; + void catalogQuery(List channels, ParentPlatform parentPlatform, String sn, String fromTag) throws InvalidArgumentException, ParseException, SipException; /** * 向上级回复DeviceInfo查询信息 @@ -52,7 +55,7 @@ public interface ISIPCommanderForPlatform { * @param fromTag * @return */ - boolean deviceInfoResponse(ParentPlatform parentPlatform, String sn, String fromTag); + void deviceInfoResponse(ParentPlatform parentPlatform, String sn, String fromTag) throws SipException, InvalidArgumentException, ParseException; /** * 向上级回复DeviceStatus查询信息 @@ -61,7 +64,7 @@ public interface ISIPCommanderForPlatform { * @param fromTag * @return */ - boolean deviceStatusResponse(ParentPlatform parentPlatform, String sn, String fromTag); + void deviceStatusResponse(ParentPlatform parentPlatform, String sn, String fromTag) throws SipException, InvalidArgumentException, ParseException; /** * 向上级回复移动位置订阅消息 @@ -70,7 +73,7 @@ public interface ISIPCommanderForPlatform { * @param subscribeInfo 订阅相关的信息 * @return */ - boolean sendNotifyMobilePosition(ParentPlatform parentPlatform, GPSMsgInfo gpsMsgInfo, SubscribeInfo subscribeInfo); + void sendNotifyMobilePosition(ParentPlatform parentPlatform, GPSMsgInfo gpsMsgInfo, SubscribeInfo subscribeInfo) throws InvalidArgumentException, ParseException, NoSuchFieldException, SipException, IllegalAccessException; /** * 向上级回复报警消息 @@ -78,21 +81,21 @@ public interface ISIPCommanderForPlatform { * @param deviceAlarm 报警信息信息 * @return */ - boolean sendAlarmMessage(ParentPlatform parentPlatform, DeviceAlarm deviceAlarm); + void sendAlarmMessage(ParentPlatform parentPlatform, DeviceAlarm deviceAlarm) throws SipException, InvalidArgumentException, ParseException; /** * 回复catalog事件-增加/更新 * @param parentPlatform * @param deviceChannels */ - boolean sendNotifyForCatalogAddOrUpdate(String type, ParentPlatform parentPlatform, List deviceChannels, SubscribeInfo subscribeInfo, Integer index); + void sendNotifyForCatalogAddOrUpdate(String type, ParentPlatform parentPlatform, List deviceChannels, SubscribeInfo subscribeInfo, Integer index) throws InvalidArgumentException, ParseException, NoSuchFieldException, SipException, IllegalAccessException; /** * 回复catalog事件-删除 * @param parentPlatform * @param deviceChannels */ - boolean sendNotifyForCatalogOther(String type, ParentPlatform parentPlatform, List deviceChannels, SubscribeInfo subscribeInfo, Integer index); + void sendNotifyForCatalogOther(String type, ParentPlatform parentPlatform, List deviceChannels, SubscribeInfo subscribeInfo, Integer index) throws InvalidArgumentException, ParseException, NoSuchFieldException, SipException, IllegalAccessException; /** * 回复recordInfo @@ -101,7 +104,7 @@ public interface ISIPCommanderForPlatform { * @param fromTag fromTag * @param recordInfo 录像信息 */ - boolean recordInfo(DeviceChannel deviceChannel, ParentPlatform parentPlatform, String fromTag, RecordInfo recordInfo); + void recordInfo(DeviceChannel deviceChannel, ParentPlatform parentPlatform, String fromTag, RecordInfo recordInfo) throws SipException, InvalidArgumentException, ParseException; /** * 录像播放推送完成时发送MediaStatus消息 @@ -109,13 +112,13 @@ public interface ISIPCommanderForPlatform { * @param sendRtpItem * @return */ - boolean sendMediaStatusNotify(ParentPlatform platform, SendRtpItem sendRtpItem); + void sendMediaStatusNotify(ParentPlatform platform, SendRtpItem sendRtpItem) throws SipException, InvalidArgumentException, ParseException; /** * 向发起点播的上级回复bye * @param platform 平台信息 * @param callId callId */ - void streamByeCmd(ParentPlatform platform, String callId); - void streamByeCmd(ParentPlatform platform, SendRtpItem sendRtpItem); + void streamByeCmd(ParentPlatform platform, String callId) throws SipException, InvalidArgumentException, ParseException; + void streamByeCmd(ParentPlatform platform, SendRtpItem sendRtpItem) throws SipException, InvalidArgumentException, ParseException; } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderProvider.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderProvider.java index 34c5cbe5..1374ddf5 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderProvider.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderProvider.java @@ -10,6 +10,9 @@ import javax.sip.header.*; import javax.sip.message.Request; import com.genersoft.iot.vmp.common.StreamInfo; +import com.genersoft.iot.vmp.gb28181.bean.SipMsgInfo; +import com.genersoft.iot.vmp.gb28181.bean.SipTransactionInfo; +import com.genersoft.iot.vmp.gb28181.bean.SsrcTransaction; import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager; import com.genersoft.iot.vmp.gb28181.utils.SipUtils; import com.genersoft.iot.vmp.storager.IRedisCatchStorage; @@ -17,6 +20,7 @@ import com.genersoft.iot.vmp.utils.GitUtil; import gov.nist.javax.sip.SipProviderImpl; import gov.nist.javax.sip.SipStackImpl; import gov.nist.javax.sip.message.SIPRequest; +import gov.nist.javax.sip.message.SIPResponse; import gov.nist.javax.sip.stack.SIPDialog; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; @@ -168,34 +172,37 @@ public class SIPRequestHeaderProvider { return request; } - public Request createByteRequest(Device device, String channelId, String viaTag, String fromTag, String toTag, String callId) throws ParseException, InvalidArgumentException, PeerUnavailableException { + public Request createByteRequest(Device device, String channelId, SipTransactionInfo transactionInfo) throws ParseException, InvalidArgumentException, PeerUnavailableException { Request request = null; //请求行 SipURI requestLine = sipFactory.createAddressFactory().createSipURI(channelId, device.getHostAddress()); // via ArrayList viaHeaders = new ArrayList(); - ViaHeader viaHeader = sipFactory.createHeaderFactory().createViaHeader(sipConfig.getIp(), sipConfig.getPort(), device.getTransport(), viaTag); + ViaHeader viaHeader = sipFactory.createHeaderFactory().createViaHeader(sipConfig.getIp(), sipConfig.getPort(), device.getTransport(), SipUtils.getNewViaTag()); viaHeaders.add(viaHeader); //from SipURI fromSipURI = sipFactory.createAddressFactory().createSipURI(sipConfig.getId(),sipConfig.getDomain()); Address fromAddress = sipFactory.createAddressFactory().createAddress(fromSipURI); - FromHeader fromHeader = sipFactory.createHeaderFactory().createFromHeader(fromAddress, fromTag); //必须要有标记,否则无法创建会话,无法回应ack + FromHeader fromHeader = sipFactory.createHeaderFactory().createFromHeader(fromAddress, transactionInfo.getFromTag()); //to SipURI toSipURI = sipFactory.createAddressFactory().createSipURI(channelId,device.getHostAddress()); Address toAddress = sipFactory.createAddressFactory().createAddress(toSipURI); - ToHeader toHeader = sipFactory.createHeaderFactory().createToHeader(toAddress,toTag); + ToHeader toHeader = sipFactory.createHeaderFactory().createToHeader(toAddress, transactionInfo.getToTag()); //Forwards MaxForwardsHeader maxForwards = sipFactory.createHeaderFactory().createMaxForwardsHeader(70); //ceq CSeqHeader cSeqHeader = sipFactory.createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(), Request.BYE); - CallIdHeader callIdHeader = sipFactory.createHeaderFactory().createCallIdHeader(callId); + CallIdHeader callIdHeader = sipFactory.createHeaderFactory().createCallIdHeader(transactionInfo.getCallId()); request = sipFactory.createMessageFactory().createRequest(requestLine, Request.BYE, callIdHeader, cSeqHeader,fromHeader, toHeader, viaHeaders, maxForwards); request.addHeader(SipUtils.createUserAgentHeader(sipFactory, gitUtil)); Address concatAddress = sipFactory.createAddressFactory().createAddress(sipFactory.createAddressFactory().createSipURI(sipConfig.getId(), sipConfig.getIp()+":"+sipConfig.getPort())); + request.addHeader(sipFactory.createHeaderFactory().createContactHeader(concatAddress)); + + request.addHeader(SipUtils.createUserAgentHeader(sipFactory, gitUtil)); return request; } @@ -251,47 +258,72 @@ public class SIPRequestHeaderProvider { return request; } - public Request createInfoRequest(Device device, StreamInfo streamInfo, String content) + public SIPRequest createInfoRequest(Device device, String channelId, String content, SipTransactionInfo transactionInfo) throws SipException, ParseException, InvalidArgumentException { - if (streamInfo == null) { + if (device == null || transactionInfo == null) { return null; } - Request request = null; - SIPDialog dialog = streamSession.getDialogByStream(streamInfo.getDeviceID(), streamInfo.getChannelId(), streamInfo.getStream()); - if (dialog == null) { - return null; + SIPRequest request = null; + //请求行 + SipURI requestLine = sipFactory.createAddressFactory().createSipURI(channelId, device.getHostAddress()); + // via + ArrayList viaHeaders = new ArrayList(); + ViaHeader viaHeader = sipFactory.createHeaderFactory().createViaHeader(sipConfig.getIp(), sipConfig.getPort(), device.getTransport(), SipUtils.getNewViaTag()); + viaHeaders.add(viaHeader); + //from + SipURI fromSipURI = sipFactory.createAddressFactory().createSipURI(sipConfig.getId(),sipConfig.getDomain()); + Address fromAddress = sipFactory.createAddressFactory().createAddress(fromSipURI); + FromHeader fromHeader = sipFactory.createHeaderFactory().createFromHeader(fromAddress, transactionInfo.getFromTag()); + //to + SipURI toSipURI = sipFactory.createAddressFactory().createSipURI(channelId,device.getHostAddress()); + Address toAddress = sipFactory.createAddressFactory().createAddress(toSipURI); + ToHeader toHeader = sipFactory.createHeaderFactory().createToHeader(toAddress, transactionInfo.getToTag()); + + //Forwards + MaxForwardsHeader maxForwards = sipFactory.createHeaderFactory().createMaxForwardsHeader(70); + + //ceq + CSeqHeader cSeqHeader = sipFactory.createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(), Request.INFO); + CallIdHeader callIdHeader = sipFactory.createHeaderFactory().createCallIdHeader(transactionInfo.getCallId()); + request = (SIPRequest)sipFactory.createMessageFactory().createRequest(requestLine, Request.INFO, callIdHeader, cSeqHeader,fromHeader, toHeader, viaHeaders, maxForwards); + + request.addHeader(SipUtils.createUserAgentHeader(sipFactory, gitUtil)); + + Address concatAddress = sipFactory.createAddressFactory().createAddress(sipFactory.createAddressFactory().createSipURI(sipConfig.getId(), sipConfig.getIp()+":"+sipConfig.getPort())); + request.addHeader(sipFactory.createHeaderFactory().createContactHeader(concatAddress)); + + request.addHeader(SipUtils.createUserAgentHeader(sipFactory, gitUtil)); + + if (content != null) { + ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader("Application", + "MANSRTSP"); + request.setContent(content, contentTypeHeader); } + return request; + } - SipStack sipStack = udpSipProvider.getSipStack(); - SIPDialog sipDialog = ((SipStackImpl) sipStack).putDialog(dialog); - if (dialog != sipDialog) { - dialog = sipDialog; - }else { - dialog.setSipProvider(udpSipProvider); - } - streamSession.put(streamInfo.getDeviceID(), streamInfo.getChannelId(), dialog.getCallId().getCallId(), dialog); - Request infoRequest = dialog.createRequest(Request.INFO); - SipURI sipURI = (SipURI) infoRequest.getRequestURI(); - sipURI.setHost(device.getIp()); - sipURI.setPort(device.getPort()); - sipURI.setUser(streamInfo.getChannelId()); + public Request createAckRequest(SipURI sipURI, SIPResponse sipResponse) throws ParseException, InvalidArgumentException, PeerUnavailableException { - ViaHeader viaHeader = (ViaHeader) infoRequest.getHeader(ViaHeader.NAME); - viaHeader.setRPort(); - // 增加Contact header - Address concatAddress = sipFactory.createAddressFactory().createAddress(sipFactory.createAddressFactory() - .createSipURI(sipConfig.getId(), sipConfig.getIp() + ":" + sipConfig.getPort())); - infoRequest.addHeader(sipFactory.createHeaderFactory().createContactHeader(concatAddress)); - infoRequest.addHeader(SipUtils.createUserAgentHeader(sipFactory, gitUtil)); + // via + ArrayList viaHeaders = new ArrayList(); + ViaHeader viaHeader = sipFactory.createHeaderFactory().createViaHeader(sipConfig.getIp(), sipConfig.getPort(), sipResponse.getTopmostViaHeader().getTransport(), SipUtils.getNewViaTag()); + viaHeaders.add(viaHeader); - ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader("Application", - "MANSRTSP"); - infoRequest.setContent(content, contentTypeHeader); + //Forwards + MaxForwardsHeader maxForwards = sipFactory.createHeaderFactory().createMaxForwardsHeader(70); - CSeqHeader cSeqHeader = (CSeqHeader)infoRequest.getHeader(CSeqHeader.NAME); - cSeqHeader.setSeqNumber(redisCatchStorage.getCSEQ()); - // ceq - infoRequest.addHeader(cSeqHeader); - return infoRequest; + //ceq + CSeqHeader cSeqHeader = sipFactory.createHeaderFactory().createCSeqHeader(sipResponse.getCSeqHeader().getSeqNumber(), Request.ACK); + + Request request = sipFactory.createMessageFactory().createRequest(sipURI, Request.ACK, sipResponse.getCallIdHeader(), cSeqHeader, sipResponse.getFromHeader(), sipResponse.getToHeader(), viaHeaders, maxForwards); + + request.addHeader(SipUtils.createUserAgentHeader(sipFactory, gitUtil)); + + Address concatAddress = sipFactory.createAddressFactory().createAddress(sipFactory.createAddressFactory().createSipURI(sipConfig.getId(), sipConfig.getIp()+":"+sipConfig.getPort())); + request.addHeader(sipFactory.createHeaderFactory().createContactHeader(concatAddress)); + + request.addHeader(SipUtils.createUserAgentHeader(sipFactory, gitUtil)); + + return request; } } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java index d08201f8..14c01164 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java @@ -5,6 +5,7 @@ import com.genersoft.iot.vmp.common.StreamInfo; import com.genersoft.iot.vmp.conf.DynamicTask; import com.genersoft.iot.vmp.conf.SipConfig; import com.genersoft.iot.vmp.conf.UserSetting; +import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException; import com.genersoft.iot.vmp.gb28181.bean.*; import com.genersoft.iot.vmp.gb28181.event.SipSubscribe; import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager; @@ -22,17 +23,20 @@ import com.genersoft.iot.vmp.service.bean.SSRCInfo; import com.genersoft.iot.vmp.storager.IRedisCatchStorage; import com.genersoft.iot.vmp.storager.IVideoManagerStorage; import com.genersoft.iot.vmp.utils.GitUtil; +import gov.nist.javax.sip.SIPConstants; import gov.nist.javax.sip.SipProviderImpl; import gov.nist.javax.sip.SipStackImpl; -import gov.nist.javax.sip.message.MessageFactoryImpl; import gov.nist.javax.sip.message.SIPRequest; +import gov.nist.javax.sip.message.SIPResponse; import gov.nist.javax.sip.stack.SIPClientTransaction; +import gov.nist.javax.sip.stack.SIPClientTransactionImpl; import gov.nist.javax.sip.stack.SIPDialog; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.DependsOn; +import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Component; import org.springframework.util.ObjectUtils; @@ -41,1791 +45,1444 @@ import javax.sip.address.Address; import javax.sip.address.SipURI; import javax.sip.header.*; import javax.sip.message.Request; +import javax.sip.message.Response; import java.lang.reflect.Field; import java.text.ParseException; import java.util.HashSet; -/** - * @description:设备能力接口,用于定义设备的控制、查询能力 +/** + * @description:设备能力接口,用于定义设备的控制、查询能力 * @author: swwheihei - * @date: 2020年5月3日 下午9:22:48 + * @date: 2020年5月3日 下午9:22:48 */ @Component @DependsOn("sipLayer") public class SIPCommander implements ISIPCommander { - private final Logger logger = LoggerFactory.getLogger(SIPCommander.class); + private final Logger logger = LoggerFactory.getLogger(SIPCommander.class); - @Autowired - private SipConfig sipConfig; + @Autowired + private SipConfig sipConfig; - @Autowired - private SipFactory sipFactory; + @Autowired + private SipFactory sipFactory; - @Autowired - private GitUtil gitUtil; + @Autowired + private GitUtil gitUtil; - @Autowired - @Qualifier(value="tcpSipProvider") - private SipProviderImpl tcpSipProvider; + @Autowired + @Qualifier(value = "tcpSipProvider") + private SipProviderImpl tcpSipProvider; - @Autowired - @Qualifier(value="udpSipProvider") - private SipProviderImpl udpSipProvider; + @Autowired + @Qualifier(value = "udpSipProvider") + private SipProviderImpl udpSipProvider; - @Autowired - private SIPRequestHeaderProvider headerProvider; - - @Autowired - private VideoStreamSessionManager streamSession; + @Autowired + private SIPRequestHeaderProvider headerProvider; - @Autowired - private IVideoManagerStorage storager; + @Autowired + private VideoStreamSessionManager streamSession; - @Autowired - private IRedisCatchStorage redisCatchStorage; + @Autowired + private UserSetting userSetting; - @Autowired - private UserSetting userSetting; + @Autowired + private ZlmHttpHookSubscribe subscribe; - @Autowired - private ZlmHttpHookSubscribe subscribe; + @Autowired + private SipSubscribe sipSubscribe; - @Autowired - private SipSubscribe sipSubscribe; - - @Autowired - private IMediaServerService mediaServerService; - - @Autowired - private DynamicTask dynamicTask; + @Autowired + private IMediaServerService mediaServerService; - /** - * 云台方向放控制,使用配置文件中的默认镜头移动速度 - * - * @param device 控制设备 - * @param channelId 预览通道 - * @param leftRight 镜头左移右移 0:停止 1:左移 2:右移 - * @param upDown 镜头上移下移 0:停止 1:上移 2:下移 - */ - @Override - public boolean ptzdirectCmd(Device device, String channelId, int leftRight, int upDown) { - return ptzCmd(device, channelId, leftRight, upDown, 0, sipConfig.getPtzSpeed(), 0); - } + /** + * 云台方向放控制,使用配置文件中的默认镜头移动速度 + * + * @param device 控制设备 + * @param channelId 预览通道 + * @param leftRight 镜头左移右移 0:停止 1:左移 2:右移 + * @param upDown 镜头上移下移 0:停止 1:上移 2:下移 + */ + @Override + public void ptzdirectCmd(Device device, String channelId, int leftRight, int upDown) throws InvalidArgumentException, ParseException, SipException { + ptzCmd(device, channelId, leftRight, upDown, 0, sipConfig.getPtzSpeed(), 0); + } - /** - * 云台方向放控制 - * - * @param device 控制设备 - * @param channelId 预览通道 - * @param leftRight 镜头左移右移 0:停止 1:左移 2:右移 - * @param upDown 镜头上移下移 0:停止 1:上移 2:下移 - * @param moveSpeed 镜头移动速度 - */ - @Override - public boolean ptzdirectCmd(Device device, String channelId, int leftRight, int upDown, int moveSpeed) { - return ptzCmd(device, channelId, leftRight, upDown, 0, moveSpeed, 0); - } + /** + * 云台方向放控制 + * + * @param device 控制设备 + * @param channelId 预览通道 + * @param leftRight 镜头左移右移 0:停止 1:左移 2:右移 + * @param upDown 镜头上移下移 0:停止 1:上移 2:下移 + * @param moveSpeed 镜头移动速度 + */ + @Override + public void ptzdirectCmd(Device device, String channelId, int leftRight, int upDown, int moveSpeed) throws InvalidArgumentException, ParseException, SipException { + ptzCmd(device, channelId, leftRight, upDown, 0, moveSpeed, 0); + } - /** - * 云台缩放控制,使用配置文件中的默认镜头缩放速度 - * - * @param device 控制设备 - * @param channelId 预览通道 - * @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大 - */ - @Override - public boolean ptzZoomCmd(Device device, String channelId, int inOut) { - return ptzCmd(device, channelId, 0, 0, inOut, 0, sipConfig.getPtzSpeed()); - } + /** + * 云台缩放控制,使用配置文件中的默认镜头缩放速度 + * + * @param device 控制设备 + * @param channelId 预览通道 + * @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大 + */ + @Override + public void ptzZoomCmd(Device device, String channelId, int inOut) throws InvalidArgumentException, ParseException, SipException { + ptzCmd(device, channelId, 0, 0, inOut, 0, sipConfig.getPtzSpeed()); + } - /** - * 云台缩放控制 - * - * @param device 控制设备 - * @param channelId 预览通道 - * @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大 - * @param zoomSpeed 镜头缩放速度 - */ - @Override - public boolean ptzZoomCmd(Device device, String channelId, int inOut, int zoomSpeed) { - return ptzCmd(device, channelId, 0, 0, inOut, 0, zoomSpeed); - } - - /** - * 云台指令码计算 - * - * @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); - 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(); -} + /** + * 云台缩放控制 + * + * @param device 控制设备 + * @param channelId 预览通道 + * @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大 + * @param zoomSpeed 镜头缩放速度 + */ + @Override + public void ptzZoomCmd(Device device, String channelId, int inOut, int zoomSpeed) throws InvalidArgumentException, ParseException, SipException { + ptzCmd(device, channelId, 0, 0, inOut, 0, zoomSpeed); + } - /** - * 云台指令码计算 - * - * @param cmdCode 指令码 - * @param parameter1 数据1 - * @param parameter2 数据2 - * @param combineCode2 组合码2 - */ + /** + * 云台指令码计算 + * + * @param cmdCode 指令码 + * @param parameter1 数据1 + * @param parameter2 数据2 + * @param combineCode2 组合码2 + */ public static String frontEndCmdString(int cmdCode, int parameter1, int parameter2, int combineCode2) { - StringBuilder builder = new StringBuilder("A50F01"); - String strTmp; - strTmp = String.format("%02X", cmdCode); - builder.append(strTmp, 0, 2); - strTmp = String.format("%02X", parameter1); - builder.append(strTmp, 0, 2); - strTmp = String.format("%02X", parameter2); - builder.append(strTmp, 0, 2); - strTmp = String.format("%X", combineCode2); - builder.append(strTmp, 0, 1).append("0"); - //计算校验码 - int checkCode = (0XA5 + 0X0F + 0X01 + cmdCode + parameter1 + parameter2 + (combineCode2 & 0XF0)) % 0X100; - strTmp = String.format("%02X", checkCode); - builder.append(strTmp, 0, 2); - return builder.toString(); - } + StringBuilder builder = new StringBuilder("A50F01"); + String strTmp; + strTmp = String.format("%02X", cmdCode); + builder.append(strTmp, 0, 2); + strTmp = String.format("%02X", parameter1); + builder.append(strTmp, 0, 2); + strTmp = String.format("%02X", parameter2); + builder.append(strTmp, 0, 2); + strTmp = String.format("%X", combineCode2); + builder.append(strTmp, 0, 1).append("0"); + //计算校验码 + int checkCode = (0XA5 + 0X0F + 0X01 + cmdCode + parameter1 + parameter2 + (combineCode2 & 0XF0)) % 0X100; + strTmp = String.format("%02X", checkCode); + builder.append(strTmp, 0, 2); + return builder.toString(); + } - /** - * 云台控制,支持方向与缩放控制 - * - * @param device 控制设备 - * @param channelId 预览通道 - * @param leftRight 镜头左移右移 0:停止 1:左移 2:右移 - * @param upDown 镜头上移下移 0:停止 1:上移 2:下移 - * @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大 - * @param moveSpeed 镜头移动速度 - * @param zoomSpeed 镜头缩放速度 - */ - @Override - public boolean ptzCmd(Device device, String channelId, int leftRight, int upDown, int inOut, int moveSpeed, - int zoomSpeed) { - try { - String cmdStr= cmdString(leftRight, upDown, inOut, moveSpeed, zoomSpeed); - StringBuffer ptzXml = new StringBuffer(200); - String charset = device.getCharset(); - ptzXml.append("\r\n"); - ptzXml.append("\r\n"); - ptzXml.append("DeviceControl\r\n"); - ptzXml.append("" + (int)((Math.random()*9+1)*100000) + "\r\n"); - ptzXml.append("" + channelId + "\r\n"); - ptzXml.append("" + cmdStr + "\r\n"); - ptzXml.append("\r\n"); - ptzXml.append("5\r\n"); - ptzXml.append("\r\n"); - ptzXml.append("\r\n"); + /** + * 云台控制,支持方向与缩放控制 + * + * @param device 控制设备 + * @param channelId 预览通道 + * @param leftRight 镜头左移右移 0:停止 1:左移 2:右移 + * @param upDown 镜头上移下移 0:停止 1:上移 2:下移 + * @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大 + * @param moveSpeed 镜头移动速度 + * @param zoomSpeed 镜头缩放速度 + */ + @Override + public void ptzCmd(Device device, String channelId, int leftRight, int upDown, int inOut, int moveSpeed, + int zoomSpeed) throws InvalidArgumentException, SipException, ParseException { + String cmdStr = SipUtils.cmdString(leftRight, upDown, inOut, moveSpeed, zoomSpeed); + StringBuffer ptzXml = new StringBuffer(200); + String charset = device.getCharset(); + ptzXml.append("\r\n"); + ptzXml.append("\r\n"); + ptzXml.append("DeviceControl\r\n"); + ptzXml.append("" + (int) ((Math.random() * 9 + 1) * 100000) + "\r\n"); + ptzXml.append("" + channelId + "\r\n"); + ptzXml.append("" + cmdStr + "\r\n"); + ptzXml.append("\r\n"); + ptzXml.append("5\r\n"); + ptzXml.append("\r\n"); + ptzXml.append("\r\n"); - CallIdHeader callIdHeader = device.getTransport().equalsIgnoreCase("TCP") ? tcpSipProvider.getNewCallId() - : udpSipProvider.getNewCallId(); + CallIdHeader callIdHeader = device.getTransport().equalsIgnoreCase("TCP") ? tcpSipProvider.getNewCallId() + : udpSipProvider.getNewCallId(); - Request request = headerProvider.createMessageRequest(device, ptzXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null, callIdHeader); - - transmitRequest(device, request); - return true; - } catch (SipException | ParseException | InvalidArgumentException e) { - e.printStackTrace(); - } - return false; - } + Request request = headerProvider.createMessageRequest(device, ptzXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null, callIdHeader); - /** - * 前端控制,包括PTZ指令、FI指令、预置位指令、巡航指令、扫描指令和辅助开关指令 - * - * @param device 控制设备 - * @param channelId 预览通道 - * @param cmdCode 指令码 - * @param parameter1 数据1 - * @param parameter2 数据2 - * @param combineCode2 组合码2 - */ - @Override - public boolean frontEndCmd(Device device, String channelId, int cmdCode, int parameter1, int parameter2, int combineCode2) { - try { - String cmdStr= frontEndCmdString(cmdCode, parameter1, parameter2, combineCode2); - logger.debug("控制字符串:" + cmdStr); - StringBuffer ptzXml = new StringBuffer(200); - String charset = device.getCharset(); - ptzXml.append("\r\n"); - ptzXml.append("\r\n"); - ptzXml.append("DeviceControl\r\n"); - ptzXml.append("" + (int)((Math.random()*9+1)*100000) + "\r\n"); - ptzXml.append("" + channelId + "\r\n"); - ptzXml.append("" + cmdStr + "\r\n"); - ptzXml.append("\r\n"); - ptzXml.append("5\r\n"); - ptzXml.append("\r\n"); - ptzXml.append("\r\n"); - + transmitRequest(device.getTransport(), request); + } - CallIdHeader callIdHeader = device.getTransport().equalsIgnoreCase("TCP") ? tcpSipProvider.getNewCallId() - : udpSipProvider.getNewCallId(); + /** + * 前端控制,包括PTZ指令、FI指令、预置位指令、巡航指令、扫描指令和辅助开关指令 + * + * @param device 控制设备 + * @param channelId 预览通道 + * @param cmdCode 指令码 + * @param parameter1 数据1 + * @param parameter2 数据2 + * @param combineCode2 组合码2 + */ + @Override + public void frontEndCmd(Device device, String channelId, int cmdCode, int parameter1, int parameter2, int combineCode2) throws SipException, InvalidArgumentException, ParseException { - Request request = headerProvider.createMessageRequest(device, ptzXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null, callIdHeader); - transmitRequest(device, request); - return true; - } catch (SipException | ParseException | InvalidArgumentException e) { - e.printStackTrace(); - } - return false; - } + String cmdStr = frontEndCmdString(cmdCode, parameter1, parameter2, combineCode2); + StringBuffer ptzXml = new StringBuffer(200); + String charset = device.getCharset(); + ptzXml.append("\r\n"); + ptzXml.append("\r\n"); + ptzXml.append("DeviceControl\r\n"); + ptzXml.append("" + (int) ((Math.random() * 9 + 1) * 100000) + "\r\n"); + ptzXml.append("" + channelId + "\r\n"); + ptzXml.append("" + cmdStr + "\r\n"); + ptzXml.append("\r\n"); + ptzXml.append("5\r\n"); + ptzXml.append("\r\n"); + ptzXml.append("\r\n"); - /** - * 前端控制指令(用于转发上级指令) - * @param device 控制设备 - * @param channelId 预览通道 - * @param cmdString 前端控制指令串 - */ - @Override - public boolean fronEndCmd(Device device, String channelId, String cmdString, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) { - try { - StringBuffer ptzXml = new StringBuffer(200); - String charset = device.getCharset(); - ptzXml.append("\r\n"); - ptzXml.append("\r\n"); - ptzXml.append("DeviceControl\r\n"); - ptzXml.append("" + (int)((Math.random()*9+1)*100000) + "\r\n"); - ptzXml.append("" + channelId + "\r\n"); - ptzXml.append("" + cmdString + "\r\n"); - ptzXml.append("\r\n"); - ptzXml.append("5\r\n"); - ptzXml.append("\r\n"); - ptzXml.append("\r\n"); - - CallIdHeader callIdHeader = device.getTransport().equalsIgnoreCase("TCP") ? tcpSipProvider.getNewCallId() - : udpSipProvider.getNewCallId(); + CallIdHeader callIdHeader = device.getTransport().equalsIgnoreCase("TCP") ? tcpSipProvider.getNewCallId() + : udpSipProvider.getNewCallId(); - Request request = headerProvider.createMessageRequest(device, ptzXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null, callIdHeader); - transmitRequest(device, request, errorEvent, okEvent); - return true; - } catch (SipException | ParseException | InvalidArgumentException e) { - e.printStackTrace(); - } - return false; - } - - /** - * 请求预览视频流 - * @param device 视频设备 - * @param channelId 预览通道 - * @param event hook订阅 - * @param errorEvent sip错误订阅 - */ - @Override - public void playStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, - ZlmHttpHookSubscribe.Event event, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) { - String stream = ssrcInfo.getStream(); - try { - if (device == null) { - return; - } -// String streamMode = device.getStreamMode().toUpperCase(); + SIPRequest request = (SIPRequest) headerProvider.createMessageRequest(device, ptzXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null, callIdHeader); + transmitRequest(device.getTransport(), request); - logger.info("{} 分配的ZLM为: {} [{}:{}]", stream, mediaServerItem.getId(), mediaServerItem.getIp(), ssrcInfo.getPort()); - HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", stream, true, "rtsp", mediaServerItem.getId()); - subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, JSONObject json)->{ - if (event != null) { - event.response(mediaServerItemInUse, json); - subscribe.removeSubscribe(hookSubscribe); - } - }); - // - StringBuffer content = new StringBuffer(200); - content.append("v=0\r\n"); - content.append("o="+ channelId+" 0 0 IN IP4 "+ mediaServerItem.getSdpIp() +"\r\n"); - content.append("s=Play\r\n"); - content.append("c=IN IP4 "+ mediaServerItem.getSdpIp() +"\r\n"); - content.append("t=0 0\r\n"); + } - if (userSetting.isSeniorSdp()) { - if("TCP-PASSIVE".equalsIgnoreCase(device.getStreamMode())) { - content.append("m=video "+ ssrcInfo.getPort() +" TCP/RTP/AVP 96 126 125 99 34 98 97\r\n"); - }else if ("TCP-ACTIVE".equalsIgnoreCase(device.getStreamMode())) { - content.append("m=video "+ ssrcInfo.getPort() +" TCP/RTP/AVP 96 126 125 99 34 98 97\r\n"); - }else if("UDP".equalsIgnoreCase(device.getStreamMode())) { - content.append("m=video "+ ssrcInfo.getPort() +" RTP/AVP 96 126 125 99 34 98 97\r\n"); - } - content.append("a=recvonly\r\n"); - content.append("a=rtpmap:96 PS/90000\r\n"); - content.append("a=fmtp:126 profile-level-id=42e01e\r\n"); - content.append("a=rtpmap:126 H264/90000\r\n"); - content.append("a=rtpmap:125 H264S/90000\r\n"); - content.append("a=fmtp:125 profile-level-id=42e01e\r\n"); - content.append("a=rtpmap:99 H265/90000\r\n"); - content.append("a=rtpmap:98 H264/90000\r\n"); - content.append("a=rtpmap:97 MPEG4/90000\r\n"); - if("TCP-PASSIVE".equalsIgnoreCase(device.getStreamMode())){ // tcp被动模式 - content.append("a=setup:passive\r\n"); - content.append("a=connection:new\r\n"); - }else if ("TCP-ACTIVE".equalsIgnoreCase(device.getStreamMode())) { // tcp主动模式 - content.append("a=setup:active\r\n"); - content.append("a=connection:new\r\n"); - } - }else { - if("TCP-PASSIVE".equalsIgnoreCase(device.getStreamMode())) { - content.append("m=video "+ ssrcInfo.getPort() +" TCP/RTP/AVP 96 97 98 99\r\n"); - }else if ("TCP-ACTIVE".equalsIgnoreCase(device.getStreamMode())) { - content.append("m=video "+ ssrcInfo.getPort() +" TCP/RTP/AVP 96 97 98 99\r\n"); - }else if("UDP".equalsIgnoreCase(device.getStreamMode())) { - content.append("m=video "+ ssrcInfo.getPort() +" RTP/AVP 96 97 98 99\r\n"); - } - content.append("a=recvonly\r\n"); - content.append("a=rtpmap:96 PS/90000\r\n"); - content.append("a=rtpmap:98 H264/90000\r\n"); - content.append("a=rtpmap:97 MPEG4/90000\r\n"); - content.append("a=rtpmap:99 H265/90000\r\n"); - if ("TCP-PASSIVE".equalsIgnoreCase(device.getStreamMode())) { // tcp被动模式 - content.append("a=setup:passive\r\n"); - content.append("a=connection:new\r\n"); - } else if ("TCP-ACTIVE".equalsIgnoreCase(device.getStreamMode())) { // tcp主动模式 - content.append("a=setup:active\r\n"); - content.append("a=connection:new\r\n"); - } - } + /** + * 前端控制指令(用于转发上级指令) + * + * @param device 控制设备 + * @param channelId 预览通道 + * @param cmdString 前端控制指令串 + */ + @Override + public void fronEndCmd(Device device, String channelId, String cmdString, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException { - content.append("y="+ssrcInfo.getSsrc()+"\r\n");//ssrc - // f字段:f= v/编码格式/分辨率/帧率/码率类型/码率大小a/编码格式/码率大小/采样率 + StringBuffer ptzXml = new StringBuffer(200); + String charset = device.getCharset(); + ptzXml.append("\r\n"); + ptzXml.append("\r\n"); + ptzXml.append("DeviceControl\r\n"); + ptzXml.append("" + (int) ((Math.random() * 9 + 1) * 100000) + "\r\n"); + ptzXml.append("" + channelId + "\r\n"); + ptzXml.append("" + cmdString + "\r\n"); + ptzXml.append("\r\n"); + ptzXml.append("5\r\n"); + ptzXml.append("\r\n"); + ptzXml.append("\r\n"); + + + CallIdHeader callIdHeader = device.getTransport().equalsIgnoreCase("TCP") ? tcpSipProvider.getNewCallId() + : udpSipProvider.getNewCallId(); + + Request request = headerProvider.createMessageRequest(device, ptzXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null, callIdHeader); + transmitRequest(device.getTransport(), request, errorEvent, okEvent); + + } + + /** + * 请求预览视频流 + * + * @param device 视频设备 + * @param channelId 预览通道 + * @param event hook订阅 + * @param errorEvent sip错误订阅 + */ + @Override + public void playStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, + ZlmHttpHookSubscribe.Event event, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException { + String stream = ssrcInfo.getStream(); + + if (device == null) { + return; + } + + logger.info("{} 分配的ZLM为: {} [{}:{}]", stream, mediaServerItem.getId(), mediaServerItem.getIp(), ssrcInfo.getPort()); + HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", stream, true, "rtsp", mediaServerItem.getId()); + subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, JSONObject json) -> { + if (event != null) { + event.response(mediaServerItemInUse, json); + subscribe.removeSubscribe(hookSubscribe); + } + }); + // + StringBuffer content = new StringBuffer(200); + content.append("v=0\r\n"); + content.append("o=" + channelId + " 0 0 IN IP4 " + mediaServerItem.getSdpIp() + "\r\n"); + content.append("s=Play\r\n"); + content.append("c=IN IP4 " + mediaServerItem.getSdpIp() + "\r\n"); + content.append("t=0 0\r\n"); + + if (userSetting.isSeniorSdp()) { + if ("TCP-PASSIVE".equalsIgnoreCase(device.getStreamMode())) { + content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 126 125 99 34 98 97\r\n"); + } else if ("TCP-ACTIVE".equalsIgnoreCase(device.getStreamMode())) { + content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 126 125 99 34 98 97\r\n"); + } else if ("UDP".equalsIgnoreCase(device.getStreamMode())) { + content.append("m=video " + ssrcInfo.getPort() + " RTP/AVP 96 126 125 99 34 98 97\r\n"); + } + content.append("a=recvonly\r\n"); + content.append("a=rtpmap:96 PS/90000\r\n"); + content.append("a=fmtp:126 profile-level-id=42e01e\r\n"); + content.append("a=rtpmap:126 H264/90000\r\n"); + content.append("a=rtpmap:125 H264S/90000\r\n"); + content.append("a=fmtp:125 profile-level-id=42e01e\r\n"); + content.append("a=rtpmap:99 H265/90000\r\n"); + content.append("a=rtpmap:98 H264/90000\r\n"); + content.append("a=rtpmap:97 MPEG4/90000\r\n"); + if ("TCP-PASSIVE".equalsIgnoreCase(device.getStreamMode())) { // tcp被动模式 + content.append("a=setup:passive\r\n"); + content.append("a=connection:new\r\n"); + } else if ("TCP-ACTIVE".equalsIgnoreCase(device.getStreamMode())) { // tcp主动模式 + content.append("a=setup:active\r\n"); + content.append("a=connection:new\r\n"); + } + } else { + if ("TCP-PASSIVE".equalsIgnoreCase(device.getStreamMode())) { + content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 97 98 99\r\n"); + } else if ("TCP-ACTIVE".equalsIgnoreCase(device.getStreamMode())) { + content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 97 98 99\r\n"); + } else if ("UDP".equalsIgnoreCase(device.getStreamMode())) { + content.append("m=video " + ssrcInfo.getPort() + " RTP/AVP 96 97 98 99\r\n"); + } + content.append("a=recvonly\r\n"); + content.append("a=rtpmap:96 PS/90000\r\n"); + content.append("a=rtpmap:98 H264/90000\r\n"); + content.append("a=rtpmap:97 MPEG4/90000\r\n"); + content.append("a=rtpmap:99 H265/90000\r\n"); + if ("TCP-PASSIVE".equalsIgnoreCase(device.getStreamMode())) { // tcp被动模式 + content.append("a=setup:passive\r\n"); + content.append("a=connection:new\r\n"); + } else if ("TCP-ACTIVE".equalsIgnoreCase(device.getStreamMode())) { // tcp主动模式 + content.append("a=setup:active\r\n"); + content.append("a=connection:new\r\n"); + } + } + + content.append("y=" + ssrcInfo.getSsrc() + "\r\n");//ssrc + // f字段:f= v/编码格式/分辨率/帧率/码率类型/码率大小a/编码格式/码率大小/采样率 // content.append("f=v/2/5/25/1/4000a/1/8/1" + "\r\n"); // 未发现支持此特性的设备 - CallIdHeader callIdHeader = device.getTransport().equalsIgnoreCase("TCP") ? tcpSipProvider.getNewCallId() - : udpSipProvider.getNewCallId(); - - Request request = headerProvider.createInviteRequest(device, channelId, content.toString(), null, SipUtils.getNewFromTag(), null, ssrcInfo.getSsrc(), callIdHeader); - - transmitRequest(device, request, (e -> { - streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream()); - mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc()); - errorEvent.response(e); - }), e ->{ - // 这里为例避免一个通道的点播只有一个callID这个参数使用一个固定值 - streamSession.put(device.getDeviceId(), channelId ,"play", stream, ssrcInfo.getSsrc(), mediaServerItem.getId(), ((ResponseEvent)e.event).getClientTransaction(), VideoStreamSessionManager.SessionType.play); - Dialog sipDialog = null; - if (e.dialog == null) { - SIPClientTransaction clientTransaction = (SIPClientTransaction)((ResponseEvent)e.event).getClientTransaction(); - sipDialog = new SIPDialog(clientTransaction, clientTransaction.getLastResponse()); - }else { - sipDialog = e.dialog; - } - streamSession.put(device.getDeviceId(), channelId ,"play", sipDialog); - okEvent.response(e); - }); - - - } catch ( SipException | ParseException | InvalidArgumentException e) { - e.printStackTrace(); - } - } - - /** - * 请求回放视频流 - * - * @param device 视频设备 - * @param channelId 预览通道 - * @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss - * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss - */ - @Override - public void playbackStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, - String startTime, String endTime, InviteStreamCallback inviteStreamCallback, InviteStreamCallback hookEvent, - SipSubscribe.Event okEvent,SipSubscribe.Event errorEvent) { - try { - - logger.info("{} 分配的ZLM为: {} [{}:{}]", ssrcInfo.getStream(), mediaServerItem.getId(), mediaServerItem.getIp(), ssrcInfo.getPort()); - - StringBuffer content = new StringBuffer(200); - content.append("v=0\r\n"); - content.append("o="+channelId+" 0 0 IN IP4 " + mediaServerItem.getSdpIp() + "\r\n"); - content.append("s=Playback\r\n"); - content.append("u="+channelId+":0\r\n"); - content.append("c=IN IP4 "+mediaServerItem.getSdpIp()+"\r\n"); - content.append("t="+DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(startTime)+" " - +DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(endTime) +"\r\n"); - - String streamMode = device.getStreamMode(); - - if (userSetting.isSeniorSdp()) { - if("TCP-PASSIVE".equalsIgnoreCase(streamMode)) { - content.append("m=video "+ ssrcInfo.getPort() +" TCP/RTP/AVP 96 126 125 99 34 98 97\r\n"); - }else if ("TCP-ACTIVE".equalsIgnoreCase(streamMode)) { - content.append("m=video "+ ssrcInfo.getPort() +" TCP/RTP/AVP 96 126 125 99 34 98 97\r\n"); - }else if("UDP".equalsIgnoreCase(streamMode)) { - content.append("m=video "+ ssrcInfo.getPort() +" RTP/AVP 96 126 125 99 34 98 97\r\n"); - } - content.append("a=recvonly\r\n"); - content.append("a=rtpmap:96 PS/90000\r\n"); - content.append("a=fmtp:126 profile-level-id=42e01e\r\n"); - content.append("a=rtpmap:126 H264/90000\r\n"); - content.append("a=rtpmap:125 H264S/90000\r\n"); - content.append("a=fmtp:125 profile-level-id=42e01e\r\n"); - content.append("a=rtpmap:99 H265/90000\r\n"); - content.append("a=rtpmap:98 H264/90000\r\n"); - content.append("a=rtpmap:97 MPEG4/90000\r\n"); - if("TCP-PASSIVE".equalsIgnoreCase(streamMode)){ // tcp被动模式 - content.append("a=setup:passive\r\n"); - content.append("a=connection:new\r\n"); - }else if ("TCP-ACTIVE".equalsIgnoreCase(streamMode)) { // tcp主动模式 - content.append("a=setup:active\r\n"); - content.append("a=connection:new\r\n"); - } - }else { - if("TCP-PASSIVE".equalsIgnoreCase(streamMode)) { - content.append("m=video "+ ssrcInfo.getPort() +" TCP/RTP/AVP 96 97 98 99\r\n"); - }else if ("TCP-ACTIVE".equalsIgnoreCase(streamMode)) { - content.append("m=video "+ ssrcInfo.getPort() +" TCP/RTP/AVP 96 97 98 99\r\n"); - }else if("UDP".equalsIgnoreCase(streamMode)) { - content.append("m=video "+ ssrcInfo.getPort() +" RTP/AVP 96 97 98 99\r\n"); - } - content.append("a=recvonly\r\n"); - content.append("a=rtpmap:96 PS/90000\r\n"); - content.append("a=rtpmap:97 MPEG4/90000\r\n"); - content.append("a=rtpmap:98 H264/90000\r\n"); - content.append("a=rtpmap:99 H265/90000\r\n"); - if("TCP-PASSIVE".equalsIgnoreCase(streamMode)){ // tcp被动模式 - content.append("a=setup:passive\r\n"); - content.append("a=connection:new\r\n"); - }else if ("TCP-ACTIVE".equalsIgnoreCase(streamMode)) { // tcp主动模式 - content.append("a=setup:active\r\n"); - content.append("a=connection:new\r\n"); - } - } - - content.append("y=" + ssrcInfo.getSsrc() + "\r\n");//ssrc - - CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId() - : udpSipProvider.getNewCallId(); - HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", ssrcInfo.getStream(), true, "rtsp", mediaServerItem.getId()); - // 添加订阅 - subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, JSONObject json)->{ - if (hookEvent != null) { - InviteStreamInfo inviteStreamInfo = new InviteStreamInfo(mediaServerItemInUse, json, callIdHeader.getCallId(), "rtp", ssrcInfo.getStream()); - hookEvent.call(inviteStreamInfo); - } - subscribe.removeSubscribe(hookSubscribe); - }); - Request request = headerProvider.createPlaybackInviteRequest(device, channelId, content.toString(), null, SipUtils.getNewFromTag(), null, callIdHeader, ssrcInfo.getSsrc()); - - transmitRequest(device, request, errorEvent, event -> { - ResponseEvent responseEvent = (ResponseEvent) event.event; - streamSession.put(device.getDeviceId(), channelId, callIdHeader.getCallId(), ssrcInfo.getStream(), ssrcInfo.getSsrc(), mediaServerItem.getId(), responseEvent.getClientTransaction(), VideoStreamSessionManager.SessionType.playback); - streamSession.put(device.getDeviceId(), channelId, callIdHeader.getCallId(), event.dialog); - okEvent.response(event); - }); - if (inviteStreamCallback != null) { - inviteStreamCallback.call(new InviteStreamInfo(mediaServerItem, null, callIdHeader.getCallId(), "rtp", ssrcInfo.getStream())); - } - } catch ( SipException | ParseException | InvalidArgumentException e) { - e.printStackTrace(); - } - } - - /** - * 请求历史媒体下载 - * - * @param device 视频设备 - * @param channelId 预览通道 - * @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss - * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss - * @param downloadSpeed 下载倍速参数 - */ - @Override - public void downloadStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, - String startTime, String endTime, int downloadSpeed, InviteStreamCallback inviteStreamCallback, InviteStreamCallback hookEvent, - SipSubscribe.Event errorEvent) { - try { - logger.info("{} 分配的ZLM为: {} [{}:{}]", ssrcInfo.getStream(), mediaServerItem.getId(), mediaServerItem.getIp(), ssrcInfo.getPort()); - - StringBuffer content = new StringBuffer(200); - content.append("v=0\r\n"); - content.append("o="+channelId+" 0 0 IN IP4 " + mediaServerItem.getSdpIp() + "\r\n"); - content.append("s=Download\r\n"); - content.append("u="+channelId+":0\r\n"); - content.append("c=IN IP4 "+mediaServerItem.getSdpIp()+"\r\n"); - content.append("t="+DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(startTime)+" " - +DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(endTime) +"\r\n"); - - String streamMode = device.getStreamMode().toUpperCase(); - - if (userSetting.isSeniorSdp()) { - if("TCP-PASSIVE".equals(streamMode)) { - content.append("m=video "+ ssrcInfo.getPort() +" TCP/RTP/AVP 96 126 125 99 34 98 97\r\n"); - }else if ("TCP-ACTIVE".equals(streamMode)) { - content.append("m=video "+ ssrcInfo.getPort() +" TCP/RTP/AVP 96 126 125 99 34 98 97\r\n"); - }else if("UDP".equals(streamMode)) { - content.append("m=video "+ ssrcInfo.getPort() +" RTP/AVP 96 126 125 99 34 98 97\r\n"); - } - content.append("a=recvonly\r\n"); - content.append("a=rtpmap:96 PS/90000\r\n"); - content.append("a=fmtp:126 profile-level-id=42e01e\r\n"); - content.append("a=rtpmap:126 H264/90000\r\n"); - content.append("a=rtpmap:125 H264S/90000\r\n"); - content.append("a=fmtp:125 profile-level-id=42e01e\r\n"); - content.append("a=rtpmap:99 MP4V-ES/90000\r\n"); - content.append("a=fmtp:99 profile-level-id=3\r\n"); - content.append("a=rtpmap:98 H264/90000\r\n"); - content.append("a=rtpmap:97 MPEG4/90000\r\n"); - if("TCP-PASSIVE".equals(streamMode)){ // tcp被动模式 - content.append("a=setup:passive\r\n"); - content.append("a=connection:new\r\n"); - }else if ("TCP-ACTIVE".equals(streamMode)) { // tcp主动模式 - content.append("a=setup:active\r\n"); - content.append("a=connection:new\r\n"); - } - }else { - if("TCP-PASSIVE".equals(streamMode)) { - content.append("m=video "+ ssrcInfo.getPort() +" TCP/RTP/AVP 96 97 98 99\r\n"); - }else if ("TCP-ACTIVE".equals(streamMode)) { - content.append("m=video "+ ssrcInfo.getPort() +" TCP/RTP/AVP 96 97 98 99\r\n"); - }else if("UDP".equals(streamMode)) { - content.append("m=video "+ ssrcInfo.getPort() +" RTP/AVP 96 97 98 99\r\n"); - } - content.append("a=recvonly\r\n"); - content.append("a=rtpmap:96 PS/90000\r\n"); - content.append("a=rtpmap:97 MPEG4/90000\r\n"); - content.append("a=rtpmap:98 H264/90000\r\n"); - content.append("a=rtpmap:99 H265/90000\r\n"); - if("TCP-PASSIVE".equals(streamMode)){ // tcp被动模式 - content.append("a=setup:passive\r\n"); - content.append("a=connection:new\r\n"); - }else if ("TCP-ACTIVE".equals(streamMode)) { // tcp主动模式 - content.append("a=setup:active\r\n"); - content.append("a=connection:new\r\n"); - } - } - content.append("a=downloadspeed:" + downloadSpeed + "\r\n"); - - content.append("y=" + ssrcInfo.getSsrc() + "\r\n");//ssrc - - CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId() - : udpSipProvider.getNewCallId(); - - HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", ssrcInfo.getStream(), true, null, mediaServerItem.getId()); - // 添加订阅 - subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, JSONObject json)->{ - hookEvent.call(new InviteStreamInfo(mediaServerItem, json, callIdHeader.getCallId(), "rtp", ssrcInfo.getStream())); - subscribe.removeSubscribe(hookSubscribe); - hookSubscribe.getContent().put("regist", false); - hookSubscribe.getContent().put("schema", "rtsp"); - // 添加流注销的订阅,注销了后向设备发送bye - subscribe.addSubscribe(hookSubscribe, - (MediaServerItem mediaServerItemForEnd, JSONObject jsonForEnd)->{ - ClientTransaction transaction = streamSession.getTransaction(device.getDeviceId(), channelId, ssrcInfo.getStream(), callIdHeader.getCallId()); - if (transaction != null) { - logger.info("[录像]下载结束, 发送BYE"); - streamByeCmd(device.getDeviceId(), channelId, ssrcInfo.getStream(), callIdHeader.getCallId()); - } - }); - }); - - Request request = headerProvider.createPlaybackInviteRequest(device, channelId, content.toString(), null, SipUtils.getNewFromTag(), null, callIdHeader, ssrcInfo.getSsrc()); - if (inviteStreamCallback != null) { - inviteStreamCallback.call(new InviteStreamInfo(mediaServerItem, null, callIdHeader.getCallId(), "rtp", ssrcInfo.getStream())); - } - transmitRequest(device, request, errorEvent, okEvent->{ - ResponseEvent responseEvent = (ResponseEvent) okEvent.event; - streamSession.put(device.getDeviceId(), channelId, callIdHeader.getCallId(), ssrcInfo.getStream(), ssrcInfo.getSsrc(), mediaServerItem.getId(), responseEvent.getClientTransaction(), VideoStreamSessionManager.SessionType.download); - streamSession.put(device.getDeviceId(), channelId, callIdHeader.getCallId(), okEvent.dialog); - }); - - - } catch ( SipException | ParseException | InvalidArgumentException e) { - e.printStackTrace(); - } - } - - /** - * 视频流停止, 不使用回调 - */ - @Override - public void streamByeCmd(String deviceId, String channelId, String stream, String callId) { - streamByeCmd(deviceId, channelId, stream, callId, null); - } - - /** - * 视频流停止 - */ - @Override - public void streamByeCmd(String deviceId, String channelId, String stream, String callId, SipSubscribe.Event okEvent) { - try { - SsrcTransaction ssrcTransaction = streamSession.getSsrcTransaction(deviceId, channelId, callId, stream); - ClientTransaction transaction = streamSession.getTransaction(deviceId, channelId, stream, callId); - - if (transaction == null ) { - logger.warn("[ {} -> {}]停止视频流的时候发现事务已丢失", deviceId, channelId); - SipSubscribe.EventResult eventResult = new SipSubscribe.EventResult<>(); - if (okEvent != null) { - okEvent.response(eventResult); - } - return; - } - SIPDialog dialog; - if (callId != null) { - dialog = streamSession.getDialogByCallId(ssrcTransaction.getDeviceId(), ssrcTransaction.getChannelId(), callId); - }else { - if (stream == null && ssrcTransaction == null && ssrcTransaction.getStream() == null) { - return; - } - dialog = streamSession.getDialogByStream(ssrcTransaction.getDeviceId(), ssrcTransaction.getChannelId(), ssrcTransaction.getStream()); - } - mediaServerService.releaseSsrc(ssrcTransaction.getMediaServerId(), ssrcTransaction.getSsrc()); - mediaServerService.closeRTPServer(ssrcTransaction.getMediaServerId(), ssrcTransaction.getStream()); - streamSession.remove(ssrcTransaction.getDeviceId(), ssrcTransaction.getChannelId(), ssrcTransaction.getStream()); - - if (dialog == null) { - logger.warn("[ {} -> {}]停止视频流的时候发现对话已丢失", ssrcTransaction.getDeviceId(), ssrcTransaction.getChannelId()); - return; - } - SipStack sipStack = udpSipProvider.getSipStack(); - SIPDialog sipDialog = ((SipStackImpl) sipStack).putDialog(dialog); - if (dialog != sipDialog) { - dialog = sipDialog; - }else { - dialog.setSipProvider(udpSipProvider); - try { - Field sipStackField = SIPDialog.class.getDeclaredField("sipStack"); - sipStackField.setAccessible(true); - sipStackField.set(dialog, sipStack); - Field eventListenersField = SIPDialog.class.getDeclaredField("eventListeners"); - eventListenersField.setAccessible(true); - eventListenersField.set(dialog, new HashSet<>()); - } catch (NoSuchFieldException | IllegalAccessException e) { - e.printStackTrace(); - } - } - - Request byeRequest = dialog.createRequest(Request.BYE); - SipURI byeURI = (SipURI) byeRequest.getRequestURI(); - SIPRequest request = (SIPRequest)transaction.getRequest(); - byeURI.setHost(request.getRemoteAddress().getHostAddress()); - byeURI.setPort(request.getRemotePort()); - byeURI.setUser(channelId); - ViaHeader viaHeader = (ViaHeader) byeRequest.getHeader(ViaHeader.NAME); - String protocol = viaHeader.getTransport().toUpperCase(); - viaHeader.setRPort(); - // 增加Contact header - Address concatAddress = sipFactory.createAddressFactory().createAddress(sipFactory.createAddressFactory().createSipURI(sipConfig.getId(), sipConfig.getIp()+":"+sipConfig.getPort())); - byeRequest.addHeader(sipFactory.createHeaderFactory().createContactHeader(concatAddress)); - UserAgentHeader userAgentHeader = SipUtils.createUserAgentHeader(sipFactory, gitUtil); - byeRequest.addHeader(userAgentHeader); - ClientTransaction clientTransaction = null; - if("TCP".equals(protocol)) { - clientTransaction = tcpSipProvider.getNewClientTransaction(byeRequest); - } else if("UDP".equals(protocol)) { - clientTransaction = udpSipProvider.getNewClientTransaction(byeRequest); - } - - CallIdHeader callIdHeader = (CallIdHeader) byeRequest.getHeader(CallIdHeader.NAME); - if (okEvent != null) { - sipSubscribe.addOkSubscribe(callIdHeader.getCallId(), okEvent); - } - CSeqHeader cSeqHeader = (CSeqHeader)byeRequest.getHeader(CSeqHeader.NAME); - cSeqHeader.setSeqNumber(redisCatchStorage.getCSEQ()); - dialog.sendRequest(clientTransaction); - - } catch (SipException | ParseException e) { - e.printStackTrace(); - } catch (InvalidArgumentException e) { - throw new RuntimeException(e); - } - } - - /** - * 语音广播 - * - * @param device 视频设备 - * @param channelId 预览通道 - */ - @Override - public boolean audioBroadcastCmd(Device device, String channelId) { - // 改为新的实现 - return false; - } - - /** - * 语音广播 - * - * @param device 视频设备 - */ - @Override - public boolean audioBroadcastCmd(Device device) { - try { - StringBuffer broadcastXml = new StringBuffer(200); - String charset = device.getCharset(); - broadcastXml.append("\r\n"); - broadcastXml.append("\r\n"); - broadcastXml.append("Broadcast\r\n"); - broadcastXml.append("" + (int)((Math.random()*9+1)*100000) + "\r\n"); - broadcastXml.append("" + sipConfig.getId() + "\r\n"); - broadcastXml.append("" + device.getDeviceId() + "\r\n"); - broadcastXml.append("\r\n"); - - CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId() - : udpSipProvider.getNewCallId(); - - Request request = headerProvider.createMessageRequest(device, broadcastXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null, callIdHeader); - transmitRequest(device, request); - return true; - } catch (SipException | ParseException | InvalidArgumentException e) { - e.printStackTrace(); - } - return false; - } - @Override - public void audioBroadcastCmd(Device device, SipSubscribe.Event errorEvent) { - try { - StringBuffer broadcastXml = new StringBuffer(200); - String charset = device.getCharset(); - broadcastXml.append("\r\n"); - broadcastXml.append("\r\n"); - broadcastXml.append("Broadcast\r\n"); - broadcastXml.append("" + (int)((Math.random()*9+1)*100000) + "\r\n"); - broadcastXml.append("" + sipConfig.getId() + "\r\n"); - broadcastXml.append("" + device.getDeviceId() + "\r\n"); - broadcastXml.append("\r\n"); - - CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId() - : udpSipProvider.getNewCallId(); - - Request request = headerProvider.createMessageRequest(device, broadcastXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null, callIdHeader); - transmitRequest(device, request, errorEvent); - } catch (SipException | ParseException | InvalidArgumentException e) { - e.printStackTrace(); - } - } - - - /** - * 音视频录像控制 - * - * @param device 视频设备 - * @param channelId 预览通道 - * @param recordCmdStr 录像命令:Record / StopRecord - */ - @Override - public boolean recordCmd(Device device, String channelId, String recordCmdStr, SipSubscribe.Event errorEvent) { - try { - StringBuffer cmdXml = new StringBuffer(200); - String charset = device.getCharset(); - cmdXml.append("\r\n"); - cmdXml.append("\r\n"); - cmdXml.append("DeviceControl\r\n"); - cmdXml.append("" + (int)((Math.random()*9+1)*100000) + "\r\n"); - if (ObjectUtils.isEmpty(channelId)) { - cmdXml.append("" + device.getDeviceId() + "\r\n"); - } else { - cmdXml.append("" + channelId + "\r\n"); - } - cmdXml.append("" + recordCmdStr + "\r\n"); - cmdXml.append("\r\n"); - - CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId() - : udpSipProvider.getNewCallId(); - - Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null, callIdHeader); - transmitRequest(device, request, errorEvent); - return true; - } catch (SipException | ParseException | InvalidArgumentException e) { - e.printStackTrace(); - return false; - } - } - - /** - * 远程启动控制命令 - * - * @param device 视频设备 - */ - @Override - public boolean teleBootCmd(Device device) { - try { - StringBuffer cmdXml = new StringBuffer(200); - String charset = device.getCharset(); - cmdXml.append("\r\n"); - cmdXml.append("\r\n"); - cmdXml.append("DeviceControl\r\n"); - cmdXml.append("" + (int)((Math.random()*9+1)*100000) + "\r\n"); - cmdXml.append("" + device.getDeviceId() + "\r\n"); - cmdXml.append("Boot\r\n"); - cmdXml.append("\r\n"); - - CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId() - : udpSipProvider.getNewCallId(); - - Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null, callIdHeader); - transmitRequest(device, request); - return true; - } catch (SipException | ParseException | InvalidArgumentException e) { - e.printStackTrace(); - return false; - } - } - - /** - * 报警布防/撤防命令 - * - * @param device 视频设备 - * @param guardCmdStr "SetGuard"/"ResetGuard" - */ - @Override - public boolean guardCmd(Device device, String guardCmdStr, SipSubscribe.Event errorEvent) { - try { - StringBuffer cmdXml = new StringBuffer(200); - String charset = device.getCharset(); - cmdXml.append("\r\n"); - cmdXml.append("\r\n"); - cmdXml.append("DeviceControl\r\n"); - cmdXml.append("" + (int)((Math.random()*9+1)*100000) + "\r\n"); - cmdXml.append("" + device.getDeviceId() + "\r\n"); - cmdXml.append("" + guardCmdStr + "\r\n"); - cmdXml.append("\r\n"); - - CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId() - : udpSipProvider.getNewCallId(); - - Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null, callIdHeader); - transmitRequest(device, request, errorEvent); - return true; - } catch (SipException | ParseException | InvalidArgumentException e) { - e.printStackTrace(); - return false; - } - } - - /** - * 报警复位命令 - * - * @param device 视频设备 - */ - @Override - public boolean alarmCmd(Device device, String alarmMethod, String alarmType, SipSubscribe.Event errorEvent) { - try { - StringBuffer cmdXml = new StringBuffer(200); - String charset = device.getCharset(); - cmdXml.append("\r\n"); - cmdXml.append("\r\n"); - cmdXml.append("DeviceControl\r\n"); - cmdXml.append("" + (int)((Math.random()*9+1)*100000) + "\r\n"); - cmdXml.append("" + device.getDeviceId() + "\r\n"); - cmdXml.append("ResetAlarm\r\n"); - if (!ObjectUtils.isEmpty(alarmMethod) || !ObjectUtils.isEmpty(alarmType)) { - cmdXml.append("\r\n"); - } - if (!ObjectUtils.isEmpty(alarmMethod)) { - cmdXml.append("" + alarmMethod + "\r\n"); - } - if (!ObjectUtils.isEmpty(alarmType)) { - cmdXml.append("" + alarmType + "\r\n"); - } - if (!ObjectUtils.isEmpty(alarmMethod) || !ObjectUtils.isEmpty(alarmType)) { - cmdXml.append("\r\n"); - } - cmdXml.append("\r\n"); - - CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId() - : udpSipProvider.getNewCallId(); - - Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null, callIdHeader); - transmitRequest(device, request, errorEvent); - return true; - } catch (SipException | ParseException | InvalidArgumentException e) { - e.printStackTrace(); - return false; - } - } - - /** - * 强制关键帧命令,设备收到此命令应立刻发送一个IDR帧 - * - * @param device 视频设备 - * @param channelId 预览通道 - */ - @Override - public boolean iFrameCmd(Device device, String channelId) { - try { - StringBuffer cmdXml = new StringBuffer(200); - String charset = device.getCharset(); - cmdXml.append("\r\n"); - cmdXml.append("\r\n"); - cmdXml.append("DeviceControl\r\n"); - cmdXml.append("" + (int)((Math.random()*9+1)*100000) + "\r\n"); - if (ObjectUtils.isEmpty(channelId)) { - cmdXml.append("" + device.getDeviceId() + "\r\n"); - } else { - cmdXml.append("" + channelId + "\r\n"); - } - cmdXml.append("Send\r\n"); - cmdXml.append("\r\n"); - - CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId() - : udpSipProvider.getNewCallId(); - - Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null, callIdHeader); - transmitRequest(device, request); - return true; - } catch (SipException | ParseException | InvalidArgumentException e) { - e.printStackTrace(); - return false; - } - } - - /** - * 看守位控制命令 - * - * @param device 视频设备 - * @param enabled 看守位使能:1 = 开启,0 = 关闭 - * @param resetTime 自动归位时间间隔,开启看守位时使用,单位:秒(s) - * @param presetIndex 调用预置位编号,开启看守位时使用,取值范围0~255 - */ - @Override - public boolean homePositionCmd(Device device, String channelId, String enabled, String resetTime, String presetIndex, SipSubscribe.Event errorEvent) { - try { - StringBuffer cmdXml = new StringBuffer(200); - String charset = device.getCharset(); - cmdXml.append("\r\n"); - cmdXml.append("\r\n"); - cmdXml.append("DeviceControl\r\n"); - cmdXml.append("" + (int)((Math.random()*9+1)*100000) + "\r\n"); - if (ObjectUtils.isEmpty(channelId)) { - cmdXml.append("" + device.getDeviceId() + "\r\n"); - } else { - cmdXml.append("" + channelId + "\r\n"); - } - cmdXml.append("\r\n"); - if (NumericUtil.isInteger(enabled) && (!enabled.equals("0"))) { - cmdXml.append("1\r\n"); - if (NumericUtil.isInteger(resetTime)) { - cmdXml.append("" + resetTime + "\r\n"); - } else { - cmdXml.append("0\r\n"); - } - if (NumericUtil.isInteger(presetIndex)) { - cmdXml.append("" + presetIndex + "\r\n"); - } else { - cmdXml.append("0\r\n"); - } - } else { - cmdXml.append("0\r\n"); - } - cmdXml.append("\r\n"); - cmdXml.append("\r\n"); - - CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId() - : udpSipProvider.getNewCallId(); - - Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null, callIdHeader); - transmitRequest(device, request, errorEvent); - return true; - } catch (SipException | ParseException | InvalidArgumentException e) { - e.printStackTrace(); - return false; - } - } - - /** - * 设备配置命令 - * - * @param device 视频设备 - */ - @Override - public boolean deviceConfigCmd(Device device) { - // TODO Auto-generated method stub - return false; - } - - /** - * 设备配置命令:basicParam - * - * @param device 视频设备 - * @param channelId 通道编码(可选) - * @param name 设备/通道名称(可选) - * @param expiration 注册过期时间(可选) - * @param heartBeatInterval 心跳间隔时间(可选) - * @param heartBeatCount 心跳超时次数(可选) - */ - @Override - public boolean deviceBasicConfigCmd(Device device, String channelId, String name, String expiration, - String heartBeatInterval, String heartBeatCount, SipSubscribe.Event errorEvent) { - try { - StringBuffer cmdXml = new StringBuffer(200); - String charset = device.getCharset(); - cmdXml.append("\r\n"); - cmdXml.append("\r\n"); - cmdXml.append("DeviceConfig\r\n"); - cmdXml.append("" + (int)((Math.random()*9+1)*100000) + "\r\n"); - if (ObjectUtils.isEmpty(channelId)) { - cmdXml.append("" + device.getDeviceId() + "\r\n"); - } else { - cmdXml.append("" + channelId + "\r\n"); - } - cmdXml.append("\r\n"); - if (!ObjectUtils.isEmpty(name)) { - cmdXml.append("" + name + "\r\n"); - } - if (NumericUtil.isInteger(expiration)) { - if (Integer.valueOf(expiration) > 0) { - cmdXml.append("" + expiration + "\r\n"); - } - } - if (NumericUtil.isInteger(heartBeatInterval)) { - if (Integer.valueOf(heartBeatInterval) > 0) { - cmdXml.append("" + heartBeatInterval + "\r\n"); - } - } - if (NumericUtil.isInteger(heartBeatCount)) { - if (Integer.valueOf(heartBeatCount) > 0) { - cmdXml.append("" + heartBeatCount + "\r\n"); - } - } - cmdXml.append("\r\n"); - cmdXml.append("\r\n"); - - CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId() - : udpSipProvider.getNewCallId(); - - Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null, callIdHeader); - transmitRequest(device, request, errorEvent); - return true; - } catch (SipException | ParseException | InvalidArgumentException e) { - e.printStackTrace(); - return false; - } - } - - /** - * 查询设备状态 - * - * @param device 视频设备 - */ - @Override - public boolean deviceStatusQuery(Device device, SipSubscribe.Event errorEvent) { - try { - String charset = device.getCharset(); - StringBuffer catalogXml = new StringBuffer(200); - catalogXml.append("\r\n"); - catalogXml.append("\r\n"); - catalogXml.append("DeviceStatus\r\n"); - catalogXml.append("" + (int)((Math.random()*9+1)*100000) + "\r\n"); - catalogXml.append("" + device.getDeviceId() + "\r\n"); - catalogXml.append("\r\n"); - - CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId() - : udpSipProvider.getNewCallId(); - - Request request = headerProvider.createMessageRequest(device, catalogXml.toString(), null, SipUtils.getNewFromTag(), null, callIdHeader); - - transmitRequest(device, request, errorEvent); - return true; - - } catch (SipException | ParseException | InvalidArgumentException e) { - e.printStackTrace(); - return false; - } - } - - /** - * 查询设备信息 - * - * @param device 视频设备 - */ - @Override - public boolean deviceInfoQuery(Device device) { - try { - StringBuffer catalogXml = new StringBuffer(200); - String charset = device.getCharset(); - catalogXml.append("\r\n"); - catalogXml.append("\r\n"); - catalogXml.append("DeviceInfo\r\n"); - catalogXml.append("" + (int)((Math.random()*9+1)*100000) + "\r\n"); - catalogXml.append("" + device.getDeviceId() + "\r\n"); - catalogXml.append("\r\n"); - - CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId() - : udpSipProvider.getNewCallId(); - - Request request = headerProvider.createMessageRequest(device, catalogXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null, callIdHeader); - - transmitRequest(device, request); - - } catch (SipException | ParseException | InvalidArgumentException e) { - e.printStackTrace(); - return false; - } - return true; - } - - /** - * 查询目录列表 - * - * @param device 视频设备 - */ - @Override - public boolean catalogQuery(Device device, int sn, SipSubscribe.Event errorEvent) { - try { - StringBuffer catalogXml = new StringBuffer(200); - String charset = device.getCharset(); - catalogXml.append("\r\n"); - catalogXml.append("\r\n"); - catalogXml.append(" Catalog\r\n"); - catalogXml.append(" " + sn + "\r\n"); - catalogXml.append(" " + device.getDeviceId() + "\r\n"); - catalogXml.append("\r\n"); - - CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId() - : udpSipProvider.getNewCallId(); - - Request request = headerProvider.createMessageRequest(device, catalogXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null, callIdHeader); - - transmitRequest(device, request, errorEvent); - } catch (SipException | ParseException | InvalidArgumentException e) { - e.printStackTrace(); - return false; - } - return true; - } - - /** - * 查询录像信息 - * - * @param device 视频设备 - * @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss - * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss - */ - @Override - public boolean recordInfoQuery(Device device, String channelId, String startTime, String endTime, int sn, Integer secrecy, String type, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) { - if (secrecy == null) { - secrecy = 0; - } - if (type == null) { - type = "all"; - } - try { - StringBuffer recordInfoXml = new StringBuffer(200); - String charset = device.getCharset(); - recordInfoXml.append("\r\n"); - recordInfoXml.append("\r\n"); - recordInfoXml.append("RecordInfo\r\n"); - recordInfoXml.append("" + sn + "\r\n"); - recordInfoXml.append("" + channelId + "\r\n"); - if (startTime != null) { - recordInfoXml.append("" + DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(startTime) + "\r\n"); - } - if (endTime != null) { - recordInfoXml.append("" + DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(endTime) + "\r\n"); - } - if (secrecy != null) { - recordInfoXml.append(" "+ secrecy + " \r\n"); - } - if (type != null) { - // 大华NVR要求必须增加一个值为all的文本元素节点Type - recordInfoXml.append("" + type+"\r\n"); - } - recordInfoXml.append("\r\n"); - - CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId() - : udpSipProvider.getNewCallId(); - - Request request = headerProvider.createMessageRequest(device, recordInfoXml.toString(), - SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null, callIdHeader); - - transmitRequest(device, request, errorEvent, okEvent); - } catch (SipException | ParseException | InvalidArgumentException e) { - e.printStackTrace(); - return false; - } - return true; - } - - /** - * 查询报警信息 - * - * @param device 视频设备 - * @param startPriority 报警起始级别(可选) - * @param endPriority 报警终止级别(可选) - * @param alarmMethod 报警方式条件(可选) - * @param alarmType 报警类型 - * @param startTime 报警发生起始时间(可选) - * @param endTime 报警发生终止时间(可选) - * @return true = 命令发送成功 - */ - @Override - public boolean alarmInfoQuery(Device device, String startPriority, String endPriority, String alarmMethod, String alarmType, - String startTime, String endTime, SipSubscribe.Event errorEvent) { - try { - StringBuffer cmdXml = new StringBuffer(200); - String charset = device.getCharset(); - cmdXml.append("\r\n"); - cmdXml.append("\r\n"); - cmdXml.append("Alarm\r\n"); - cmdXml.append("" + (int)((Math.random()*9+1)*100000) + "\r\n"); - cmdXml.append("" + device.getDeviceId() + "\r\n"); - if (!ObjectUtils.isEmpty(startPriority)) { - cmdXml.append("" + startPriority + "\r\n"); - } - if (!ObjectUtils.isEmpty(endPriority)) { - cmdXml.append("" + endPriority + "\r\n"); - } - if (!ObjectUtils.isEmpty(alarmMethod)) { - cmdXml.append("" + alarmMethod + "\r\n"); - } - if (!ObjectUtils.isEmpty(alarmType)) { - cmdXml.append("" + alarmType + "\r\n"); - } - if (!ObjectUtils.isEmpty(startTime)) { - cmdXml.append("" + startTime + "\r\n"); - } - if (!ObjectUtils.isEmpty(endTime)) { - cmdXml.append("" + endTime + "\r\n"); - } - cmdXml.append("\r\n"); - - CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId() - : udpSipProvider.getNewCallId(); - - Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null, callIdHeader); - transmitRequest(device, request, errorEvent); - return true; - } catch (SipException | ParseException | InvalidArgumentException e) { - e.printStackTrace(); - return false; - } - } - - /** - * 查询设备配置 - * - * @param device 视频设备 - * @param channelId 通道编码(可选) - * @param configType 配置类型: - */ - @Override - public boolean deviceConfigQuery(Device device, String channelId, String configType, SipSubscribe.Event errorEvent) { - try { - StringBuffer cmdXml = new StringBuffer(200); - String charset = device.getCharset(); - cmdXml.append("\r\n"); - cmdXml.append("\r\n"); - cmdXml.append("ConfigDownload\r\n"); - cmdXml.append("" + (int)((Math.random()*9+1)*100000) + "\r\n"); - if (ObjectUtils.isEmpty(channelId)) { - cmdXml.append("" + device.getDeviceId() + "\r\n"); - } else { - cmdXml.append("" + channelId + "\r\n"); - } - cmdXml.append("" + configType + "\r\n"); - cmdXml.append("\r\n"); - - CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId() - : udpSipProvider.getNewCallId(); - - Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null, callIdHeader); - transmitRequest(device, request, errorEvent); - return true; - } catch (SipException | ParseException | InvalidArgumentException e) { - e.printStackTrace(); - return false; - } - } - - /** - * 查询设备预置位置 - * - * @param device 视频设备 - */ - @Override - public boolean presetQuery(Device device, String channelId, SipSubscribe.Event errorEvent) { - try { - StringBuffer cmdXml = new StringBuffer(200); - String charset = device.getCharset(); - cmdXml.append("\r\n"); - cmdXml.append("\r\n"); - cmdXml.append("PresetQuery\r\n"); - cmdXml.append("" + (int)((Math.random()*9+1)*100000) + "\r\n"); - if (ObjectUtils.isEmpty(channelId)) { - cmdXml.append("" + device.getDeviceId() + "\r\n"); - } else { - cmdXml.append("" + channelId + "\r\n"); - } - cmdXml.append("\r\n"); - - CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId() - : udpSipProvider.getNewCallId(); - - Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null, callIdHeader); - transmitRequest(device, request, errorEvent); - return true; - } catch (SipException | ParseException | InvalidArgumentException e) { - e.printStackTrace(); - return false; - } - } - - /** - * 查询移动设备位置数据 - * - * @param device 视频设备 - */ - @Override - public boolean mobilePostitionQuery(Device device, SipSubscribe.Event errorEvent) { - try { - StringBuffer mobilePostitionXml = new StringBuffer(200); - String charset = device.getCharset(); - mobilePostitionXml.append("\r\n"); - mobilePostitionXml.append("\r\n"); - mobilePostitionXml.append("MobilePosition\r\n"); - mobilePostitionXml.append("" + (int)((Math.random()*9+1)*100000) + "\r\n"); - mobilePostitionXml.append("" + device.getDeviceId() + "\r\n"); - mobilePostitionXml.append("60\r\n"); - mobilePostitionXml.append("\r\n"); - - CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId() - : udpSipProvider.getNewCallId(); - - Request request = headerProvider.createMessageRequest(device, mobilePostitionXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null, callIdHeader); - - transmitRequest(device, request, errorEvent); - - } catch (SipException | ParseException | InvalidArgumentException e) { - e.printStackTrace(); - return false; - } - return true; - } - - /** - * 订阅、取消订阅移动位置 - * - * @param device 视频设备 - * @return true = 命令发送成功 - */ - @Override - public SIPRequest mobilePositionSubscribe(Device device, SIPRequest requestOld, SipSubscribe.Event okEvent ,SipSubscribe.Event errorEvent) { - try { - StringBuffer subscribePostitionXml = new StringBuffer(200); - String charset = device.getCharset(); - subscribePostitionXml.append("\r\n"); - subscribePostitionXml.append("\r\n"); - subscribePostitionXml.append("MobilePosition\r\n"); - subscribePostitionXml.append("" + (int)((Math.random()*9+1)*100000) + "\r\n"); - subscribePostitionXml.append("" + device.getDeviceId() + "\r\n"); - if (device.getSubscribeCycleForMobilePosition() > 0) { - subscribePostitionXml.append("" + device.getMobilePositionSubmissionInterval() + "\r\n"); - } - subscribePostitionXml.append("\r\n"); - - CallIdHeader callIdHeader; - - if (requestOld != null) { - callIdHeader = sipFactory.createHeaderFactory().createCallIdHeader(requestOld.getCallIdHeader().getCallId()); - }else { - callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId() - : udpSipProvider.getNewCallId(); - } - SIPRequest request = (SIPRequest)headerProvider.createSubscribeRequest(device, subscribePostitionXml.toString(), requestOld, device.getSubscribeCycleForMobilePosition(), "presence" ,callIdHeader); //Position;id=" + tm.substring(tm.length() - 4)); - - transmitRequest(device, request, errorEvent, okEvent); - - return request; - - } catch ( NumberFormatException | ParseException | InvalidArgumentException | SipException e) { - e.printStackTrace(); - return null; - } - } - - /** - * 订阅、取消订阅报警信息 - * - * @param device 视频设备 - * @param expires 订阅过期时间(0 = 取消订阅) - * @param startPriority 报警起始级别(可选) - * @param endPriority 报警终止级别(可选) - * @param alarmMethod 报警方式条件(可选) - * @param alarmType 报警类型 - * @param startTime 报警发生起始时间(可选) - * @param endTime 报警发生终止时间(可选) - * @return true = 命令发送成功 - */ - @Override - public boolean alarmSubscribe(Device device, int expires, String startPriority, String endPriority, String alarmMethod, String alarmType, String startTime, String endTime) { - try { - StringBuffer cmdXml = new StringBuffer(200); - String charset = device.getCharset(); - cmdXml.append("\r\n"); - cmdXml.append("\r\n"); - cmdXml.append("Alarm\r\n"); - cmdXml.append("" + (int)((Math.random()*9+1)*100000) + "\r\n"); - cmdXml.append("" + device.getDeviceId() + "\r\n"); - if (!ObjectUtils.isEmpty(startPriority)) { - cmdXml.append("" + startPriority + "\r\n"); - } - if (!ObjectUtils.isEmpty(endPriority)) { - cmdXml.append("" + endPriority + "\r\n"); - } - if (!ObjectUtils.isEmpty(alarmMethod)) { - cmdXml.append("" + alarmMethod + "\r\n"); - } - if (!ObjectUtils.isEmpty(alarmType)) { - cmdXml.append("" + alarmType + "\r\n"); - } - if (!ObjectUtils.isEmpty(startTime)) { - cmdXml.append("" + startTime + "\r\n"); - } - if (!ObjectUtils.isEmpty(endTime)) { - cmdXml.append("" + endTime + "\r\n"); - } - cmdXml.append("\r\n"); - - CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId() - : udpSipProvider.getNewCallId(); - - Request request = headerProvider.createSubscribeRequest(device, cmdXml.toString(), null, expires, "presence" , callIdHeader); - transmitRequest(device, request); - - return true; - - } catch ( NumberFormatException | ParseException | InvalidArgumentException | SipException e) { - e.printStackTrace(); - return false; - } - } - - @Override - public SIPRequest catalogSubscribe(Device device, SIPRequest requestOld, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) { - try { - StringBuffer cmdXml = new StringBuffer(200); - String charset = device.getCharset(); - cmdXml.append("\r\n"); - cmdXml.append("\r\n"); - cmdXml.append("Catalog\r\n"); - cmdXml.append("" + (int)((Math.random()*9+1)*100000) + "\r\n"); - cmdXml.append("" + device.getDeviceId() + "\r\n"); - cmdXml.append("\r\n"); - - CallIdHeader callIdHeader ; - - if (requestOld != null) { - callIdHeader = sipFactory.createHeaderFactory().createCallIdHeader(requestOld.getCallIdHeader().getCallId()); - }else { - callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId() - : udpSipProvider.getNewCallId(); - } - - // 有效时间默认为60秒以上 - SIPRequest request = (SIPRequest)headerProvider.createSubscribeRequest(device, cmdXml.toString(), requestOld, device.getSubscribeCycleForCatalog(), "Catalog" , - callIdHeader); - transmitRequest(device, request, errorEvent, okEvent); - return request; - - } catch ( NumberFormatException | ParseException | InvalidArgumentException | SipException e) { - e.printStackTrace(); - return null; - } - } - - @Override - public boolean dragZoomCmd(Device device, String channelId, String cmdString) { - try { - StringBuffer dragXml = new StringBuffer(200); - String charset = device.getCharset(); - dragXml.append("\r\n"); - dragXml.append("\r\n"); - dragXml.append("DeviceControl\r\n"); - dragXml.append("" + (int) ((Math.random() * 9 + 1) * 100000) + "\r\n"); - if (ObjectUtils.isEmpty(channelId)) { - dragXml.append("" + device.getDeviceId() + "\r\n"); - } else { - dragXml.append("" + channelId + "\r\n"); - } - dragXml.append(cmdString); - dragXml.append("\r\n"); - CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId() - : udpSipProvider.getNewCallId(); - Request request = headerProvider.createMessageRequest(device, dragXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null, callIdHeader); - logger.debug("拉框信令: " + request.toString()); - transmitRequest(device, request); - return true; - } catch (SipException | ParseException | InvalidArgumentException e) { - e.printStackTrace(); - } - return false; - } - - - private ClientTransaction transmitRequest(Device device, Request request) throws SipException { - return transmitRequest(device, request, null, null); - } - - private ClientTransaction transmitRequest(Device device, Request request, SipSubscribe.Event errorEvent) throws SipException { - return transmitRequest(device, request, errorEvent, null); - } - - private ClientTransaction transmitRequest(Device device, Request request, SipSubscribe.Event errorEvent , SipSubscribe.Event okEvent) throws SipException { - ClientTransaction clientTransaction = null; - if("TCP".equals(device.getTransport())) { - clientTransaction = tcpSipProvider.getNewClientTransaction(request); - } else if("UDP".equals(device.getTransport())) { - clientTransaction = udpSipProvider.getNewClientTransaction(request); - } - if (request.getHeader(UserAgentHeader.NAME) == null) { - try { - request.addHeader(SipUtils.createUserAgentHeader(sipFactory, gitUtil)); - } catch (ParseException e) { - logger.error("添加UserAgentHeader失败", e); - } - } - CallIdHeader callIdHeader = (CallIdHeader)request.getHeader(CallIdHeader.NAME); - // 添加错误订阅 - if (errorEvent != null) { - sipSubscribe.addErrorSubscribe(callIdHeader.getCallId(), (eventResult -> { - errorEvent.response(eventResult); - sipSubscribe.removeErrorSubscribe(eventResult.callId); - sipSubscribe.removeOkSubscribe(eventResult.callId); - })); - } - // 添加订阅 - if (okEvent != null) { - sipSubscribe.addOkSubscribe(callIdHeader.getCallId(), eventResult ->{ - okEvent.response(eventResult); - sipSubscribe.removeOkSubscribe(eventResult.callId); - sipSubscribe.removeErrorSubscribe(eventResult.callId); - }); - } - - clientTransaction.sendRequest(); - return clientTransaction; - } - - /** - * 回放暂停 - */ - @Override - public void playPauseCmd(Device device, StreamInfo streamInfo) { - try { - StringBuffer content = new StringBuffer(200); - content.append("PAUSE RTSP/1.0\r\n"); - content.append("CSeq: " + getInfoCseq() + "\r\n"); - content.append("PauseTime: now\r\n"); - Request request = headerProvider.createInfoRequest(device, streamInfo, content.toString()); - if (request == null) { - return; - } - logger.info(request.toString()); - ClientTransaction clientTransaction = null; - if ("TCP".equals(device.getTransport())) { - clientTransaction = tcpSipProvider.getNewClientTransaction(request); - } else if ("UDP".equals(device.getTransport())) { - clientTransaction = udpSipProvider.getNewClientTransaction(request); - } - if (clientTransaction != null) { - clientTransaction.sendRequest(); - } - - } catch (SipException | ParseException | InvalidArgumentException e) { - e.printStackTrace(); - } - } - - /** - * 回放恢复 - */ - @Override - public void playResumeCmd(Device device, StreamInfo streamInfo) { - try { - StringBuffer content = new StringBuffer(200); - content.append("PLAY RTSP/1.0\r\n"); - content.append("CSeq: " + getInfoCseq() + "\r\n"); - content.append("Range: npt=now-\r\n"); - Request request = headerProvider.createInfoRequest(device, streamInfo, content.toString()); - if (request == null) { - return; - } - logger.info(request.toString()); - ClientTransaction clientTransaction = null; - if ("TCP".equals(device.getTransport())) { - clientTransaction = tcpSipProvider.getNewClientTransaction(request); - } else if ("UDP".equals(device.getTransport())) { - clientTransaction = udpSipProvider.getNewClientTransaction(request); - } - - clientTransaction.sendRequest(); - - } catch (SipException | ParseException | InvalidArgumentException e) { - e.printStackTrace(); - } - } - - /** - * 回放拖动播放 - */ - @Override - public void playSeekCmd(Device device, StreamInfo streamInfo, long seekTime) { - try { - StringBuffer content = new StringBuffer(200); - content.append("PLAY RTSP/1.0\r\n"); - content.append("CSeq: " + getInfoCseq() + "\r\n"); - content.append("Range: npt=" + Math.abs(seekTime) + "-\r\n"); - - Request request = headerProvider.createInfoRequest(device, streamInfo, content.toString()); - if (request == null) { - return; - } - logger.info(request.toString()); - ClientTransaction clientTransaction = null; - if ("TCP".equals(device.getTransport())) { - clientTransaction = tcpSipProvider.getNewClientTransaction(request); - } else if ("UDP".equals(device.getTransport())) { - clientTransaction = udpSipProvider.getNewClientTransaction(request); - } - - clientTransaction.sendRequest(); - - } catch (SipException | ParseException | InvalidArgumentException e) { - e.printStackTrace(); - } - } - - /** - * 回放倍速播放 - */ - @Override - public void playSpeedCmd(Device device, StreamInfo streamInfo, Double speed) { - try { - - StringBuffer content = new StringBuffer(200); - content.append("PLAY RTSP/1.0\r\n"); - content.append("CSeq: " + getInfoCseq() + "\r\n"); - content.append("Scale: " + String.format("%.6f",speed) + "\r\n"); - Request request = headerProvider.createInfoRequest(device, streamInfo, content.toString()); - if (request == null) { - return; - } - logger.info(request.toString()); - ClientTransaction clientTransaction = null; - if ("TCP".equals(device.getTransport())) { - clientTransaction = tcpSipProvider.getNewClientTransaction(request); - } else if ("UDP".equals(device.getTransport())) { - clientTransaction = udpSipProvider.getNewClientTransaction(request); - } - - clientTransaction.sendRequest(); - - } catch (SipException | ParseException | InvalidArgumentException e) { - e.printStackTrace(); - } - } - - private int getInfoCseq() { - return (int) ((Math.random() * 9 + 1) * Math.pow(10, 8)); - } - - @Override - public void playbackControlCmd(Device device, StreamInfo streamInfo, String content,SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) { - try { - Request request = headerProvider.createInfoRequest(device, streamInfo, content); - if (request == null) { - return; - } - ClientTransaction clientTransaction = null; - if ("TCP".equals(device.getTransport())) { - clientTransaction = tcpSipProvider.getNewClientTransaction(request); - } else if ("UDP".equals(device.getTransport())) { - clientTransaction = udpSipProvider.getNewClientTransaction(request); - } - CallIdHeader callIdHeader = (CallIdHeader)request.getHeader(CallIdHeader.NAME); - if(errorEvent != null) { - sipSubscribe.addErrorSubscribe(callIdHeader.getCallId(), (eventResult -> { - errorEvent.response(eventResult); - sipSubscribe.removeErrorSubscribe(eventResult.callId); - sipSubscribe.removeOkSubscribe(eventResult.callId); - })); - } - - if(okEvent != null) { - sipSubscribe.addOkSubscribe(callIdHeader.getCallId(), eventResult -> { - okEvent.response(eventResult); - sipSubscribe.removeOkSubscribe(eventResult.callId); - sipSubscribe.removeErrorSubscribe(eventResult.callId); - }); - } - clientTransaction.sendRequest(); - - } catch (SipException | ParseException | InvalidArgumentException e) { - e.printStackTrace(); - } - } - - @Override - public boolean sendAlarmMessage(Device device, DeviceAlarm deviceAlarm) { - if (device == null) { - return false; - } - logger.info("[发送 报警通知] {}/{}->{},{}", device.getDeviceId(), deviceAlarm.getChannelId(), - deviceAlarm.getLongitude(), deviceAlarm.getLatitude()); - try { - String characterSet = device.getCharset(); - StringBuffer deviceStatusXml = new StringBuffer(600); - deviceStatusXml.append("\r\n"); - deviceStatusXml.append("\r\n"); - deviceStatusXml.append("Alarm\r\n"); - deviceStatusXml.append("" + (int)((Math.random()*9+1)*100000) + "\r\n"); - deviceStatusXml.append("" + deviceAlarm.getChannelId() + "\r\n"); - deviceStatusXml.append("" + deviceAlarm.getAlarmPriority() + "\r\n"); - deviceStatusXml.append("" + deviceAlarm.getAlarmMethod() + "\r\n"); - deviceStatusXml.append("" + deviceAlarm.getAlarmTime() + "\r\n"); - deviceStatusXml.append("" + deviceAlarm.getAlarmDescription() + "\r\n"); - deviceStatusXml.append("" + deviceAlarm.getLongitude() + "\r\n"); - deviceStatusXml.append("" + deviceAlarm.getLatitude() + "\r\n"); - deviceStatusXml.append("\r\n"); - deviceStatusXml.append("" + deviceAlarm.getAlarmType() + "\r\n"); - deviceStatusXml.append("\r\n"); - deviceStatusXml.append("\r\n"); - - CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId() - : udpSipProvider.getNewCallId(); - Request request = headerProvider.createMessageRequest(device, deviceStatusXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null, callIdHeader); - transmitRequest(device, request); - - - } catch (SipException | ParseException e) { - e.printStackTrace(); - return false; - } catch (InvalidArgumentException e) { - throw new RuntimeException(e); - } - return true; - } + CallIdHeader callIdHeader = device.getTransport().equalsIgnoreCase("TCP") ? tcpSipProvider.getNewCallId() + : udpSipProvider.getNewCallId(); + + Request request = headerProvider.createInviteRequest(device, channelId, content.toString(), null, SipUtils.getNewFromTag(), null, ssrcInfo.getSsrc(), callIdHeader); + transmitRequest(device.getTransport(), request, (e -> { + streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream()); + mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc()); + errorEvent.response(e); + }), e -> { + // 这里为例避免一个通道的点播只有一个callID这个参数使用一个固定值 + ResponseEvent responseEvent = (ResponseEvent) e.event; + SIPResponse response = (SIPResponse) responseEvent.getResponse(); + streamSession.put(device.getDeviceId(), channelId, "play", stream, ssrcInfo.getSsrc(), mediaServerItem.getId(), response, VideoStreamSessionManager.SessionType.play); + okEvent.response(e); + }); + } + + /** + * 请求回放视频流 + * + * @param device 视频设备 + * @param channelId 预览通道 + * @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss + * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss + */ + @Override + public void playbackStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, + String startTime, String endTime, InviteStreamCallback inviteStreamCallback, InviteStreamCallback hookEvent, + SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException { + + + logger.info("{} 分配的ZLM为: {} [{}:{}]", ssrcInfo.getStream(), mediaServerItem.getId(), mediaServerItem.getIp(), ssrcInfo.getPort()); + + StringBuffer content = new StringBuffer(200); + content.append("v=0\r\n"); + content.append("o=" + channelId + " 0 0 IN IP4 " + mediaServerItem.getSdpIp() + "\r\n"); + content.append("s=Playback\r\n"); + content.append("u=" + channelId + ":0\r\n"); + content.append("c=IN IP4 " + mediaServerItem.getSdpIp() + "\r\n"); + content.append("t=" + DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(startTime) + " " + + DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(endTime) + "\r\n"); + + String streamMode = device.getStreamMode(); + + if (userSetting.isSeniorSdp()) { + if ("TCP-PASSIVE".equalsIgnoreCase(streamMode)) { + content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 126 125 99 34 98 97\r\n"); + } else if ("TCP-ACTIVE".equalsIgnoreCase(streamMode)) { + content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 126 125 99 34 98 97\r\n"); + } else if ("UDP".equalsIgnoreCase(streamMode)) { + content.append("m=video " + ssrcInfo.getPort() + " RTP/AVP 96 126 125 99 34 98 97\r\n"); + } + content.append("a=recvonly\r\n"); + content.append("a=rtpmap:96 PS/90000\r\n"); + content.append("a=fmtp:126 profile-level-id=42e01e\r\n"); + content.append("a=rtpmap:126 H264/90000\r\n"); + content.append("a=rtpmap:125 H264S/90000\r\n"); + content.append("a=fmtp:125 profile-level-id=42e01e\r\n"); + content.append("a=rtpmap:99 H265/90000\r\n"); + content.append("a=rtpmap:98 H264/90000\r\n"); + content.append("a=rtpmap:97 MPEG4/90000\r\n"); + if ("TCP-PASSIVE".equalsIgnoreCase(streamMode)) { // tcp被动模式 + content.append("a=setup:passive\r\n"); + content.append("a=connection:new\r\n"); + } else if ("TCP-ACTIVE".equalsIgnoreCase(streamMode)) { // tcp主动模式 + content.append("a=setup:active\r\n"); + content.append("a=connection:new\r\n"); + } + } else { + if ("TCP-PASSIVE".equalsIgnoreCase(streamMode)) { + content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 97 98 99\r\n"); + } else if ("TCP-ACTIVE".equalsIgnoreCase(streamMode)) { + content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 97 98 99\r\n"); + } else if ("UDP".equalsIgnoreCase(streamMode)) { + content.append("m=video " + ssrcInfo.getPort() + " RTP/AVP 96 97 98 99\r\n"); + } + content.append("a=recvonly\r\n"); + content.append("a=rtpmap:96 PS/90000\r\n"); + content.append("a=rtpmap:97 MPEG4/90000\r\n"); + content.append("a=rtpmap:98 H264/90000\r\n"); + content.append("a=rtpmap:99 H265/90000\r\n"); + if ("TCP-PASSIVE".equalsIgnoreCase(streamMode)) { // tcp被动模式 + content.append("a=setup:passive\r\n"); + content.append("a=connection:new\r\n"); + } else if ("TCP-ACTIVE".equalsIgnoreCase(streamMode)) { // tcp主动模式 + content.append("a=setup:active\r\n"); + content.append("a=connection:new\r\n"); + } + } + + content.append("y=" + ssrcInfo.getSsrc() + "\r\n");//ssrc + + CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId() + : udpSipProvider.getNewCallId(); + HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", ssrcInfo.getStream(), true, "rtsp", mediaServerItem.getId()); + // 添加订阅 + subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, JSONObject json) -> { + if (hookEvent != null) { + InviteStreamInfo inviteStreamInfo = new InviteStreamInfo(mediaServerItemInUse, json, callIdHeader.getCallId(), "rtp", ssrcInfo.getStream()); + hookEvent.call(inviteStreamInfo); + } + subscribe.removeSubscribe(hookSubscribe); + }); + Request request = headerProvider.createPlaybackInviteRequest(device, channelId, content.toString(), null, SipUtils.getNewFromTag(), null, callIdHeader, ssrcInfo.getSsrc()); + + transmitRequest(device.getTransport(), request, errorEvent, event -> { + ResponseEvent responseEvent = (ResponseEvent) event.event; + SIPResponse response = (SIPResponse) responseEvent.getResponse(); + streamSession.put(device.getDeviceId(), channelId, callIdHeader.getCallId(), ssrcInfo.getStream(), ssrcInfo.getSsrc(), mediaServerItem.getId(), response, VideoStreamSessionManager.SessionType.playback); + okEvent.response(event); + }); + if (inviteStreamCallback != null) { + inviteStreamCallback.call(new InviteStreamInfo(mediaServerItem, null, callIdHeader.getCallId(), "rtp", ssrcInfo.getStream())); + } + } + + /** + * 请求历史媒体下载 + * + * @param device 视频设备 + * @param channelId 预览通道 + * @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss + * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss + * @param downloadSpeed 下载倍速参数 + */ + @Override + public void downloadStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, + String startTime, String endTime, int downloadSpeed, InviteStreamCallback inviteStreamCallback, InviteStreamCallback hookEvent, + SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException { + + logger.info("{} 分配的ZLM为: {} [{}:{}]", ssrcInfo.getStream(), mediaServerItem.getId(), mediaServerItem.getIp(), ssrcInfo.getPort()); + + StringBuffer content = new StringBuffer(200); + content.append("v=0\r\n"); + content.append("o=" + channelId + " 0 0 IN IP4 " + mediaServerItem.getSdpIp() + "\r\n"); + content.append("s=Download\r\n"); + content.append("u=" + channelId + ":0\r\n"); + content.append("c=IN IP4 " + mediaServerItem.getSdpIp() + "\r\n"); + content.append("t=" + DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(startTime) + " " + + DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(endTime) + "\r\n"); + + String streamMode = device.getStreamMode().toUpperCase(); + + if (userSetting.isSeniorSdp()) { + if ("TCP-PASSIVE".equals(streamMode)) { + content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 126 125 99 34 98 97\r\n"); + } else if ("TCP-ACTIVE".equals(streamMode)) { + content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 126 125 99 34 98 97\r\n"); + } else if ("UDP".equals(streamMode)) { + content.append("m=video " + ssrcInfo.getPort() + " RTP/AVP 96 126 125 99 34 98 97\r\n"); + } + content.append("a=recvonly\r\n"); + content.append("a=rtpmap:96 PS/90000\r\n"); + content.append("a=fmtp:126 profile-level-id=42e01e\r\n"); + content.append("a=rtpmap:126 H264/90000\r\n"); + content.append("a=rtpmap:125 H264S/90000\r\n"); + content.append("a=fmtp:125 profile-level-id=42e01e\r\n"); + content.append("a=rtpmap:99 MP4V-ES/90000\r\n"); + content.append("a=fmtp:99 profile-level-id=3\r\n"); + content.append("a=rtpmap:98 H264/90000\r\n"); + content.append("a=rtpmap:97 MPEG4/90000\r\n"); + if ("TCP-PASSIVE".equals(streamMode)) { // tcp被动模式 + content.append("a=setup:passive\r\n"); + content.append("a=connection:new\r\n"); + } else if ("TCP-ACTIVE".equals(streamMode)) { // tcp主动模式 + content.append("a=setup:active\r\n"); + content.append("a=connection:new\r\n"); + } + } else { + if ("TCP-PASSIVE".equals(streamMode)) { + content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 97 98 99\r\n"); + } else if ("TCP-ACTIVE".equals(streamMode)) { + content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 97 98 99\r\n"); + } else if ("UDP".equals(streamMode)) { + content.append("m=video " + ssrcInfo.getPort() + " RTP/AVP 96 97 98 99\r\n"); + } + content.append("a=recvonly\r\n"); + content.append("a=rtpmap:96 PS/90000\r\n"); + content.append("a=rtpmap:97 MPEG4/90000\r\n"); + content.append("a=rtpmap:98 H264/90000\r\n"); + content.append("a=rtpmap:99 H265/90000\r\n"); + if ("TCP-PASSIVE".equals(streamMode)) { // tcp被动模式 + content.append("a=setup:passive\r\n"); + content.append("a=connection:new\r\n"); + } else if ("TCP-ACTIVE".equals(streamMode)) { // tcp主动模式 + content.append("a=setup:active\r\n"); + content.append("a=connection:new\r\n"); + } + } + content.append("a=downloadspeed:" + downloadSpeed + "\r\n"); + + content.append("y=" + ssrcInfo.getSsrc() + "\r\n");//ssrc + + CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId() + : udpSipProvider.getNewCallId(); + + HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", ssrcInfo.getStream(), true, null, mediaServerItem.getId()); + // 添加订阅 + subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, JSONObject json) -> { + hookEvent.call(new InviteStreamInfo(mediaServerItem, json, callIdHeader.getCallId(), "rtp", ssrcInfo.getStream())); + subscribe.removeSubscribe(hookSubscribe); + hookSubscribe.getContent().put("regist", false); + hookSubscribe.getContent().put("schema", "rtsp"); + // 添加流注销的订阅,注销了后向设备发送bye + subscribe.addSubscribe(hookSubscribe, + (MediaServerItem mediaServerItemForEnd, JSONObject jsonForEnd) -> { + logger.info("[录像]下载结束, 发送BYE"); + try { + streamByeCmd(device, channelId, ssrcInfo.getStream(), callIdHeader.getCallId()); + } catch (InvalidArgumentException | ParseException | SipException | + SsrcTransactionNotFoundException e) { + logger.error("[录像]下载结束, 发送BYE失败 {}", e.getMessage()); + } + }); + }); + + Request request = headerProvider.createPlaybackInviteRequest(device, channelId, content.toString(), null, SipUtils.getNewFromTag(), null, callIdHeader, ssrcInfo.getSsrc()); + if (inviteStreamCallback != null) { + inviteStreamCallback.call(new InviteStreamInfo(mediaServerItem, null, callIdHeader.getCallId(), "rtp", ssrcInfo.getStream())); + } + transmitRequest(device.getTransport(), request, errorEvent, okEvent -> { + ResponseEvent responseEvent = (ResponseEvent) okEvent.event; + SIPResponse response = (SIPResponse) responseEvent.getResponse(); + streamSession.put(device.getDeviceId(), channelId, callIdHeader.getCallId(), ssrcInfo.getStream(), ssrcInfo.getSsrc(), mediaServerItem.getId(), response, VideoStreamSessionManager.SessionType.download); + }); + } + + /** + * 视频流停止, 不使用回调 + */ + @Override + public void streamByeCmd(Device device, String channelId, String stream, String callId) throws InvalidArgumentException, ParseException, SipException, SsrcTransactionNotFoundException { + streamByeCmd(device, channelId, stream, callId, null); + } + + /** + * 视频流停止 + */ + @Override + public void streamByeCmd(Device device, String channelId, String stream, String callId, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException, SsrcTransactionNotFoundException { + SsrcTransaction ssrcTransaction = streamSession.getSsrcTransaction(device.getDeviceId(), channelId, callId, stream); + if (ssrcTransaction == null) { + throw new SsrcTransactionNotFoundException(device.getDeviceId(), channelId, callId, stream); + } + + mediaServerService.releaseSsrc(ssrcTransaction.getMediaServerId(), ssrcTransaction.getSsrc()); + mediaServerService.closeRTPServer(ssrcTransaction.getMediaServerId(), ssrcTransaction.getStream()); + streamSession.remove(ssrcTransaction.getDeviceId(), ssrcTransaction.getChannelId(), ssrcTransaction.getStream()); + + Request byteRequest = headerProvider.createByteRequest(device, channelId, ssrcTransaction.getSipTransactionInfo()); + transmitRequest(device.getTransport(), byteRequest, null, okEvent); + } + + /** + * 语音广播 + * + * @param device 视频设备 + * @param channelId 预览通道 + */ + @Override + public void audioBroadcastCmd(Device device, String channelId) { + } + + /** + * 语音广播 + * + * @param device 视频设备 + */ + @Override + public void audioBroadcastCmd(Device device) throws InvalidArgumentException, SipException, ParseException { + + StringBuffer broadcastXml = new StringBuffer(200); + String charset = device.getCharset(); + broadcastXml.append("\r\n"); + broadcastXml.append("\r\n"); + broadcastXml.append("Broadcast\r\n"); + broadcastXml.append("" + (int) ((Math.random() * 9 + 1) * 100000) + "\r\n"); + broadcastXml.append("" + sipConfig.getId() + "\r\n"); + broadcastXml.append("" + device.getDeviceId() + "\r\n"); + broadcastXml.append("\r\n"); + + CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId() + : udpSipProvider.getNewCallId(); + + Request request = headerProvider.createMessageRequest(device, broadcastXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null, callIdHeader); + transmitRequest(device.getTransport(), request); + + } + + @Override + public void audioBroadcastCmd(Device device, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException { + + StringBuffer broadcastXml = new StringBuffer(200); + String charset = device.getCharset(); + broadcastXml.append("\r\n"); + broadcastXml.append("\r\n"); + broadcastXml.append("Broadcast\r\n"); + broadcastXml.append("" + (int) ((Math.random() * 9 + 1) * 100000) + "\r\n"); + broadcastXml.append("" + sipConfig.getId() + "\r\n"); + broadcastXml.append("" + device.getDeviceId() + "\r\n"); + broadcastXml.append("\r\n"); + + CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId() + : udpSipProvider.getNewCallId(); + + Request request = headerProvider.createMessageRequest(device, broadcastXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null, callIdHeader); + transmitRequest(device.getTransport(), request, errorEvent); + + } + + + /** + * 音视频录像控制 + * + * @param device 视频设备 + * @param channelId 预览通道 + * @param recordCmdStr 录像命令:Record / StopRecord + */ + @Override + public void recordCmd(Device device, String channelId, String recordCmdStr, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException { + StringBuffer cmdXml = new StringBuffer(200); + String charset = device.getCharset(); + cmdXml.append("\r\n"); + cmdXml.append("\r\n"); + cmdXml.append("DeviceControl\r\n"); + cmdXml.append("" + (int) ((Math.random() * 9 + 1) * 100000) + "\r\n"); + if (ObjectUtils.isEmpty(channelId)) { + cmdXml.append("" + device.getDeviceId() + "\r\n"); + } else { + cmdXml.append("" + channelId + "\r\n"); + } + cmdXml.append("" + recordCmdStr + "\r\n"); + cmdXml.append("\r\n"); + + CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId() + : udpSipProvider.getNewCallId(); + + Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null, callIdHeader); + transmitRequest(device.getTransport(), request, errorEvent); + } + + /** + * 远程启动控制命令 + * + * @param device 视频设备 + */ + @Override + public void teleBootCmd(Device device) throws InvalidArgumentException, SipException, ParseException { + + StringBuffer cmdXml = new StringBuffer(200); + String charset = device.getCharset(); + cmdXml.append("\r\n"); + cmdXml.append("\r\n"); + cmdXml.append("DeviceControl\r\n"); + cmdXml.append("" + (int) ((Math.random() * 9 + 1) * 100000) + "\r\n"); + cmdXml.append("" + device.getDeviceId() + "\r\n"); + cmdXml.append("Boot\r\n"); + cmdXml.append("\r\n"); + + CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId() + : udpSipProvider.getNewCallId(); + + Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null, callIdHeader); + transmitRequest(device.getTransport(), request); + } + + /** + * 报警布防/撤防命令 + * + * @param device 视频设备 + * @param guardCmdStr "SetGuard"/"ResetGuard" + */ + @Override + public void guardCmd(Device device, String guardCmdStr, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException { + + StringBuffer cmdXml = new StringBuffer(200); + String charset = device.getCharset(); + cmdXml.append("\r\n"); + cmdXml.append("\r\n"); + cmdXml.append("DeviceControl\r\n"); + cmdXml.append("" + (int) ((Math.random() * 9 + 1) * 100000) + "\r\n"); + cmdXml.append("" + device.getDeviceId() + "\r\n"); + cmdXml.append("" + guardCmdStr + "\r\n"); + cmdXml.append("\r\n"); + + CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId() + : udpSipProvider.getNewCallId(); + + Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null, callIdHeader); + transmitRequest(device.getTransport(), request, errorEvent); + } + + /** + * 报警复位命令 + * + * @param device 视频设备 + */ + @Override + public void alarmCmd(Device device, String alarmMethod, String alarmType, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException { + + StringBuffer cmdXml = new StringBuffer(200); + String charset = device.getCharset(); + cmdXml.append("\r\n"); + cmdXml.append("\r\n"); + cmdXml.append("DeviceControl\r\n"); + cmdXml.append("" + (int) ((Math.random() * 9 + 1) * 100000) + "\r\n"); + cmdXml.append("" + device.getDeviceId() + "\r\n"); + cmdXml.append("ResetAlarm\r\n"); + if (!ObjectUtils.isEmpty(alarmMethod) || !ObjectUtils.isEmpty(alarmType)) { + cmdXml.append("\r\n"); + } + if (!ObjectUtils.isEmpty(alarmMethod)) { + cmdXml.append("" + alarmMethod + "\r\n"); + } + if (!ObjectUtils.isEmpty(alarmType)) { + cmdXml.append("" + alarmType + "\r\n"); + } + if (!ObjectUtils.isEmpty(alarmMethod) || !ObjectUtils.isEmpty(alarmType)) { + cmdXml.append("\r\n"); + } + cmdXml.append("\r\n"); + + CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId() + : udpSipProvider.getNewCallId(); + + Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null, callIdHeader); + transmitRequest(device.getTransport(), request, errorEvent); + } + + /** + * 强制关键帧命令,设备收到此命令应立刻发送一个IDR帧 + * + * @param device 视频设备 + * @param channelId 预览通道 + */ + @Override + public void iFrameCmd(Device device, String channelId) throws InvalidArgumentException, SipException, ParseException { + + StringBuffer cmdXml = new StringBuffer(200); + String charset = device.getCharset(); + cmdXml.append("\r\n"); + cmdXml.append("\r\n"); + cmdXml.append("DeviceControl\r\n"); + cmdXml.append("" + (int) ((Math.random() * 9 + 1) * 100000) + "\r\n"); + if (ObjectUtils.isEmpty(channelId)) { + cmdXml.append("" + device.getDeviceId() + "\r\n"); + } else { + cmdXml.append("" + channelId + "\r\n"); + } + cmdXml.append("Send\r\n"); + cmdXml.append("\r\n"); + + CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId() + : udpSipProvider.getNewCallId(); + + Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null, callIdHeader); + transmitRequest(device.getTransport(), request); + } + + /** + * 看守位控制命令 + * + * @param device 视频设备 + * @param enabled 看守位使能:1 = 开启,0 = 关闭 + * @param resetTime 自动归位时间间隔,开启看守位时使用,单位:秒(s) + * @param presetIndex 调用预置位编号,开启看守位时使用,取值范围0~255 + */ + @Override + public void homePositionCmd(Device device, String channelId, String enabled, String resetTime, String presetIndex, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException { + + StringBuffer cmdXml = new StringBuffer(200); + String charset = device.getCharset(); + cmdXml.append("\r\n"); + cmdXml.append("\r\n"); + cmdXml.append("DeviceControl\r\n"); + cmdXml.append("" + (int) ((Math.random() * 9 + 1) * 100000) + "\r\n"); + if (ObjectUtils.isEmpty(channelId)) { + cmdXml.append("" + device.getDeviceId() + "\r\n"); + } else { + cmdXml.append("" + channelId + "\r\n"); + } + cmdXml.append("\r\n"); + if (NumericUtil.isInteger(enabled) && (!enabled.equals("0"))) { + cmdXml.append("1\r\n"); + if (NumericUtil.isInteger(resetTime)) { + cmdXml.append("" + resetTime + "\r\n"); + } else { + cmdXml.append("0\r\n"); + } + if (NumericUtil.isInteger(presetIndex)) { + cmdXml.append("" + presetIndex + "\r\n"); + } else { + cmdXml.append("0\r\n"); + } + } else { + cmdXml.append("0\r\n"); + } + cmdXml.append("\r\n"); + cmdXml.append("\r\n"); + + CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId() + : udpSipProvider.getNewCallId(); + + Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null, callIdHeader); + transmitRequest(device.getTransport(), request, errorEvent); + } + + /** + * 设备配置命令 + * + * @param device 视频设备 + */ + @Override + public void deviceConfigCmd(Device device) { + // TODO Auto-generated method stub + } + + /** + * 设备配置命令:basicParam + * + * @param device 视频设备 + * @param channelId 通道编码(可选) + * @param name 设备/通道名称(可选) + * @param expiration 注册过期时间(可选) + * @param heartBeatInterval 心跳间隔时间(可选) + * @param heartBeatCount 心跳超时次数(可选) + */ + @Override + public void deviceBasicConfigCmd(Device device, String channelId, String name, String expiration, + String heartBeatInterval, String heartBeatCount, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException { + + StringBuffer cmdXml = new StringBuffer(200); + String charset = device.getCharset(); + cmdXml.append("\r\n"); + cmdXml.append("\r\n"); + cmdXml.append("DeviceConfig\r\n"); + cmdXml.append("" + (int) ((Math.random() * 9 + 1) * 100000) + "\r\n"); + if (ObjectUtils.isEmpty(channelId)) { + cmdXml.append("" + device.getDeviceId() + "\r\n"); + } else { + cmdXml.append("" + channelId + "\r\n"); + } + cmdXml.append("\r\n"); + if (!ObjectUtils.isEmpty(name)) { + cmdXml.append("" + name + "\r\n"); + } + if (NumericUtil.isInteger(expiration)) { + if (Integer.valueOf(expiration) > 0) { + cmdXml.append("" + expiration + "\r\n"); + } + } + if (NumericUtil.isInteger(heartBeatInterval)) { + if (Integer.valueOf(heartBeatInterval) > 0) { + cmdXml.append("" + heartBeatInterval + "\r\n"); + } + } + if (NumericUtil.isInteger(heartBeatCount)) { + if (Integer.valueOf(heartBeatCount) > 0) { + cmdXml.append("" + heartBeatCount + "\r\n"); + } + } + cmdXml.append("\r\n"); + cmdXml.append("\r\n"); + + CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId() + : udpSipProvider.getNewCallId(); + + Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null, callIdHeader); + transmitRequest(device.getTransport(), request, errorEvent); + } + + /** + * 查询设备状态 + * + * @param device 视频设备 + */ + @Override + public void deviceStatusQuery(Device device, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException { + + String charset = device.getCharset(); + StringBuffer catalogXml = new StringBuffer(200); + catalogXml.append("\r\n"); + catalogXml.append("\r\n"); + catalogXml.append("DeviceStatus\r\n"); + catalogXml.append("" + (int) ((Math.random() * 9 + 1) * 100000) + "\r\n"); + catalogXml.append("" + device.getDeviceId() + "\r\n"); + catalogXml.append("\r\n"); + + CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId() + : udpSipProvider.getNewCallId(); + + Request request = headerProvider.createMessageRequest(device, catalogXml.toString(), null, SipUtils.getNewFromTag(), null, callIdHeader); + + transmitRequest(device.getTransport(), request, errorEvent); + } + + /** + * 查询设备信息 + * + * @param device 视频设备 + */ + @Override + public void deviceInfoQuery(Device device) throws InvalidArgumentException, SipException, ParseException { + + StringBuffer catalogXml = new StringBuffer(200); + String charset = device.getCharset(); + catalogXml.append("\r\n"); + catalogXml.append("\r\n"); + catalogXml.append("DeviceInfo\r\n"); + catalogXml.append("" + (int) ((Math.random() * 9 + 1) * 100000) + "\r\n"); + catalogXml.append("" + device.getDeviceId() + "\r\n"); + catalogXml.append("\r\n"); + + CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId() + : udpSipProvider.getNewCallId(); + + Request request = headerProvider.createMessageRequest(device, catalogXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null, callIdHeader); + + transmitRequest(device.getTransport(), request); + + } + + /** + * 查询目录列表 + * + * @param device 视频设备 + */ + @Override + public void catalogQuery(Device device, int sn, SipSubscribe.Event errorEvent) throws SipException, InvalidArgumentException, ParseException { + + StringBuffer catalogXml = new StringBuffer(200); + String charset = device.getCharset(); + catalogXml.append("\r\n"); + catalogXml.append("\r\n"); + catalogXml.append(" Catalog\r\n"); + catalogXml.append(" " + sn + "\r\n"); + catalogXml.append(" " + device.getDeviceId() + "\r\n"); + catalogXml.append("\r\n"); + + CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId() + : udpSipProvider.getNewCallId(); + + Request request = headerProvider.createMessageRequest(device, catalogXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null, callIdHeader); + + transmitRequest(device.getTransport(), request, errorEvent); + } + + /** + * 查询录像信息 + * + * @param device 视频设备 + * @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss + * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss + */ + @Override + public void recordInfoQuery(Device device, String channelId, String startTime, String endTime, int sn, Integer secrecy, String type, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException { + if (secrecy == null) { + secrecy = 0; + } + if (type == null) { + type = "all"; + } + + StringBuffer recordInfoXml = new StringBuffer(200); + String charset = device.getCharset(); + recordInfoXml.append("\r\n"); + recordInfoXml.append("\r\n"); + recordInfoXml.append("RecordInfo\r\n"); + recordInfoXml.append("" + sn + "\r\n"); + recordInfoXml.append("" + channelId + "\r\n"); + if (startTime != null) { + recordInfoXml.append("" + DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(startTime) + "\r\n"); + } + if (endTime != null) { + recordInfoXml.append("" + DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(endTime) + "\r\n"); + } + if (secrecy != null) { + recordInfoXml.append(" " + secrecy + " \r\n"); + } + if (type != null) { + // 大华NVR要求必须增加一个值为all的文本元素节点Type + recordInfoXml.append("" + type + "\r\n"); + } + recordInfoXml.append("\r\n"); + + CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId() + : udpSipProvider.getNewCallId(); + + Request request = headerProvider.createMessageRequest(device, recordInfoXml.toString(), + SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null, callIdHeader); + + transmitRequest(device.getTransport(), request, errorEvent, okEvent); + } + + /** + * 查询报警信息 + * + * @param device 视频设备 + * @param startPriority 报警起始级别(可选) + * @param endPriority 报警终止级别(可选) + * @param alarmMethod 报警方式条件(可选) + * @param alarmType 报警类型 + * @param startTime 报警发生起始时间(可选) + * @param endTime 报警发生终止时间(可选) + * @return true = 命令发送成功 + */ + @Override + public void alarmInfoQuery(Device device, String startPriority, String endPriority, String alarmMethod, String alarmType, + String startTime, String endTime, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException { + + StringBuffer cmdXml = new StringBuffer(200); + String charset = device.getCharset(); + cmdXml.append("\r\n"); + cmdXml.append("\r\n"); + cmdXml.append("Alarm\r\n"); + cmdXml.append("" + (int) ((Math.random() * 9 + 1) * 100000) + "\r\n"); + cmdXml.append("" + device.getDeviceId() + "\r\n"); + if (!ObjectUtils.isEmpty(startPriority)) { + cmdXml.append("" + startPriority + "\r\n"); + } + if (!ObjectUtils.isEmpty(endPriority)) { + cmdXml.append("" + endPriority + "\r\n"); + } + if (!ObjectUtils.isEmpty(alarmMethod)) { + cmdXml.append("" + alarmMethod + "\r\n"); + } + if (!ObjectUtils.isEmpty(alarmType)) { + cmdXml.append("" + alarmType + "\r\n"); + } + if (!ObjectUtils.isEmpty(startTime)) { + cmdXml.append("" + startTime + "\r\n"); + } + if (!ObjectUtils.isEmpty(endTime)) { + cmdXml.append("" + endTime + "\r\n"); + } + cmdXml.append("\r\n"); + + CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId() + : udpSipProvider.getNewCallId(); + + Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null, callIdHeader); + transmitRequest(device.getTransport(), request, errorEvent); + } + + /** + * 查询设备配置 + * + * @param device 视频设备 + * @param channelId 通道编码(可选) + * @param configType 配置类型: + */ + @Override + public void deviceConfigQuery(Device device, String channelId, String configType, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException { + + StringBuffer cmdXml = new StringBuffer(200); + String charset = device.getCharset(); + cmdXml.append("\r\n"); + cmdXml.append("\r\n"); + cmdXml.append("ConfigDownload\r\n"); + cmdXml.append("" + (int) ((Math.random() * 9 + 1) * 100000) + "\r\n"); + if (ObjectUtils.isEmpty(channelId)) { + cmdXml.append("" + device.getDeviceId() + "\r\n"); + } else { + cmdXml.append("" + channelId + "\r\n"); + } + cmdXml.append("" + configType + "\r\n"); + cmdXml.append("\r\n"); + + CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId() + : udpSipProvider.getNewCallId(); + + Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null, callIdHeader); + transmitRequest(device.getTransport(), request, errorEvent); + } + + /** + * 查询设备预置位置 + * + * @param device 视频设备 + */ + @Override + public void presetQuery(Device device, String channelId, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException { + + StringBuffer cmdXml = new StringBuffer(200); + String charset = device.getCharset(); + cmdXml.append("\r\n"); + cmdXml.append("\r\n"); + cmdXml.append("PresetQuery\r\n"); + cmdXml.append("" + (int) ((Math.random() * 9 + 1) * 100000) + "\r\n"); + if (ObjectUtils.isEmpty(channelId)) { + cmdXml.append("" + device.getDeviceId() + "\r\n"); + } else { + cmdXml.append("" + channelId + "\r\n"); + } + cmdXml.append("\r\n"); + + CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId() + : udpSipProvider.getNewCallId(); + + Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null, callIdHeader); + transmitRequest(device.getTransport(), request, errorEvent); + } + + /** + * 查询移动设备位置数据 + * + * @param device 视频设备 + */ + @Override + public void mobilePostitionQuery(Device device, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException { + + StringBuffer mobilePostitionXml = new StringBuffer(200); + String charset = device.getCharset(); + mobilePostitionXml.append("\r\n"); + mobilePostitionXml.append("\r\n"); + mobilePostitionXml.append("MobilePosition\r\n"); + mobilePostitionXml.append("" + (int) ((Math.random() * 9 + 1) * 100000) + "\r\n"); + mobilePostitionXml.append("" + device.getDeviceId() + "\r\n"); + mobilePostitionXml.append("60\r\n"); + mobilePostitionXml.append("\r\n"); + + CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId() + : udpSipProvider.getNewCallId(); + + Request request = headerProvider.createMessageRequest(device, mobilePostitionXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null, callIdHeader); + + transmitRequest(device.getTransport(), request, errorEvent); + + } + + /** + * 订阅、取消订阅移动位置 + * + * @param device 视频设备 + * @return true = 命令发送成功 + */ + @Override + public SIPRequest mobilePositionSubscribe(Device device, SIPRequest requestOld, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException { + + StringBuffer subscribePostitionXml = new StringBuffer(200); + String charset = device.getCharset(); + subscribePostitionXml.append("\r\n"); + subscribePostitionXml.append("\r\n"); + subscribePostitionXml.append("MobilePosition\r\n"); + subscribePostitionXml.append("" + (int) ((Math.random() * 9 + 1) * 100000) + "\r\n"); + subscribePostitionXml.append("" + device.getDeviceId() + "\r\n"); + if (device.getSubscribeCycleForMobilePosition() > 0) { + subscribePostitionXml.append("" + device.getMobilePositionSubmissionInterval() + "\r\n"); + } + subscribePostitionXml.append("\r\n"); + + CallIdHeader callIdHeader; + + if (requestOld != null) { + callIdHeader = sipFactory.createHeaderFactory().createCallIdHeader(requestOld.getCallIdHeader().getCallId()); + } else { + callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId() + : udpSipProvider.getNewCallId(); + } + SIPRequest request = (SIPRequest) headerProvider.createSubscribeRequest(device, subscribePostitionXml.toString(), requestOld, device.getSubscribeCycleForMobilePosition(), "presence", callIdHeader); //Position;id=" + tm.substring(tm.length() - 4)); + + transmitRequest(device.getTransport(), request, errorEvent, okEvent); + return request; + } + + /** + * 订阅、取消订阅报警信息 + * + * @param device 视频设备 + * @param expires 订阅过期时间(0 = 取消订阅) + * @param startPriority 报警起始级别(可选) + * @param endPriority 报警终止级别(可选) + * @param alarmMethod 报警方式条件(可选) + * @param alarmType 报警类型 + * @param startTime 报警发生起始时间(可选) + * @param endTime 报警发生终止时间(可选) + * @return true = 命令发送成功 + */ + @Override + public void alarmSubscribe(Device device, int expires, String startPriority, String endPriority, String alarmMethod, String alarmType, String startTime, String endTime) throws InvalidArgumentException, SipException, ParseException { + + StringBuffer cmdXml = new StringBuffer(200); + String charset = device.getCharset(); + cmdXml.append("\r\n"); + cmdXml.append("\r\n"); + cmdXml.append("Alarm\r\n"); + cmdXml.append("" + (int) ((Math.random() * 9 + 1) * 100000) + "\r\n"); + cmdXml.append("" + device.getDeviceId() + "\r\n"); + if (!ObjectUtils.isEmpty(startPriority)) { + cmdXml.append("" + startPriority + "\r\n"); + } + if (!ObjectUtils.isEmpty(endPriority)) { + cmdXml.append("" + endPriority + "\r\n"); + } + if (!ObjectUtils.isEmpty(alarmMethod)) { + cmdXml.append("" + alarmMethod + "\r\n"); + } + if (!ObjectUtils.isEmpty(alarmType)) { + cmdXml.append("" + alarmType + "\r\n"); + } + if (!ObjectUtils.isEmpty(startTime)) { + cmdXml.append("" + startTime + "\r\n"); + } + if (!ObjectUtils.isEmpty(endTime)) { + cmdXml.append("" + endTime + "\r\n"); + } + cmdXml.append("\r\n"); + + CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId() + : udpSipProvider.getNewCallId(); + + Request request = headerProvider.createSubscribeRequest(device, cmdXml.toString(), null, expires, "presence", callIdHeader); + transmitRequest(device.getTransport(), request); + + } + + @Override + public SIPRequest catalogSubscribe(Device device, SIPRequest requestOld, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException { + + StringBuffer cmdXml = new StringBuffer(200); + String charset = device.getCharset(); + cmdXml.append("\r\n"); + cmdXml.append("\r\n"); + cmdXml.append("Catalog\r\n"); + cmdXml.append("" + (int) ((Math.random() * 9 + 1) * 100000) + "\r\n"); + cmdXml.append("" + device.getDeviceId() + "\r\n"); + cmdXml.append("\r\n"); + + CallIdHeader callIdHeader; + + if (requestOld != null) { + callIdHeader = sipFactory.createHeaderFactory().createCallIdHeader(requestOld.getCallIdHeader().getCallId()); + } else { + callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId() + : udpSipProvider.getNewCallId(); + } + + // 有效时间默认为60秒以上 + SIPRequest request = (SIPRequest) headerProvider.createSubscribeRequest(device, cmdXml.toString(), requestOld, device.getSubscribeCycleForCatalog(), "Catalog", + callIdHeader); + transmitRequest(device.getTransport(), request, errorEvent, okEvent); + return request; + } + + @Override + public void dragZoomCmd(Device device, String channelId, String cmdString) throws InvalidArgumentException, SipException, ParseException { + + StringBuffer dragXml = new StringBuffer(200); + String charset = device.getCharset(); + dragXml.append("\r\n"); + dragXml.append("\r\n"); + dragXml.append("DeviceControl\r\n"); + dragXml.append("" + (int) ((Math.random() * 9 + 1) * 100000) + "\r\n"); + if (ObjectUtils.isEmpty(channelId)) { + dragXml.append("" + device.getDeviceId() + "\r\n"); + } else { + dragXml.append("" + channelId + "\r\n"); + } + dragXml.append(cmdString); + dragXml.append("\r\n"); + CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId() + : udpSipProvider.getNewCallId(); + Request request = headerProvider.createMessageRequest(device, dragXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null, callIdHeader); + logger.debug("拉框信令: " + request.toString()); + transmitRequest(device.getTransport(), request); + } + + + @Override + public void transmitRequest(String transport, Request request) throws SipException, ParseException { + transmitRequest(transport, request, null, null); + } + + @Override + public void transmitRequest(String transport, Request request, SipSubscribe.Event errorEvent) throws SipException, ParseException { + transmitRequest(transport, request, errorEvent, null); + } + + @Override + public void transmitRequest(String transport, Request request, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws SipException, ParseException { + + if (request.getHeader(UserAgentHeader.NAME) == null) { + try { + request.addHeader(SipUtils.createUserAgentHeader(sipFactory, gitUtil)); + } catch (ParseException e) { + logger.error("添加UserAgentHeader失败", e); + } + } + + CallIdHeader callIdHeader = (CallIdHeader) request.getHeader(CallIdHeader.NAME); + // 添加错误订阅 + if (errorEvent != null) { + sipSubscribe.addErrorSubscribe(callIdHeader.getCallId(), (eventResult -> { + errorEvent.response(eventResult); + sipSubscribe.removeErrorSubscribe(eventResult.callId); + sipSubscribe.removeOkSubscribe(eventResult.callId); + })); + } + // 添加订阅 + if (okEvent != null) { + sipSubscribe.addOkSubscribe(callIdHeader.getCallId(), eventResult -> { + okEvent.response(eventResult); + sipSubscribe.removeOkSubscribe(eventResult.callId); + sipSubscribe.removeErrorSubscribe(eventResult.callId); + }); + } + if ("TCP".equals(transport)) { + tcpSipProvider.sendRequest(request); + } else if ("UDP".equals(transport)) { + udpSipProvider.sendRequest(request); + } + + } + + + /** + * 回放暂停 + */ + @Override + public void playPauseCmd(Device device, StreamInfo streamInfo) throws InvalidArgumentException, ParseException, SipException { + StringBuffer content = new StringBuffer(200); + content.append("PAUSE RTSP/1.0\r\n"); + content.append("CSeq: " + getInfoCseq() + "\r\n"); + content.append("PauseTime: now\r\n"); + + playbackControlCmd(device, streamInfo, content.toString(), null, null); + } + + + /** + * 回放恢复 + */ + @Override + public void playResumeCmd(Device device, StreamInfo streamInfo) throws InvalidArgumentException, ParseException, SipException { + StringBuffer content = new StringBuffer(200); + content.append("PLAY RTSP/1.0\r\n"); + content.append("CSeq: " + getInfoCseq() + "\r\n"); + content.append("Range: npt=now-\r\n"); + + playbackControlCmd(device, streamInfo, content.toString(), null, null); + } + + /** + * 回放拖动播放 + */ + @Override + public void playSeekCmd(Device device, StreamInfo streamInfo, long seekTime) throws InvalidArgumentException, ParseException, SipException { + StringBuffer content = new StringBuffer(200); + content.append("PLAY RTSP/1.0\r\n"); + content.append("CSeq: " + getInfoCseq() + "\r\n"); + content.append("Range: npt=" + Math.abs(seekTime) + "-\r\n"); + + playbackControlCmd(device, streamInfo, content.toString(), null, null); + } + + /** + * 回放倍速播放 + */ + @Override + public void playSpeedCmd(Device device, StreamInfo streamInfo, Double speed) throws InvalidArgumentException, ParseException, SipException { + StringBuffer content = new StringBuffer(200); + content.append("PLAY RTSP/1.0\r\n"); + content.append("CSeq: " + getInfoCseq() + "\r\n"); + content.append("Scale: " + String.format("%.6f", speed) + "\r\n"); + + playbackControlCmd(device, streamInfo, content.toString(), null, null); + } + + private int getInfoCseq() { + return (int) ((Math.random() * 9 + 1) * Math.pow(10, 8)); + } + + @Override + public void playbackControlCmd(Device device, StreamInfo streamInfo, String content, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws SipException, InvalidArgumentException, ParseException { + + SsrcTransaction ssrcTransaction = streamSession.getSsrcTransaction(device.getDeviceId(), streamInfo.getChannelId(), null, streamInfo.getStream()); + if (ssrcTransaction == null) { + logger.info("[回放控制]未找到视频流信息,设备:{}, 流ID: {}", device.getDeviceId(), streamInfo.getStream()); + return; + } + + SIPRequest request = headerProvider.createInfoRequest(device, streamInfo.getChannelId(), content.toString(), ssrcTransaction.getSipTransactionInfo()); + if (request == null) { + logger.info("[回放控制]构建Request信息失败,设备:{}, 流ID: {}", device.getDeviceId(), streamInfo.getStream()); + return; + } + + transmitRequest(device.getTransport(), request, errorEvent, okEvent); + } + + @Override + public void sendAlarmMessage(Device device, DeviceAlarm deviceAlarm) throws InvalidArgumentException, SipException, ParseException { + if (device == null) { + return; + } + logger.info("[发送 报警通知] {}/{}->{},{}", device.getDeviceId(), deviceAlarm.getChannelId(), + deviceAlarm.getLongitude(), deviceAlarm.getLatitude()); + + String characterSet = device.getCharset(); + StringBuffer deviceStatusXml = new StringBuffer(600); + deviceStatusXml.append("\r\n"); + deviceStatusXml.append("\r\n"); + deviceStatusXml.append("Alarm\r\n"); + deviceStatusXml.append("" + (int) ((Math.random() * 9 + 1) * 100000) + "\r\n"); + deviceStatusXml.append("" + deviceAlarm.getChannelId() + "\r\n"); + deviceStatusXml.append("" + deviceAlarm.getAlarmPriority() + "\r\n"); + deviceStatusXml.append("" + deviceAlarm.getAlarmMethod() + "\r\n"); + deviceStatusXml.append("" + deviceAlarm.getAlarmTime() + "\r\n"); + deviceStatusXml.append("" + deviceAlarm.getAlarmDescription() + "\r\n"); + deviceStatusXml.append("" + deviceAlarm.getLongitude() + "\r\n"); + deviceStatusXml.append("" + deviceAlarm.getLatitude() + "\r\n"); + deviceStatusXml.append("\r\n"); + deviceStatusXml.append("" + deviceAlarm.getAlarmType() + "\r\n"); + deviceStatusXml.append("\r\n"); + deviceStatusXml.append("\r\n"); + + CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId() + : udpSipProvider.getNewCallId(); + Request request = headerProvider.createMessageRequest(device, deviceStatusXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null, callIdHeader); + transmitRequest(device.getTransport(), request); + + + } } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java index a15940d7..bfc1ea9d 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java @@ -13,12 +13,13 @@ import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; import com.genersoft.iot.vmp.service.IMediaServerService; import com.genersoft.iot.vmp.service.bean.GPSMsgInfo; import com.genersoft.iot.vmp.storager.IRedisCatchStorage; +import com.genersoft.iot.vmp.utils.GitUtil; import com.genersoft.iot.vmp.utils.SerializeUtils; +import gov.nist.javax.sip.SIPConstants; import gov.nist.javax.sip.SipProviderImpl; import gov.nist.javax.sip.SipStackImpl; import gov.nist.javax.sip.message.MessageFactoryImpl; import gov.nist.javax.sip.message.SIPRequest; -import gov.nist.javax.sip.stack.SIPDialog; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -26,17 +27,15 @@ import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.DependsOn; import org.springframework.context.annotation.Lazy; import org.springframework.lang.Nullable; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import org.springframework.stereotype.Component; import org.springframework.util.ObjectUtils; import javax.sip.*; -import javax.sip.address.SipURI; import javax.sip.header.*; import javax.sip.message.Request; -import java.lang.reflect.Field; import java.text.ParseException; import java.util.ArrayList; -import java.util.HashSet; import java.util.List; @Component @@ -77,19 +76,18 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { private SubscribeHolder subscribeHolder; @Override - public boolean register(ParentPlatform parentPlatform, SipSubscribe.Event errorEvent , SipSubscribe.Event okEvent) { - return register(parentPlatform, null, null, errorEvent, okEvent, false, true); + public void register(ParentPlatform parentPlatform, SipSubscribe.Event errorEvent , SipSubscribe.Event okEvent) throws InvalidArgumentException, ParseException, SipException { + register(parentPlatform, null, null, errorEvent, okEvent, false, true); } @Override - public boolean unregister(ParentPlatform parentPlatform, SipSubscribe.Event errorEvent , SipSubscribe.Event okEvent) { - return register(parentPlatform, null, null, errorEvent, okEvent, false, false); + public void unregister(ParentPlatform parentPlatform, SipSubscribe.Event errorEvent , SipSubscribe.Event okEvent) throws InvalidArgumentException, ParseException, SipException { + register(parentPlatform, null, null, errorEvent, okEvent, false, false); } @Override - public boolean register(ParentPlatform parentPlatform, @Nullable String callId, @Nullable WWWAuthenticateHeader www, - SipSubscribe.Event errorEvent , SipSubscribe.Event okEvent, boolean registerAgain, boolean isRegister) { - try { + public void register(ParentPlatform parentPlatform, @Nullable String callId, @Nullable WWWAuthenticateHeader www, + SipSubscribe.Event errorEvent , SipSubscribe.Event okEvent, boolean registerAgain, boolean isRegister) throws SipException, InvalidArgumentException, ParseException { Request request; if (!registerAgain ) { CallIdHeader callIdHeader = null; @@ -126,23 +124,10 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { } transmitRequest(parentPlatform, request, null, okEvent); - return true; - } catch (ParseException e) { - e.printStackTrace(); - } catch (InvalidArgumentException e) { - e.printStackTrace(); - } catch (PeerUnavailableException e) { - e.printStackTrace(); - } catch (SipException e) { - e.printStackTrace(); - } - return false; } @Override - public String keepalive(ParentPlatform parentPlatform,SipSubscribe.Event errorEvent , SipSubscribe.Event okEvent) { - String callId = null; - try { + public String keepalive(ParentPlatform parentPlatform,SipSubscribe.Event errorEvent , SipSubscribe.Event okEvent) throws SipException, InvalidArgumentException, ParseException { String characterSet = parentPlatform.getCharacterSet(); StringBuffer keepaliveXml = new StringBuffer(200); keepaliveXml.append("\r\n"); @@ -163,11 +148,7 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { SipUtils.getNewViaTag(), callIdHeader); transmitRequest(parentPlatform, request, errorEvent, okEvent); - callId = callIdHeader.getCallId(); - } catch (ParseException | InvalidArgumentException | SipException e) { - e.printStackTrace(); - } - return callId; + return callIdHeader.getCallId(); } private void transmitRequest(ParentPlatform parentPlatform, Request request) throws SipException { @@ -206,39 +187,32 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { * @return */ @Override - public boolean catalogQuery(DeviceChannel channel, ParentPlatform parentPlatform, String sn, String fromTag, int size) { + public void catalogQuery(DeviceChannel channel, ParentPlatform parentPlatform, String sn, String fromTag, int size) throws SipException, InvalidArgumentException, ParseException { if ( parentPlatform ==null) { - return false; + return ; } - try { - List channels = new ArrayList<>(); - if (channel != null) { - channels.add(channel); - } - String catalogXml = getCatalogXml(channels, sn, parentPlatform, size); - - // callid - CallIdHeader callIdHeader = parentPlatform.getTransport().equalsIgnoreCase("TCP") ? tcpSipProvider.getNewCallId() - : udpSipProvider.getNewCallId(); - - Request request = headerProviderPlatformProvider.createMessageRequest(parentPlatform, catalogXml.toString(), fromTag, SipUtils.getNewViaTag(), callIdHeader); - transmitRequest(parentPlatform, request); - - } catch (SipException | ParseException | InvalidArgumentException e) { - e.printStackTrace(); - return false; + List channels = new ArrayList<>(); + if (channel != null) { + channels.add(channel); } - return true; + String catalogXml = getCatalogXml(channels, sn, parentPlatform, size); + + // callid + CallIdHeader callIdHeader = parentPlatform.getTransport().equalsIgnoreCase("TCP") ? tcpSipProvider.getNewCallId() + : udpSipProvider.getNewCallId(); + + Request request = headerProviderPlatformProvider.createMessageRequest(parentPlatform, catalogXml.toString(), fromTag, SipUtils.getNewViaTag(), callIdHeader); + transmitRequest(parentPlatform, request); + } @Override - public boolean catalogQuery(List channels, ParentPlatform parentPlatform, String sn, String fromTag) { + public void catalogQuery(List channels, ParentPlatform parentPlatform, String sn, String fromTag) throws InvalidArgumentException, ParseException, SipException { if ( parentPlatform ==null) { - return false; + return ; } sendCatalogResponse(channels, parentPlatform, sn, fromTag, 0); - return true; } private String getCatalogXml(List channels, String sn, ParentPlatform parentPlatform, int size) { String characterSet = parentPlatform.getCharacterSet(); @@ -300,30 +274,30 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { return catalogXml.toString(); } - private void sendCatalogResponse(List channels, ParentPlatform parentPlatform, String sn, String fromTag, int index) { + private void sendCatalogResponse(List channels, ParentPlatform parentPlatform, String sn, String fromTag, int index) throws SipException, InvalidArgumentException, ParseException { if (index >= channels.size()) { return; } - try { - List deviceChannels; - if (index + parentPlatform.getCatalogGroup() < channels.size()) { - deviceChannels = channels.subList(index, index + parentPlatform.getCatalogGroup()); - }else { - deviceChannels = channels.subList(index, channels.size()); - } - String catalogXml = getCatalogXml(deviceChannels, sn, parentPlatform, channels.size()); - // callid - CallIdHeader callIdHeader = parentPlatform.getTransport().equalsIgnoreCase("TCP") ? tcpSipProvider.getNewCallId() - : udpSipProvider.getNewCallId(); - - Request request = headerProviderPlatformProvider.createMessageRequest(parentPlatform, catalogXml, fromTag, SipUtils.getNewViaTag(), callIdHeader); - transmitRequest(parentPlatform, request, null, eventResult -> { - int indexNext = index + parentPlatform.getCatalogGroup(); - sendCatalogResponse(channels, parentPlatform, sn, fromTag, indexNext); - }); - } catch (SipException | ParseException | InvalidArgumentException e) { - e.printStackTrace(); + List deviceChannels; + if (index + parentPlatform.getCatalogGroup() < channels.size()) { + deviceChannels = channels.subList(index, index + parentPlatform.getCatalogGroup()); + }else { + deviceChannels = channels.subList(index, channels.size()); } + String catalogXml = getCatalogXml(deviceChannels, sn, parentPlatform, channels.size()); + // callid + CallIdHeader callIdHeader = parentPlatform.getTransport().equalsIgnoreCase("TCP") ? tcpSipProvider.getNewCallId() + : udpSipProvider.getNewCallId(); + + Request request = headerProviderPlatformProvider.createMessageRequest(parentPlatform, catalogXml, fromTag, SipUtils.getNewViaTag(), callIdHeader); + transmitRequest(parentPlatform, request, null, eventResult -> { + int indexNext = index + parentPlatform.getCatalogGroup(); + try { + sendCatalogResponse(channels, parentPlatform, sn, fromTag, indexNext); + } catch (SipException | InvalidArgumentException | ParseException e) { + logger.error("[命令发送失败] 国标级联 目录查询回复: {}", e.getMessage()); + } + }); } /** @@ -334,36 +308,29 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { * @return */ @Override - public boolean deviceInfoResponse(ParentPlatform parentPlatform, String sn, String fromTag) { + public void deviceInfoResponse(ParentPlatform parentPlatform, String sn, String fromTag) throws SipException, InvalidArgumentException, ParseException { if (parentPlatform == null) { - return false; + return; } - try { - String characterSet = parentPlatform.getCharacterSet(); - StringBuffer deviceInfoXml = new StringBuffer(600); - deviceInfoXml.append("\r\n"); - deviceInfoXml.append("\r\n"); - deviceInfoXml.append("DeviceInfo\r\n"); - deviceInfoXml.append("" +sn + "\r\n"); - deviceInfoXml.append("" + parentPlatform.getDeviceGBId() + "\r\n"); - deviceInfoXml.append("" + parentPlatform.getName() + "\r\n"); - deviceInfoXml.append("wvp\r\n"); - deviceInfoXml.append("wvp-28181-2.0\r\n"); - deviceInfoXml.append("2.0.202107\r\n"); - deviceInfoXml.append("OK\r\n"); - deviceInfoXml.append("\r\n"); + String characterSet = parentPlatform.getCharacterSet(); + StringBuffer deviceInfoXml = new StringBuffer(600); + deviceInfoXml.append("\r\n"); + deviceInfoXml.append("\r\n"); + deviceInfoXml.append("DeviceInfo\r\n"); + deviceInfoXml.append("" +sn + "\r\n"); + deviceInfoXml.append("" + parentPlatform.getDeviceGBId() + "\r\n"); + deviceInfoXml.append("" + parentPlatform.getName() + "\r\n"); + deviceInfoXml.append("wvp\r\n"); + deviceInfoXml.append("wvp-28181-2.0\r\n"); + deviceInfoXml.append("2.0.202107\r\n"); + deviceInfoXml.append("OK\r\n"); + deviceInfoXml.append("\r\n"); - CallIdHeader callIdHeader = parentPlatform.getTransport().equalsIgnoreCase("TCP") ? tcpSipProvider.getNewCallId() - : udpSipProvider.getNewCallId(); + CallIdHeader callIdHeader = parentPlatform.getTransport().equalsIgnoreCase("TCP") ? tcpSipProvider.getNewCallId() + : udpSipProvider.getNewCallId(); - Request request = headerProviderPlatformProvider.createMessageRequest(parentPlatform, deviceInfoXml.toString(), fromTag, SipUtils.getNewViaTag(), callIdHeader); - transmitRequest(parentPlatform, request); - - } catch (SipException | ParseException | InvalidArgumentException e) { - e.printStackTrace(); - return false; - } - return true; + Request request = headerProviderPlatformProvider.createMessageRequest(parentPlatform, deviceInfoXml.toString(), fromTag, SipUtils.getNewViaTag(), callIdHeader); + transmitRequest(parentPlatform, request); } /** @@ -374,129 +341,103 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { * @return */ @Override - public boolean deviceStatusResponse(ParentPlatform parentPlatform, String sn, String fromTag) { + public void deviceStatusResponse(ParentPlatform parentPlatform, String sn, String fromTag) throws SipException, InvalidArgumentException, ParseException { if (parentPlatform == null) { - return false; + return ; } - try { - String characterSet = parentPlatform.getCharacterSet(); - StringBuffer deviceStatusXml = new StringBuffer(600); - deviceStatusXml.append("\r\n"); - deviceStatusXml.append("\r\n"); - deviceStatusXml.append("DeviceStatus\r\n"); - deviceStatusXml.append("" +sn + "\r\n"); - deviceStatusXml.append("" + parentPlatform.getDeviceGBId() + "\r\n"); - deviceStatusXml.append("OK\r\n"); - deviceStatusXml.append("ONLINE\r\n"); - deviceStatusXml.append("OK\r\n"); - deviceStatusXml.append("\r\n"); + String characterSet = parentPlatform.getCharacterSet(); + StringBuffer deviceStatusXml = new StringBuffer(600); + deviceStatusXml.append("\r\n"); + deviceStatusXml.append("\r\n"); + deviceStatusXml.append("DeviceStatus\r\n"); + deviceStatusXml.append("" +sn + "\r\n"); + deviceStatusXml.append("" + parentPlatform.getDeviceGBId() + "\r\n"); + deviceStatusXml.append("OK\r\n"); + deviceStatusXml.append("ONLINE\r\n"); + deviceStatusXml.append("OK\r\n"); + deviceStatusXml.append("\r\n"); - CallIdHeader callIdHeader = parentPlatform.getTransport().equalsIgnoreCase("TCP") ? tcpSipProvider.getNewCallId() - : udpSipProvider.getNewCallId(); + CallIdHeader callIdHeader = parentPlatform.getTransport().equalsIgnoreCase("TCP") ? tcpSipProvider.getNewCallId() + : udpSipProvider.getNewCallId(); - Request request = headerProviderPlatformProvider.createMessageRequest(parentPlatform, deviceStatusXml.toString(), fromTag, SipUtils.getNewViaTag(), callIdHeader); - transmitRequest(parentPlatform, request); + Request request = headerProviderPlatformProvider.createMessageRequest(parentPlatform, deviceStatusXml.toString(), fromTag, SipUtils.getNewViaTag(), callIdHeader); + transmitRequest(parentPlatform, request); - } catch (SipException | ParseException | InvalidArgumentException e) { - e.printStackTrace(); - return false; - } - return true; } @Override - public boolean sendNotifyMobilePosition(ParentPlatform parentPlatform, GPSMsgInfo gpsMsgInfo, SubscribeInfo subscribeInfo) { + public void sendNotifyMobilePosition(ParentPlatform parentPlatform, GPSMsgInfo gpsMsgInfo, SubscribeInfo subscribeInfo) throws InvalidArgumentException, ParseException, NoSuchFieldException, SipException, IllegalAccessException { if (parentPlatform == null) { - return false; + return; } if (logger.isDebugEnabled()) { logger.debug("[发送 移动位置订阅] {}/{}->{},{}", parentPlatform.getServerGBId(), gpsMsgInfo.getId(), gpsMsgInfo.getLng(), gpsMsgInfo.getLat()); } - try { - String characterSet = parentPlatform.getCharacterSet(); - StringBuffer deviceStatusXml = new StringBuffer(600); - deviceStatusXml.append("\r\n"); - deviceStatusXml.append("\r\n"); - deviceStatusXml.append("MobilePosition\r\n"); - deviceStatusXml.append("" + (int)((Math.random()*9+1)*100000) + "\r\n"); - deviceStatusXml.append("" + gpsMsgInfo.getId() + "\r\n"); - deviceStatusXml.append("\r\n"); - deviceStatusXml.append("" + gpsMsgInfo.getLng() + "\r\n"); - deviceStatusXml.append("" + gpsMsgInfo.getLat() + "\r\n"); - deviceStatusXml.append("" + gpsMsgInfo.getSpeed() + "\r\n"); - deviceStatusXml.append("" + gpsMsgInfo.getDirection() + "\r\n"); - deviceStatusXml.append("" + gpsMsgInfo.getAltitude() + "\r\n"); - deviceStatusXml.append("\r\n"); + String characterSet = parentPlatform.getCharacterSet(); + StringBuffer deviceStatusXml = new StringBuffer(600); + deviceStatusXml.append("\r\n"); + deviceStatusXml.append("\r\n"); + deviceStatusXml.append("MobilePosition\r\n"); + deviceStatusXml.append("" + (int)((Math.random()*9+1)*100000) + "\r\n"); + deviceStatusXml.append("" + gpsMsgInfo.getId() + "\r\n"); + deviceStatusXml.append("\r\n"); + deviceStatusXml.append("" + gpsMsgInfo.getLng() + "\r\n"); + deviceStatusXml.append("" + gpsMsgInfo.getLat() + "\r\n"); + deviceStatusXml.append("" + gpsMsgInfo.getSpeed() + "\r\n"); + deviceStatusXml.append("" + gpsMsgInfo.getDirection() + "\r\n"); + deviceStatusXml.append("" + gpsMsgInfo.getAltitude() + "\r\n"); + deviceStatusXml.append("\r\n"); - sendNotify(parentPlatform, deviceStatusXml.toString(), subscribeInfo, eventResult -> { - logger.error("发送NOTIFY通知消息失败。错误:{} {}", eventResult.statusCode, eventResult.msg); - }, null); + sendNotify(parentPlatform, deviceStatusXml.toString(), subscribeInfo, eventResult -> { + logger.error("发送NOTIFY通知消息失败。错误:{} {}", eventResult.statusCode, eventResult.msg); + }, null); - } catch (SipException | ParseException e) { - e.printStackTrace(); - return false; - } catch (NoSuchFieldException e) { - e.printStackTrace(); - } catch (IllegalAccessException e) { - e.printStackTrace(); - } catch (InvalidArgumentException e) { - e.printStackTrace(); - } - return true; } @Override - public boolean sendAlarmMessage(ParentPlatform parentPlatform, DeviceAlarm deviceAlarm) { + public void sendAlarmMessage(ParentPlatform parentPlatform, DeviceAlarm deviceAlarm) throws SipException, InvalidArgumentException, ParseException { if (parentPlatform == null) { - return false; + return; } logger.info("[发送报警通知] {}/{}->{},{}: {}", parentPlatform.getServerGBId(), deviceAlarm.getChannelId(), deviceAlarm.getLongitude(), deviceAlarm.getLatitude(), JSONObject.toJSON(deviceAlarm)); - try { - String characterSet = parentPlatform.getCharacterSet(); - StringBuffer deviceStatusXml = new StringBuffer(600); - deviceStatusXml.append("\r\n"); - deviceStatusXml.append("\r\n"); - deviceStatusXml.append("Alarm\r\n"); - deviceStatusXml.append("" + (int)((Math.random()*9+1)*100000) + "\r\n"); - deviceStatusXml.append("" + deviceAlarm.getChannelId() + "\r\n"); - deviceStatusXml.append("" + deviceAlarm.getAlarmPriority() + "\r\n"); - deviceStatusXml.append("" + deviceAlarm.getAlarmMethod() + "\r\n"); - deviceStatusXml.append("" + deviceAlarm.getAlarmTime() + "\r\n"); - deviceStatusXml.append("" + deviceAlarm.getAlarmDescription() + "\r\n"); - deviceStatusXml.append("" + deviceAlarm.getLongitude() + "\r\n"); - deviceStatusXml.append("" + deviceAlarm.getLatitude() + "\r\n"); - deviceStatusXml.append("\r\n"); - deviceStatusXml.append("" + deviceAlarm.getAlarmType() + "\r\n"); - deviceStatusXml.append("\r\n"); - deviceStatusXml.append("\r\n"); + String characterSet = parentPlatform.getCharacterSet(); + StringBuffer deviceStatusXml = new StringBuffer(600); + deviceStatusXml.append("\r\n"); + deviceStatusXml.append("\r\n"); + deviceStatusXml.append("Alarm\r\n"); + deviceStatusXml.append("" + (int)((Math.random()*9+1)*100000) + "\r\n"); + deviceStatusXml.append("" + deviceAlarm.getChannelId() + "\r\n"); + deviceStatusXml.append("" + deviceAlarm.getAlarmPriority() + "\r\n"); + deviceStatusXml.append("" + deviceAlarm.getAlarmMethod() + "\r\n"); + deviceStatusXml.append("" + deviceAlarm.getAlarmTime() + "\r\n"); + deviceStatusXml.append("" + deviceAlarm.getAlarmDescription() + "\r\n"); + deviceStatusXml.append("" + deviceAlarm.getLongitude() + "\r\n"); + deviceStatusXml.append("" + deviceAlarm.getLatitude() + "\r\n"); + deviceStatusXml.append("\r\n"); + deviceStatusXml.append("" + deviceAlarm.getAlarmType() + "\r\n"); + deviceStatusXml.append("\r\n"); + deviceStatusXml.append("\r\n"); - CallIdHeader callIdHeader = parentPlatform.getTransport().equalsIgnoreCase("TCP") ? tcpSipProvider.getNewCallId() - : udpSipProvider.getNewCallId(); + CallIdHeader callIdHeader = parentPlatform.getTransport().equalsIgnoreCase("TCP") ? tcpSipProvider.getNewCallId() + : udpSipProvider.getNewCallId(); - Request request = headerProviderPlatformProvider.createMessageRequest(parentPlatform, deviceStatusXml.toString(), SipUtils.getNewFromTag(), SipUtils.getNewViaTag(), callIdHeader); - transmitRequest(parentPlatform, request); + Request request = headerProviderPlatformProvider.createMessageRequest(parentPlatform, deviceStatusXml.toString(), SipUtils.getNewFromTag(), SipUtils.getNewViaTag(), callIdHeader); + transmitRequest(parentPlatform, request); - } catch (SipException | ParseException e) { - e.printStackTrace(); - return false; - } catch (InvalidArgumentException e) { - e.printStackTrace(); - } - return true; } @Override - public boolean sendNotifyForCatalogAddOrUpdate(String type, ParentPlatform parentPlatform, List deviceChannels, SubscribeInfo subscribeInfo, Integer index) { + public void sendNotifyForCatalogAddOrUpdate(String type, ParentPlatform parentPlatform, List deviceChannels, SubscribeInfo subscribeInfo, Integer index) throws InvalidArgumentException, ParseException, NoSuchFieldException, SipException, IllegalAccessException { if (parentPlatform == null || deviceChannels == null || deviceChannels.size() == 0 || subscribeInfo == null) { - return false; + return; } if (index == null) { index = 0; } if (index >= deviceChannels.size()) { - return true; + return; } List channels; if (index + parentPlatform.getCatalogGroup() < deviceChannels.size()) { @@ -504,32 +445,25 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { }else { channels = deviceChannels.subList(index, deviceChannels.size()); } - try { - Integer finalIndex = index; - String catalogXmlContent = getCatalogXmlContentForCatalogAddOrUpdate(parentPlatform, channels, - deviceChannels.size(), type, subscribeInfo); - sendNotify(parentPlatform, catalogXmlContent, subscribeInfo, eventResult -> { - logger.error("发送NOTIFY通知消息失败。错误:{} {}", eventResult.statusCode, eventResult.msg); - }, (eventResult -> { + Integer finalIndex = index; + String catalogXmlContent = getCatalogXmlContentForCatalogAddOrUpdate(parentPlatform, channels, + deviceChannels.size(), type, subscribeInfo); + sendNotify(parentPlatform, catalogXmlContent, subscribeInfo, eventResult -> { + logger.error("发送NOTIFY通知消息失败。错误:{} {}", eventResult.statusCode, eventResult.msg); + }, (eventResult -> { + try { sendNotifyForCatalogAddOrUpdate(type, parentPlatform, deviceChannels, subscribeInfo, finalIndex + parentPlatform.getCatalogGroup()); - })); - } catch (SipException | ParseException e) { - e.printStackTrace(); - return false; - } catch (NoSuchFieldException e) { - e.printStackTrace(); - } catch (IllegalAccessException e) { - e.printStackTrace(); - } catch (InvalidArgumentException e) { - e.printStackTrace(); - } - return true; + } catch (InvalidArgumentException | ParseException | NoSuchFieldException | SipException | + IllegalAccessException e) { + logger.error("[命令发送失败] 国标级联 NOTIFY通知: {}", e.getMessage()); + } + })); } - private ClientTransaction sendNotify(ParentPlatform parentPlatform, String catalogXmlContent, + private void sendNotify(ParentPlatform parentPlatform, String catalogXmlContent, SubscribeInfo subscribeInfo, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent ) - throws NoSuchFieldException, IllegalAccessException, SipException, ParseException, InvalidArgumentException { + throws SipException, ParseException, InvalidArgumentException { MessageFactoryImpl messageFactory = (MessageFactoryImpl) sipFactory.createMessageFactory(); String characterSet = parentPlatform.getCharacterSet(); // 设置编码, 防止中文乱码 @@ -537,50 +471,7 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { SIPRequest notifyRequest = headerProviderPlatformProvider.createNotifyRequest(parentPlatform, catalogXmlContent, subscribeInfo); - notifyRequest.getCSeqHeader().setSeqNumber(redisCatchStorage.getCSEQ()); - - ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader("Application", "MANSCDP+xml"); - notifyRequest.setContent(catalogXmlContent, contentTypeHeader); - - SubscriptionStateHeader subscriptionState = sipFactory.createHeaderFactory() - .createSubscriptionStateHeader(SubscriptionStateHeader.ACTIVE); - notifyRequest.addHeader(subscriptionState); - - EventHeader event = sipFactory.createHeaderFactory().createEventHeader(subscribeInfo.getEventType()); - if (subscribeInfo.getEventId() != null) { - event.setEventId(subscribeInfo.getEventId()); - } - notifyRequest.addHeader(event); - SipURI sipURI = (SipURI) notifyRequest.getRequestURI(); - sipURI.setHost(parentPlatform.getServerIP()); - sipURI.setPort(parentPlatform.getServerPort()); - -// ClientTransaction transaction = subscribeInfo.getClientTransaction(); -// if (transaction == null || transaction.getState().equals(TransactionState.COMPLETED)) { -// if ("TCP".equals(parentPlatform.getTransport())) { -// transaction = tcpSipProvider.getNewClientTransaction(notifyRequest); -// } else if ("UDP".equals(parentPlatform.getTransport())) { -// transaction = udpSipProvider.getNewClientTransaction(notifyRequest); -// } -// } - - ClientTransaction transaction = null; - if ("TCP".equals(parentPlatform.getTransport())) { - transaction = tcpSipProvider.getNewClientTransaction(notifyRequest); - } else if ("UDP".equals(parentPlatform.getTransport())) { - transaction = udpSipProvider.getNewClientTransaction(notifyRequest); - } - - // 添加错误订阅 - if (errorEvent != null) { - sipSubscribe.addErrorSubscribe(subscribeInfo.getRequest().getCallIdHeader().getCallId(), errorEvent); - } - // 添加订阅 - if (okEvent != null) { - sipSubscribe.addOkSubscribe(subscribeInfo.getRequest().getCallIdHeader().getCallId(), okEvent); - } - transaction.sendRequest(); - return transaction; + transmitRequest(parentPlatform, notifyRequest); } private String getCatalogXmlContentForCatalogAddOrUpdate(ParentPlatform parentPlatform, List channels, int sumNum, String type, SubscribeInfo subscribeInfo) { @@ -639,20 +530,21 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { } @Override - public boolean sendNotifyForCatalogOther(String type, ParentPlatform parentPlatform, List deviceChannels, - SubscribeInfo subscribeInfo, Integer index) { + public void sendNotifyForCatalogOther(String type, ParentPlatform parentPlatform, List deviceChannels, + SubscribeInfo subscribeInfo, Integer index) throws InvalidArgumentException, ParseException, NoSuchFieldException, SipException, IllegalAccessException { if (parentPlatform == null || deviceChannels == null || deviceChannels.size() == 0 || subscribeInfo == null) { - return false; + logger.warn("[缺少必要参数]"); + return; } if (index == null) { index = 0; } if (index >= deviceChannels.size()) { - return true; + return; } List channels; if (index + parentPlatform.getCatalogGroup() < deviceChannels.size()) { @@ -660,28 +552,19 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { }else { channels = deviceChannels.subList(index, deviceChannels.size()); } - try { - Integer finalIndex = index; - String catalogXmlContent = getCatalogXmlContentForCatalogOther(parentPlatform, channels, type); - sendNotify(parentPlatform, catalogXmlContent, subscribeInfo, eventResult -> { - logger.error("发送NOTIFY通知消息失败。错误:{} {}", eventResult.statusCode, eventResult.msg); - }, (eventResult -> { + Integer finalIndex = index; + String catalogXmlContent = getCatalogXmlContentForCatalogOther(parentPlatform, channels, type); + sendNotify(parentPlatform, catalogXmlContent, subscribeInfo, eventResult -> { + logger.error("发送NOTIFY通知消息失败。错误:{} {}", eventResult.statusCode, eventResult.msg); + }, eventResult -> { + try { sendNotifyForCatalogOther(type, parentPlatform, deviceChannels, subscribeInfo, finalIndex + parentPlatform.getCatalogGroup()); - })); - } catch (SipException e) { - e.printStackTrace(); - } catch (ParseException e) { - e.printStackTrace(); - } catch (NoSuchFieldException e) { - e.printStackTrace(); - } catch (IllegalAccessException e) { - e.printStackTrace(); - } catch (InvalidArgumentException e) { - e.printStackTrace(); - } - - return true; + } catch (InvalidArgumentException | ParseException | NoSuchFieldException | SipException | + IllegalAccessException e) { + logger.error("[命令发送失败] 国标级联 NOTIFY通知: {}", e.getMessage()); + } + }); } private String getCatalogXmlContentForCatalogOther(ParentPlatform parentPlatform, List channels, String type) { @@ -711,113 +594,81 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { return catalogXml.toString(); } @Override - public boolean recordInfo(DeviceChannel deviceChannel, ParentPlatform parentPlatform, String fromTag, RecordInfo recordInfo) { + public void recordInfo(DeviceChannel deviceChannel, ParentPlatform parentPlatform, String fromTag, RecordInfo recordInfo) throws SipException, InvalidArgumentException, ParseException { if ( parentPlatform ==null) { - return false; + return ; } - try { - String characterSet = parentPlatform.getCharacterSet(); - StringBuffer recordXml = new StringBuffer(600); - recordXml.append("\r\n"); - recordXml.append("\r\n"); - recordXml.append("RecordInfo\r\n"); - recordXml.append("" +recordInfo.getSn() + "\r\n"); - recordXml.append("" + recordInfo.getDeviceId() + "\r\n"); - recordXml.append("" + recordInfo.getSumNum() + "\r\n"); - if (recordInfo.getRecordList() == null ) { - recordXml.append("\r\n"); - }else { - recordXml.append("\r\n"); - if (recordInfo.getRecordList().size() > 0) { - for (RecordItem recordItem : recordInfo.getRecordList()) { - recordXml.append("\r\n"); - if (deviceChannel != null) { - recordXml.append("" + recordItem.getDeviceId() + "\r\n"); - recordXml.append("" + recordItem.getName() + "\r\n"); - recordXml.append("" + DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(recordItem.getStartTime()) + "\r\n"); - recordXml.append("" + DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(recordItem.getEndTime()) + "\r\n"); - recordXml.append("" + recordItem.getSecrecy() + "\r\n"); - recordXml.append("" + recordItem.getType() + "\r\n"); - if (!ObjectUtils.isEmpty(recordItem.getFileSize())) { - recordXml.append("" + recordItem.getFileSize() + "\r\n"); - } - if (!ObjectUtils.isEmpty(recordItem.getFilePath())) { - recordXml.append("" + recordItem.getFilePath() + "\r\n"); - } + String characterSet = parentPlatform.getCharacterSet(); + StringBuffer recordXml = new StringBuffer(600); + recordXml.append("\r\n"); + recordXml.append("\r\n"); + recordXml.append("RecordInfo\r\n"); + recordXml.append("" +recordInfo.getSn() + "\r\n"); + recordXml.append("" + recordInfo.getDeviceId() + "\r\n"); + recordXml.append("" + recordInfo.getSumNum() + "\r\n"); + if (recordInfo.getRecordList() == null ) { + recordXml.append("\r\n"); + }else { + recordXml.append("\r\n"); + if (recordInfo.getRecordList().size() > 0) { + for (RecordItem recordItem : recordInfo.getRecordList()) { + recordXml.append("\r\n"); + if (deviceChannel != null) { + recordXml.append("" + recordItem.getDeviceId() + "\r\n"); + recordXml.append("" + recordItem.getName() + "\r\n"); + recordXml.append("" + DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(recordItem.getStartTime()) + "\r\n"); + recordXml.append("" + DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(recordItem.getEndTime()) + "\r\n"); + recordXml.append("" + recordItem.getSecrecy() + "\r\n"); + recordXml.append("" + recordItem.getType() + "\r\n"); + if (!ObjectUtils.isEmpty(recordItem.getFileSize())) { + recordXml.append("" + recordItem.getFileSize() + "\r\n"); + } + if (!ObjectUtils.isEmpty(recordItem.getFilePath())) { + recordXml.append("" + recordItem.getFilePath() + "\r\n"); } - recordXml.append("\r\n"); } + recordXml.append("\r\n"); } } - - recordXml.append("\r\n"); - recordXml.append("\r\n"); - - // callid - CallIdHeader callIdHeader = parentPlatform.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId() - : udpSipProvider.getNewCallId(); - Request request = headerProviderPlatformProvider.createMessageRequest(parentPlatform, recordXml.toString(), fromTag, SipUtils.getNewViaTag(), callIdHeader); - transmitRequest(parentPlatform, request); - - } catch (SipException | ParseException | InvalidArgumentException e) { - e.printStackTrace(); - return false; - } - return true; - } - - @Override - public boolean sendMediaStatusNotify(ParentPlatform platform, SendRtpItem sendRtpItem) { - if (sendRtpItem == null) { - return false; - } - if (platform == null) { - return false; } - try{ - - String characterSet = platform.getCharacterSet(); - StringBuffer mediaStatusXml = new StringBuffer(200); - mediaStatusXml.append("\r\n"); - mediaStatusXml.append("\r\n"); - mediaStatusXml.append("MediaStatus\r\n"); - mediaStatusXml.append("" + (int)((Math.random()*9+1)*100000) + "\r\n"); - mediaStatusXml.append("" + sendRtpItem.getChannelId() + "\r\n"); - mediaStatusXml.append("121\r\n"); - mediaStatusXml.append("\r\n"); - - SIPRequest messageRequest = (SIPRequest)headerProviderPlatformProvider.createMessageRequest(platform, mediaStatusXml.toString(), - sendRtpItem); - - ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader("Application", "MANSCDP+xml"); - messageRequest.setContent(mediaStatusXml.toString(), contentTypeHeader); - SipURI sipURI = (SipURI) messageRequest.getRequestURI(); - sipURI.setHost(platform.getServerIP()); - sipURI.setPort(platform.getServerPort()); - ClientTransaction clientTransaction; - if ("TCP".equals(platform.getTransport())) { - clientTransaction = tcpSipProvider.getNewClientTransaction(messageRequest); - }else { - clientTransaction = udpSipProvider.getNewClientTransaction(messageRequest); - } - clientTransaction.sendRequest(); - } catch (SipException e) { - e.printStackTrace(); - return false; - } catch (ParseException e) { - e.printStackTrace(); - return false; - } catch (InvalidArgumentException e) { - throw new RuntimeException(e); - } - return true; + recordXml.append("\r\n"); + recordXml.append("\r\n"); + // callid + CallIdHeader callIdHeader = parentPlatform.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId() + : udpSipProvider.getNewCallId(); + Request request = headerProviderPlatformProvider.createMessageRequest(parentPlatform, recordXml.toString(), fromTag, SipUtils.getNewViaTag(), callIdHeader); + transmitRequest(parentPlatform, request); } @Override - public void streamByeCmd(ParentPlatform platform, String callId) { + public void sendMediaStatusNotify(ParentPlatform platform, SendRtpItem sendRtpItem) throws SipException, InvalidArgumentException, ParseException { + if (sendRtpItem == null || platform == null) { + return; + } + + + String characterSet = platform.getCharacterSet(); + StringBuffer mediaStatusXml = new StringBuffer(200); + mediaStatusXml.append("\r\n"); + mediaStatusXml.append("\r\n"); + mediaStatusXml.append("MediaStatus\r\n"); + mediaStatusXml.append("" + (int)((Math.random()*9+1)*100000) + "\r\n"); + mediaStatusXml.append("" + sendRtpItem.getChannelId() + "\r\n"); + mediaStatusXml.append("121\r\n"); + mediaStatusXml.append("\r\n"); + + SIPRequest messageRequest = (SIPRequest)headerProviderPlatformProvider.createMessageRequest(platform, mediaStatusXml.toString(), + sendRtpItem); + + transmitRequest(platform, messageRequest); + + } + + @Override + public void streamByeCmd(ParentPlatform platform, String callId) throws SipException, InvalidArgumentException, ParseException { if (platform == null) { return; } @@ -828,7 +679,7 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { } @Override - public void streamByeCmd(ParentPlatform platform, SendRtpItem sendRtpItem) { + public void streamByeCmd(ParentPlatform platform, SendRtpItem sendRtpItem) throws SipException, InvalidArgumentException, ParseException { if (sendRtpItem == null ) { logger.info("[向上级发送BYE], sendRtpItem 为NULL"); return; @@ -844,25 +695,10 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { mediaServerService.releaseSsrc(mediaServerItem.getId(), sendRtpItem.getSsrc()); zlmrtpServerFactory.closeRTPServer(mediaServerItem, sendRtpItem.getStreamId()); } - try { - - SIPRequest byeRequest = headerProviderPlatformProvider.createByeRequest(platform, sendRtpItem); - if (byeRequest == null) { - logger.warn("[向上级发送bye]:无法创建 byeRequest"); - } - ClientTransaction clientTransaction; - if ("TCP".equals(platform.getTransport())) { - clientTransaction = tcpSipProvider.getNewClientTransaction(byeRequest); - } else { - clientTransaction = udpSipProvider.getNewClientTransaction(byeRequest); - } - clientTransaction.sendRequest(); - } catch (SipException e) { - e.printStackTrace(); - } catch (ParseException e) { - e.printStackTrace(); - } catch (InvalidArgumentException e) { - throw new RuntimeException(e); + SIPRequest byeRequest = headerProviderPlatformProvider.createByeRequest(platform, sendRtpItem); + if (byeRequest == null) { + logger.warn("[向上级发送bye]:无法创建 byeRequest"); } + transmitRequest(platform,byeRequest); } } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/SIPRequestProcessorParent.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/SIPRequestProcessorParent.java index c12d0df9..8c6ab995 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/SIPRequestProcessorParent.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/SIPRequestProcessorParent.java @@ -7,6 +7,7 @@ import gov.nist.javax.sip.SipStackImpl; import gov.nist.javax.sip.message.SIPRequest; import gov.nist.javax.sip.message.SIPResponse; import gov.nist.javax.sip.stack.SIPServerTransaction; +import gov.nist.javax.sip.stack.SIPServerTransactionImpl; import org.apache.commons.lang3.ArrayUtils; import org.dom4j.Document; import org.dom4j.DocumentException; @@ -57,7 +58,7 @@ public abstract class SIPRequestProcessorParent { */ public ServerTransaction getServerTransaction(RequestEvent evt) { Request request = evt.getRequest(); - ServerTransaction serverTransaction = evt.getServerTransaction(); + SIPServerTransactionImpl serverTransaction = (SIPServerTransactionImpl)evt.getServerTransaction(); // 判断TCP还是UDP boolean isTcp = false; ViaHeader reqViaHeader = (ViaHeader) request.getHeader(ViaHeader.NAME); @@ -65,28 +66,28 @@ public abstract class SIPRequestProcessorParent { if (transport.equalsIgnoreCase("TCP")) { isTcp = true; } - + if (serverTransaction != null && serverTransaction.getOriginalRequest() == null) { + serverTransaction.setOriginalRequest((SIPRequest) evt.getRequest()); + } if (serverTransaction == null) { try { if (isTcp) { SipStackImpl stack = (SipStackImpl)tcpSipProvider.getSipStack(); - serverTransaction = (SIPServerTransaction) stack.findTransaction((SIPRequest)request, true); + serverTransaction = (SIPServerTransactionImpl) stack.findTransaction((SIPRequest)request, true); if (serverTransaction == null) { - serverTransaction = tcpSipProvider.getNewServerTransaction(request); + serverTransaction = (SIPServerTransactionImpl)tcpSipProvider.getNewServerTransaction(request); } } else { SipStackImpl stack = (SipStackImpl)udpSipProvider.getSipStack(); - serverTransaction = (SIPServerTransaction) stack.findTransaction((SIPRequest)request, true); + serverTransaction = (SIPServerTransactionImpl) stack.findTransaction((SIPRequest)request, true); if (serverTransaction == null) { - serverTransaction = udpSipProvider.getNewServerTransaction(request); + serverTransaction = (SIPServerTransactionImpl)udpSipProvider.getNewServerTransaction(request); } } } catch (TransactionAlreadyExistsException e) { logger.error(e.getMessage()); } catch (TransactionUnavailableException e) { logger.error(e.getMessage()); - }finally { - } } return serverTransaction; diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/AckRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/AckRequestProcessor.java index 33cc6e6d..8acf621f 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/AckRequestProcessor.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/AckRequestProcessor.java @@ -23,12 +23,15 @@ import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; +import javax.sip.InvalidArgumentException; import javax.sip.RequestEvent; +import javax.sip.SipException; import javax.sip.address.SipURI; import javax.sip.header.CallIdHeader; import javax.sip.header.FromHeader; import javax.sip.header.HeaderAddress; import javax.sip.header.ToHeader; +import java.text.ParseException; import java.util.*; /** @@ -95,8 +98,8 @@ public class AckRequestProcessor extends SIPRequestProcessorParent implements In SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(platformGbId, channelId, null, callIdHeader.getCallId()); String is_Udp = sendRtpItem.isTcp() ? "0" : "1"; MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId()); - logger.info("收到ACK,rtp/{}开始向上级推流, 目标 {}:{},SSRC={}", sendRtpItem.getStreamId(), sendRtpItem.getIp(), sendRtpItem.getPort(), sendRtpItem.getSsrc()); - Map param = new HashMap<>(); + logger.info("收到ACK,rtp/{}开始向上级推流, 目标={}:{},SSRC={}", sendRtpItem.getStreamId(), sendRtpItem.getIp(), sendRtpItem.getPort(), sendRtpItem.getSsrc()); + Map param = new HashMap<>(12); param.put("vhost","__defaultVhost__"); param.put("app",sendRtpItem.getApp()); param.put("stream",sendRtpItem.getStreamId()); @@ -139,7 +142,11 @@ public class AckRequestProcessor extends SIPRequestProcessorParent implements In // TODO 可能是语音对讲 }else { // 向上级平台 - commanderForPlatform.streamByeCmd(parentPlatform, callIdHeader.getCallId()); + try { + commanderForPlatform.streamByeCmd(parentPlatform, callIdHeader.getCallId()); + } catch (SipException | InvalidArgumentException | ParseException e) { + logger.error("[命令发送失败] 国标级联 发送BYE: {}", e.getMessage()); + } } } } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/ByeRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/ByeRequestProcessor.java index 4211417b..8bf49317 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/ByeRequestProcessor.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/ByeRequestProcessor.java @@ -1,6 +1,7 @@ package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl; import com.genersoft.iot.vmp.common.StreamInfo; +import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException; import com.genersoft.iot.vmp.gb28181.bean.Device; import com.genersoft.iot.vmp.gb28181.bean.InviteStreamType; import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem; @@ -12,12 +13,11 @@ import com.genersoft.iot.vmp.gb28181.transmit.event.request.ISIPRequestProcessor import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent; import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory; import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; +import com.genersoft.iot.vmp.service.IDeviceService; import com.genersoft.iot.vmp.service.IMediaServerService; import com.genersoft.iot.vmp.service.bean.MessageForPushChannel; import com.genersoft.iot.vmp.storager.IRedisCatchStorage; import com.genersoft.iot.vmp.storager.IVideoManagerStorage; -import com.genersoft.iot.vmp.utils.SerializeUtils; -import gov.nist.javax.sip.stack.SIPDialog; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.InitializingBean; @@ -50,6 +50,9 @@ public class ByeRequestProcessor extends SIPRequestProcessorParent implements In @Autowired private IRedisCatchStorage redisCatchStorage; + @Autowired + private IDeviceService deviceService; + @Autowired private IVideoManagerStorage storager; @@ -77,9 +80,13 @@ public class ByeRequestProcessor extends SIPRequestProcessorParent implements In */ @Override public void process(RequestEvent evt) { + try { responseAck(getServerTransaction(evt), Response.OK); - CallIdHeader callIdHeader = (CallIdHeader)evt.getRequest().getHeader(CallIdHeader.NAME); + } catch (SipException | InvalidArgumentException | ParseException e) { + logger.error("[回复BYE信息失败],{}", e.getMessage()); + } + CallIdHeader callIdHeader = (CallIdHeader)evt.getRequest().getHeader(CallIdHeader.NAME); String platformGbId = ((SipURI) ((HeaderAddress) evt.getRequest().getHeader(FromHeader.NAME)).getAddress().getURI()).getUser(); String channelId = ((SipURI) ((HeaderAddress) evt.getRequest().getHeader(ToHeader.NAME)).getAddress().getURI()).getUser(); SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(platformGbId, channelId, null, callIdHeader.getCallId()); @@ -99,7 +106,17 @@ public class ByeRequestProcessor extends SIPRequestProcessorParent implements In if (totalReaderCount <= 0) { logger.info("[收到bye] {} 无其它观看者,通知设备停止推流", streamId); if (sendRtpItem.getPlayType().equals(InviteStreamType.PLAY)) { - cmder.streamByeCmd(sendRtpItem.getDeviceId(), channelId, streamId, null); + Device device = deviceService.queryDevice(sendRtpItem.getDeviceId()); + if (device == null) { + logger.info("[收到bye] {} 通知设备停止推流时未找到设备信息", streamId); + } + try { + logger.warn("[停止点播] {}/{}", sendRtpItem.getDeviceId(), channelId); + cmder.streamByeCmd(device, channelId, streamId, null); + } catch (InvalidArgumentException | ParseException | SipException | + SsrcTransactionNotFoundException e) { + logger.error("[收到bye] {} 无其它观看者,通知设备停止推流, 发送BYE失败 {}",streamId, e.getMessage()); + } } if (sendRtpItem.getPlayType().equals(InviteStreamType.PUSH)) { MessageForPushChannel messageForPushChannel = MessageForPushChannel.getInstance(0, @@ -120,8 +137,7 @@ public class ByeRequestProcessor extends SIPRequestProcessorParent implements In } SsrcTransaction ssrcTransactionForPlay = streamSession.getSsrcTransaction(device.getDeviceId(), channelId, "play", null); if (ssrcTransactionForPlay != null){ - SIPDialog dialogForPlay = (SIPDialog) SerializeUtils.deSerialize(ssrcTransactionForPlay.getDialog()); - if (dialogForPlay.getCallId().getCallId().equals(callIdHeader.getCallId())){ + if (ssrcTransactionForPlay.getCallId().equals(callIdHeader.getCallId())){ // 释放ssrc MediaServerItem mediaServerItem = mediaServerService.getOne(ssrcTransactionForPlay.getMediaServerId()); if (mediaServerItem != null) { @@ -140,12 +156,6 @@ public class ByeRequestProcessor extends SIPRequestProcessorParent implements In streamSession.remove(device.getDeviceId(), channelId, ssrcTransactionForPlayBack.getStream()); } } - } catch (SipException e) { - e.printStackTrace(); - } catch (InvalidArgumentException e) { - e.printStackTrace(); - } catch (ParseException e) { - e.printStackTrace(); - } + } } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java index ff3c78f0..09436edb 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java @@ -341,7 +341,11 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements logger.info("Ack 等待超时"); mediaServerService.releaseSsrc(mediaServerItemInUSe.getId(), ssrc); // 回复bye - cmderFroPlatform.streamByeCmd(platform, callIdHeader.getCallId()); + try { + cmderFroPlatform.streamByeCmd(platform, callIdHeader.getCallId()); + } catch (SipException | InvalidArgumentException | ParseException e) { + logger.error("[命令发送失败] 国标级联 发送BYE: {}", e.getMessage()); + } }, 60 * 1000); responseSdpAck(serverTransaction, content.toString(), platform); diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/info/InfoRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/info/InfoRequestProcessor.java index 0b6ced0f..b5f16ac9 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/info/InfoRequestProcessor.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/info/InfoRequestProcessor.java @@ -93,7 +93,9 @@ public class InfoRequestProcessor extends SIPRequestProcessorParent implements I responseAck(serverTransaction, Response.NOT_FOUND, "device "+ deviceId +" not found"); logger.warn("[设备未找到 ]: {}", deviceId); if (sipSubscribe.getErrorSubscribe(callIdHeader.getCallId()) != null){ - SipSubscribe.EventResult eventResult = new SipSubscribe.EventResult(new DeviceNotFoundEvent(evt.getDialog())); + DeviceNotFoundEvent deviceNotFoundEvent = new DeviceNotFoundEvent(evt.getDialog()); + deviceNotFoundEvent.setCallId(callIdHeader.getCallId()); + SipSubscribe.EventResult eventResult = new SipSubscribe.EventResult(deviceNotFoundEvent); sipSubscribe.getErrorSubscribe(callIdHeader.getCallId()).response(eventResult); }; }else { diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/MessageRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/MessageRequestProcessor.java index bd4ca650..f74c250b 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/MessageRequestProcessor.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/MessageRequestProcessor.java @@ -89,8 +89,6 @@ public class MessageRequestProcessor extends SIPRequestProcessorParent implement ParentPlatform parentPlatform = storage.queryParentPlatByServerGBId(deviceId); try { if (device != null && parentPlatform != null) { - - logger.warn("[重复]平台与设备编号重复:{}", deviceId); SIPRequest request = (SIPRequest) evt.getRequest(); String hostAddress = request.getRemoteAddress().getHostAddress(); int remotePort = request.getRemotePort(); @@ -105,7 +103,9 @@ public class MessageRequestProcessor extends SIPRequestProcessorParent implement responseAck(serverTransaction, Response.NOT_FOUND, "device "+ deviceId +" not found"); logger.warn("[设备未找到 ]: {}", deviceId); if (sipSubscribe.getErrorSubscribe(callIdHeader.getCallId()) != null){ - SipSubscribe.EventResult eventResult = new SipSubscribe.EventResult(new DeviceNotFoundEvent(evt.getDialog())); + DeviceNotFoundEvent deviceNotFoundEvent = new DeviceNotFoundEvent(evt.getDialog()); + deviceNotFoundEvent.setCallId(callIdHeader.getCallId()); + SipSubscribe.EventResult eventResult = new SipSubscribe.EventResult(deviceNotFoundEvent); sipSubscribe.getErrorSubscribe(callIdHeader.getCallId()).response(eventResult); }; }else { diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/control/cmd/DeviceControlQueryMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/control/cmd/DeviceControlQueryMessageHandler.java index 094e656b..855ad3b2 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/control/cmd/DeviceControlQueryMessageHandler.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/control/cmd/DeviceControlQueryMessageHandler.java @@ -16,6 +16,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import org.springframework.stereotype.Component; import org.springframework.util.ObjectUtils; import org.springframework.util.StringUtils; @@ -48,6 +50,10 @@ public class DeviceControlQueryMessageHandler extends SIPRequestProcessorParent @Autowired private SIPCommanderFroPlatform cmderFroPlatform; + @Qualifier("taskExecutor") + @Autowired + private ThreadPoolTaskExecutor taskExecutor; + @Override public void afterPropertiesSet() throws Exception { controlMessageHandler.addHandler(cmdType, this); @@ -71,34 +77,30 @@ public class DeviceControlQueryMessageHandler extends SIPRequestProcessorParent if (parentPlatform.getServerGBId().equals(targetGBId)) { // 远程启动本平台:需要在重新启动程序后先对SipStack解绑 logger.info("执行远程启动本平台命令"); - cmderFroPlatform.unregister(parentPlatform, null, null); - - Thread restartThread = new Thread(new Runnable() { - @Override - public void run() { - try { - Thread.sleep(3000); - SipProvider up = (SipProvider) SpringBeanFactory.getBean("udpSipProvider"); - SipStackImpl stack = (SipStackImpl)up.getSipStack(); - stack.stop(); - Iterator listener = stack.getListeningPoints(); - while (listener.hasNext()) { - stack.deleteListeningPoint((ListeningPoint) listener.next()); - } - Iterator providers = stack.getSipProviders(); - while (providers.hasNext()) { - stack.deleteSipProvider((SipProvider) providers.next()); - } - VManageBootstrap.restart(); - } catch (InterruptedException ignored) { - } catch (ObjectInUseException e) { - e.printStackTrace(); + try { + cmderFroPlatform.unregister(parentPlatform, null, null); + } catch (InvalidArgumentException | ParseException | SipException e) { + logger.error("[命令发送失败] 国标级联 注销: {}", e.getMessage()); + } + taskExecutor.execute(()->{ + try { + Thread.sleep(3000); + SipProvider up = (SipProvider) SpringBeanFactory.getBean("udpSipProvider"); + SipStackImpl stack = (SipStackImpl)up.getSipStack(); + stack.stop(); + Iterator listener = stack.getListeningPoints(); + while (listener.hasNext()) { + stack.deleteListeningPoint((ListeningPoint) listener.next()); } + Iterator providers = stack.getSipProviders(); + while (providers.hasNext()) { + stack.deleteSipProvider((SipProvider) providers.next()); + } + VManageBootstrap.restart(); + } catch (InterruptedException | ObjectInUseException e) { + logger.error("[任务执行失败] 服务重启: {}", e.getMessage()); } }); - - restartThread.setDaemon(false); - restartThread.start(); } else { // 远程启动指定设备 } @@ -111,37 +113,29 @@ public class DeviceControlQueryMessageHandler extends SIPRequestProcessorParent try { responseAck(serverTransaction, Response.NOT_FOUND); return; - } catch (SipException e) { - e.printStackTrace(); - } catch (InvalidArgumentException e) { - e.printStackTrace(); - } catch (ParseException e) { - e.printStackTrace(); + } catch (SipException | InvalidArgumentException | ParseException e) { + logger.error("[命令发送失败] 错误信息: {}", e.getMessage()); } } - cmder.fronEndCmd(deviceForPlatform, channelId, cmdString, eventResult -> { - // 失败的回复 - try { - responseAck(serverTransaction, eventResult.statusCode, eventResult.msg); - } catch (SipException e) { - e.printStackTrace(); - } catch (InvalidArgumentException e) { - e.printStackTrace(); - } catch (ParseException e) { - e.printStackTrace(); - } - }, eventResult -> { - // 成功的回复 - try { - responseAck(serverTransaction, eventResult.statusCode); - } catch (SipException e) { - e.printStackTrace(); - } catch (InvalidArgumentException e) { - e.printStackTrace(); - } catch (ParseException e) { - e.printStackTrace(); - } - }); + try { + cmder.fronEndCmd(deviceForPlatform, channelId, cmdString, eventResult -> { + // 失败的回复 + try { + responseAck(serverTransaction, eventResult.statusCode, eventResult.msg); + } catch (SipException | InvalidArgumentException | ParseException e) { + logger.error("[命令发送失败] 云台/前端回复: {}", e.getMessage()); + } + }, eventResult -> { + // 成功的回复 + try { + responseAck(serverTransaction, eventResult.statusCode); + } catch (SipException | InvalidArgumentException | ParseException e) { + logger.error("[命令发送失败] 云台/前端回复: {}", e.getMessage()); + } + }); + } catch (InvalidArgumentException | SipException | ParseException e) { + logger.error("[命令发送失败] 云台/前端: {}", e.getMessage()); + } } } } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/MediaStatusNotifyMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/MediaStatusNotifyMessageHandler.java index 332fc671..98d42d6e 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/MediaStatusNotifyMessageHandler.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/MediaStatusNotifyMessageHandler.java @@ -1,6 +1,7 @@ package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.notify.cmd; import com.genersoft.iot.vmp.common.StreamInfo; +import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException; import com.genersoft.iot.vmp.gb28181.bean.Device; import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem; @@ -89,7 +90,12 @@ public class MediaStatusNotifyMessageHandler extends SIPRequestProcessorParent i // 先从会话内查找 SsrcTransaction ssrcTransaction = sessionManager.getSsrcTransaction(null, null, callIdHeader.getCallId(), null); if (ssrcTransaction != null) { // 兼容海康 媒体通知 消息from字段不是设备ID的问题 - cmder.streamByeCmd(device.getDeviceId(), ssrcTransaction.getChannelId(), null, callIdHeader.getCallId()); + + try { + cmder.streamByeCmd(device, ssrcTransaction.getChannelId(), null, callIdHeader.getCallId()); + } catch (InvalidArgumentException | ParseException | SsrcTransactionNotFoundException | SipException e) { + logger.error("[录像流]推送完毕,收到关流通知, 发送BYE失败 {}", e.getMessage()); + } // 如果级联播放,需要给上级发送此通知 TODO 多个上级同时观看一个下级 可能存在停错的问题,需要将点播CallId进行上下级绑定 SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(null, ssrcTransaction.getChannelId(), null, null); @@ -99,7 +105,11 @@ public class MediaStatusNotifyMessageHandler extends SIPRequestProcessorParent i logger.warn("[级联消息发送]:发送MediaStatus发现上级平台{}不存在", sendRtpItem.getPlatformId()); return; } - sipCommanderFroPlatform.sendMediaStatusNotify(parentPlatform, sendRtpItem); + try { + sipCommanderFroPlatform.sendMediaStatusNotify(parentPlatform, sendRtpItem); + } catch (SipException | InvalidArgumentException | ParseException e) { + logger.error("[命令发送失败] 国标级联 录像播放完毕: {}", e.getMessage()); + } } } } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/DeviceInfoQueryMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/DeviceInfoQueryMessageHandler.java index 27d9200b..3567939e 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/DeviceInfoQueryMessageHandler.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/DeviceInfoQueryMessageHandler.java @@ -49,14 +49,14 @@ public class DeviceInfoQueryMessageHandler extends SIPRequestProcessorParent imp try { // 回复200 OK responseAck(getServerTransaction(evt), Response.OK); - } catch (SipException e) { - e.printStackTrace(); - } catch (InvalidArgumentException e) { - e.printStackTrace(); - } catch (ParseException e) { - e.printStackTrace(); + } catch (SipException | InvalidArgumentException | ParseException e) { + logger.error("[命令发送失败] DeviceInfo查询回复: {}", e.getMessage()); } String sn = rootElement.element("SN").getText(); - cmderFroPlatform.deviceInfoResponse(parentPlatform, sn, fromHeader.getTag()); + try { + cmderFroPlatform.deviceInfoResponse(parentPlatform, sn, fromHeader.getTag()); + } catch (SipException | InvalidArgumentException | ParseException e) { + logger.error("[命令发送失败] 国标级联 DeviceInfo查询回复: {}", e.getMessage()); + } } } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/DeviceStatusQueryMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/DeviceStatusQueryMessageHandler.java index 05d2714f..bb6ff785 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/DeviceStatusQueryMessageHandler.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/DeviceStatusQueryMessageHandler.java @@ -62,14 +62,14 @@ public class DeviceStatusQueryMessageHandler extends SIPRequestProcessorParent i // 回复200 OK try { responseAck(getServerTransaction(evt), Response.OK); - } catch (SipException e) { - e.printStackTrace(); - } catch (InvalidArgumentException e) { - e.printStackTrace(); - } catch (ParseException e) { - e.printStackTrace(); + } catch (SipException | InvalidArgumentException | ParseException e) { + logger.error("[命令发送失败] 国标级联 DeviceStatus查询回复200OK: {}", e.getMessage()); } String sn = rootElement.element("SN").getText(); - cmderFroPlatform.deviceStatusResponse(parentPlatform, sn, fromHeader.getTag()); + try { + cmderFroPlatform.deviceStatusResponse(parentPlatform, sn, fromHeader.getTag()); + } catch (SipException | InvalidArgumentException | ParseException e) { + logger.error("[命令发送失败] 国标级联 DeviceStatus查询回复: {}", e.getMessage()); + } } } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/RecordInfoQueryMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/RecordInfoQueryMessageHandler.java index 49e04e9b..8c1365a4 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/RecordInfoQueryMessageHandler.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/RecordInfoQueryMessageHandler.java @@ -103,53 +103,45 @@ public class RecordInfoQueryMessageHandler extends SIPRequestProcessorParent imp DeviceChannel deviceChannel = storager.queryChannelInParentPlatform(parentPlatform.getServerGBId(), channelId); // 接收录像数据 recordEndEventListener.addEndEventHandler(deviceChannel.getDeviceId(), channelId, (recordInfo)->{ - cmderFroPlatform.recordInfo(deviceChannel, parentPlatform, fromHeader.getTag(), recordInfo); + try { + cmderFroPlatform.recordInfo(deviceChannel, parentPlatform, fromHeader.getTag(), recordInfo); + } catch (SipException | InvalidArgumentException | ParseException e) { + logger.error("[命令发送失败] 国标级联 回复录像数据: {}", e.getMessage()); + } }); - commander.recordInfoQuery(device, channelId, DateUtil.ISO8601Toyyyy_MM_dd_HH_mm_ss(startTime), - DateUtil.ISO8601Toyyyy_MM_dd_HH_mm_ss(endTime), sn, secrecy, type, (eventResult -> { - // 回复200 OK - try { - responseAck(serverTransaction, Response.OK); - } catch (SipException e) { - e.printStackTrace(); - } catch (InvalidArgumentException e) { - e.printStackTrace(); - } catch (ParseException e) { - e.printStackTrace(); - } - }),(eventResult -> { - // 查询失败 - try { - responseAck(serverTransaction, eventResult.statusCode, eventResult.msg); - } catch (SipException e) { - e.printStackTrace(); - } catch (InvalidArgumentException e) { - e.printStackTrace(); - } catch (ParseException e) { - e.printStackTrace(); - } - })); + try { + commander.recordInfoQuery(device, channelId, DateUtil.ISO8601Toyyyy_MM_dd_HH_mm_ss(startTime), + DateUtil.ISO8601Toyyyy_MM_dd_HH_mm_ss(endTime), sn, secrecy, type, (eventResult -> { + // 回复200 OK + try { + responseAck(serverTransaction, Response.OK); + } catch (SipException | InvalidArgumentException | ParseException e) { + logger.error("[命令发送失败] 录像查询回复: {}", e.getMessage()); + } + }),(eventResult -> { + // 查询失败 + try { + responseAck(serverTransaction, eventResult.statusCode, eventResult.msg); + } catch (SipException | InvalidArgumentException | ParseException e) { + logger.error("[命令发送失败] 录像查询回复: {}", e.getMessage()); + } + })); + } catch (InvalidArgumentException | ParseException | SipException e) { + logger.error("[命令发送失败] 录像查询: {}", e.getMessage()); + } }else if (channelSources.get(1).getCount() > 0) { // 直播流 // TODO try { responseAck(serverTransaction, Response.NOT_IMPLEMENTED); // 回复未实现 - } catch (SipException e) { - e.printStackTrace(); - } catch (InvalidArgumentException e) { - e.printStackTrace(); - } catch (ParseException e) { - e.printStackTrace(); + } catch (SipException | InvalidArgumentException | ParseException e) { + logger.error("[命令发送失败] 录像查询: {}", e.getMessage()); } }else { // 错误的请求 try { responseAck(serverTransaction, Response.BAD_REQUEST); - } catch (SipException e) { - e.printStackTrace(); - } catch (InvalidArgumentException e) { - e.printStackTrace(); - } catch (ParseException e) { - e.printStackTrace(); + } catch (SipException | InvalidArgumentException | ParseException e) { + logger.error("[命令发送失败] 录像查询: {}", e.getMessage()); } } } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/CatalogResponseMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/CatalogResponseMessageHandler.java index 3cff19d4..94fed568 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/CatalogResponseMessageHandler.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/CatalogResponseMessageHandler.java @@ -87,89 +87,73 @@ public class CatalogResponseMessageHandler extends SIPRequestProcessorParent imp public void handForDevice(RequestEvent evt, Device device, Element element) { taskQueue.offer(new HandlerCatchData(evt, device, element)); // 回复200 OK + ServerTransaction serverTransaction = getServerTransaction(evt); try { - ServerTransaction serverTransaction = getServerTransaction(evt); responseAck(serverTransaction, Response.OK); - if (!taskQueueHandlerRun) { - taskQueueHandlerRun = true; - taskExecutor.execute(()-> { - while (!taskQueue.isEmpty()) { - HandlerCatchData take = taskQueue.poll(); - try { - Element rootElement = getRootElement(take.getEvt(), take.getDevice().getCharset()); - if (rootElement == null) { - logger.warn("[ 收到通道 ] content cannot be null, {}", evt.getRequest()); - continue; - } - Element deviceListElement = rootElement.element("DeviceList"); - Element sumNumElement = rootElement.element("SumNum"); - Element snElement = rootElement.element("SN"); - if (snElement == null || sumNumElement == null || deviceListElement == null) { - responseAck(serverTransaction, Response.BAD_REQUEST, "xml error"); - continue; - } - int sumNum = Integer.parseInt(sumNumElement.getText()); - - if (sumNum == 0) { - logger.info("[收到通道]设备:{}的: 0个", take.getDevice().getDeviceId()); - // 数据已经完整接收 - storager.cleanChannelsForDevice(take.getDevice().getDeviceId()); - catalogDataCatch.setChannelSyncEnd(take.getDevice().getDeviceId(), null); - }else { - Iterator deviceListIterator = deviceListElement.elementIterator(); - if (deviceListIterator != null) { - List channelList = new ArrayList<>(); - // 遍历DeviceList - while (deviceListIterator.hasNext()) { - Element itemDevice = deviceListIterator.next(); - Element channelDeviceElement = itemDevice.element("DeviceID"); - if (channelDeviceElement == null) { - continue; - } - DeviceChannel deviceChannel = XmlUtil.channelContentHander(itemDevice, device, null); - deviceChannel.setDeviceId(take.getDevice().getDeviceId()); - - channelList.add(deviceChannel); - } - int sn = Integer.parseInt(snElement.getText()); - catalogDataCatch.put(take.getDevice().getDeviceId(), sn, sumNum, take.getDevice(), channelList); - logger.info("[收到通道]设备: {} -> {}个,{}/{}", take.getDevice().getDeviceId(), channelList.size(), catalogDataCatch.get(take.getDevice().getDeviceId()) == null ? 0 :catalogDataCatch.get(take.getDevice().getDeviceId()).size(), sumNum); - if (catalogDataCatch.get(take.getDevice().getDeviceId()).size() == sumNum) { - // 数据已经完整接收, 此时可能存在某个设备离线变上线的情况,但是考虑到性能,此处不做处理, - // 目前支持设备通道上线通知时和设备上线时向上级通知 - boolean resetChannelsResult = storager.resetChannels(take.getDevice().getDeviceId(), catalogDataCatch.get(take.getDevice().getDeviceId())); - if (!resetChannelsResult) { - String errorMsg = "接收成功,写入失败,共" + sumNum + "条,已接收" + catalogDataCatch.get(take.getDevice().getDeviceId()).size() + "条"; - catalogDataCatch.setChannelSyncEnd(take.getDevice().getDeviceId(), errorMsg); - }else { - catalogDataCatch.setChannelSyncEnd(take.getDevice().getDeviceId(), null); - } - } - } - - } - } catch (DocumentException e) { - e.printStackTrace(); - } catch (InvalidArgumentException e) { - e.printStackTrace(); - } catch (ParseException e) { - e.printStackTrace(); - } catch (SipException e) { - e.printStackTrace(); - } finally { - taskQueueHandlerRun = false; - } + } catch (SipException | InvalidArgumentException | ParseException e) { + logger.error("[命令发送失败] 目录查询回复: {}", e.getMessage()); + } + if (!taskQueueHandlerRun) { + taskQueueHandlerRun = true; + taskExecutor.execute(() -> { + while (!taskQueue.isEmpty()) { + HandlerCatchData take = taskQueue.poll(); + Element rootElement = null; + try { + rootElement = getRootElement(take.getEvt(), take.getDevice().getCharset()); + } catch (DocumentException e) { + logger.error("[xml解析] 失败: ", e); + continue; } - }); - } - } catch (SipException e) { - throw new RuntimeException(e); - } catch (InvalidArgumentException e) { - throw new RuntimeException(e); - } catch (ParseException e) { - throw new RuntimeException(e); - } finally { - taskQueueHandlerRun = false; + if (rootElement == null) { + logger.warn("[ 收到通道 ] content cannot be null, {}", evt.getRequest()); + continue; + } + Element deviceListElement = rootElement.element("DeviceList"); + Element sumNumElement = rootElement.element("SumNum"); + Element snElement = rootElement.element("SN"); + int sumNum = Integer.parseInt(sumNumElement.getText()); + + if (sumNum == 0) { + logger.info("[收到通道]设备:{}的: 0个", take.getDevice().getDeviceId()); + // 数据已经完整接收 + storager.cleanChannelsForDevice(take.getDevice().getDeviceId()); + catalogDataCatch.setChannelSyncEnd(take.getDevice().getDeviceId(), null); + } else { + Iterator deviceListIterator = deviceListElement.elementIterator(); + if (deviceListIterator != null) { + List channelList = new ArrayList<>(); + // 遍历DeviceList + while (deviceListIterator.hasNext()) { + Element itemDevice = deviceListIterator.next(); + Element channelDeviceElement = itemDevice.element("DeviceID"); + if (channelDeviceElement == null) { + continue; + } + DeviceChannel deviceChannel = XmlUtil.channelContentHander(itemDevice, device, null); + deviceChannel.setDeviceId(take.getDevice().getDeviceId()); + + channelList.add(deviceChannel); + } + int sn = Integer.parseInt(snElement.getText()); + catalogDataCatch.put(take.getDevice().getDeviceId(), sn, sumNum, take.getDevice(), channelList); + logger.info("[收到通道]设备: {} -> {}个,{}/{}", take.getDevice().getDeviceId(), channelList.size(), catalogDataCatch.get(take.getDevice().getDeviceId()) == null ? 0 : catalogDataCatch.get(take.getDevice().getDeviceId()).size(), sumNum); + if (catalogDataCatch.get(take.getDevice().getDeviceId()).size() == sumNum) { + // 数据已经完整接收, 此时可能存在某个设备离线变上线的情况,但是考虑到性能,此处不做处理, + // 目前支持设备通道上线通知时和设备上线时向上级通知 + boolean resetChannelsResult = storager.resetChannels(take.getDevice().getDeviceId(), catalogDataCatch.get(take.getDevice().getDeviceId())); + if (!resetChannelsResult) { + String errorMsg = "接收成功,写入失败,共" + sumNum + "条,已接收" + catalogDataCatch.get(take.getDevice().getDeviceId()).size() + "条"; + catalogDataCatch.setChannelSyncEnd(take.getDevice().getDeviceId(), errorMsg); + } else { + catalogDataCatch.setChannelSyncEnd(take.getDevice().getDeviceId(), null); + } + } + } + + } + } + }); } } @@ -182,7 +166,7 @@ public class CatalogResponseMessageHandler extends SIPRequestProcessorParent imp public SyncStatus getChannelSyncProgress(String deviceId) { if (catalogDataCatch.get(deviceId) == null) { return null; - }else { + } else { return catalogDataCatch.getSyncStatus(deviceId); } } @@ -190,7 +174,7 @@ public class CatalogResponseMessageHandler extends SIPRequestProcessorParent imp public boolean isSyncRunning(String deviceId) { if (catalogDataCatch.get(deviceId) == null) { return false; - }else { + } else { return catalogDataCatch.isSyncRunning(deviceId); } } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/PresetQueryResponseMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/PresetQueryResponseMessageHandler.java index 1febeae6..366c7add 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/PresetQueryResponseMessageHandler.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/PresetQueryResponseMessageHandler.java @@ -50,12 +50,12 @@ public class PresetQueryResponseMessageHandler extends SIPRequestProcessorParent @Override public void handForDevice(RequestEvent evt, Device device, Element element) { - Element rootElement = null; + + ServerTransaction serverTransaction = getServerTransaction(evt); + try { + Element rootElement = getRootElement(evt, device.getCharset()); - ServerTransaction serverTransaction = getServerTransaction(evt); - - rootElement = getRootElement(evt, device.getCharset()); if (rootElement == null) { logger.warn("[ 设备预置位查询应答 ] content cannot be null, {}", evt.getRequest()); responseAck(serverTransaction, Response.BAD_REQUEST); @@ -66,32 +66,29 @@ public class PresetQueryResponseMessageHandler extends SIPRequestProcessorParent //该字段可能为通道或则设备的id String deviceId = getText(rootElement, "DeviceID"); String key = DeferredResultHolder.CALLBACK_CMD_PRESETQUERY + deviceId; - if (snElement == null || presetListNumElement == null) { + if (snElement == null || presetListNumElement == null) { responseAck(serverTransaction, Response.BAD_REQUEST, "xml error"); return; } int sumNum = Integer.parseInt(presetListNumElement.attributeValue("Num")); List presetQuerySipReqList = new ArrayList<>(); if (sumNum > 0) { - for (Iterator presetIterator = presetListNumElement.elementIterator();presetIterator.hasNext();){ + for (Iterator presetIterator = presetListNumElement.elementIterator(); presetIterator.hasNext(); ) { Element itemListElement = presetIterator.next(); PresetQuerySipReq presetQuerySipReq = new PresetQuerySipReq(); - for (Iterator itemListIterator = itemListElement.elementIterator();itemListIterator.hasNext();){ - // 遍历item - Element itemOne = itemListIterator.next(); - String name = itemOne.getName(); - String textTrim = itemOne.getTextTrim(); - if("PresetID".equalsIgnoreCase(name)){ - presetQuerySipReq.setPresetId(textTrim); - }else { - presetQuerySipReq.setPresetName(textTrim); - } + for (Iterator itemListIterator = itemListElement.elementIterator(); itemListIterator.hasNext(); ) { + // 遍历item + Element itemOne = itemListIterator.next(); + String name = itemOne.getName(); + String textTrim = itemOne.getTextTrim(); + if ("PresetID".equalsIgnoreCase(name)) { + presetQuerySipReq.setPresetId(textTrim); + } else { + presetQuerySipReq.setPresetName(textTrim); + } } presetQuerySipReqList.add(presetQuerySipReq); - - } - } RequestMessage requestMessage = new RequestMessage(); requestMessage.setKey(key); @@ -99,13 +96,9 @@ public class PresetQueryResponseMessageHandler extends SIPRequestProcessorParent deferredResultHolder.invokeAllResult(requestMessage); responseAck(serverTransaction, Response.OK); } catch (DocumentException e) { - e.printStackTrace(); - } catch (InvalidArgumentException e) { - e.printStackTrace(); - } catch (ParseException e) { - e.printStackTrace(); - } catch (SipException e) { - e.printStackTrace(); + logger.error("[解析xml]失败: ", e); + } catch (InvalidArgumentException | ParseException | SipException e) { + logger.error("[命令发送失败] 设备预置位查询应答处理: {}", e.getMessage()); } } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/response/impl/InviteResponseProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/response/impl/InviteResponseProcessor.java index 9b090299..3cca115f 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/response/impl/InviteResponseProcessor.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/response/impl/InviteResponseProcessor.java @@ -1,18 +1,27 @@ package com.genersoft.iot.vmp.gb28181.transmit.event.response.impl; import com.genersoft.iot.vmp.conf.SipConfig; +import com.genersoft.iot.vmp.gb28181.bean.Device; +import com.genersoft.iot.vmp.gb28181.bean.SsrcTransaction; import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager; import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver; +import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander; +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 com.genersoft.iot.vmp.service.IDeviceService; import com.genersoft.iot.vmp.utils.GitUtil; import gov.nist.javax.sip.ResponseEventExt; +import gov.nist.javax.sip.SipProviderImpl; import gov.nist.javax.sip.message.SIPResponse; import gov.nist.javax.sip.stack.SIPClientTransaction; import gov.nist.javax.sip.stack.SIPDialog; +import gov.nist.javax.sip.stack.SIPTransaction; +import gov.nist.javax.sip.stack.SIPTransactionImpl; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Component; import javax.sdp.SdpFactory; @@ -54,6 +63,20 @@ public class InviteResponseProcessor extends SIPResponseProcessorAbstract { @Autowired private GitUtil gitUtil; + @Autowired + private ISIPCommander commander; + + @Autowired + private IDeviceService deviceService; + + @Autowired + private SIPRequestHeaderProvider headerProvider; + + @Autowired + @Qualifier(value="udpSipProvider") + private SipProviderImpl udpSipProvider; + + @Override public void afterPropertiesSet() throws Exception { // 添加消息处理的订阅 @@ -71,7 +94,8 @@ public class InviteResponseProcessor extends SIPResponseProcessorAbstract { @Override public void process(ResponseEvent evt ){ try { - Response response = evt.getResponse(); + + SIPResponse response = (SIPResponse)evt.getResponse(); int statusCode = response.getStatusCode(); // trying不会回复 if (statusCode == Response.TRYING) { @@ -80,10 +104,7 @@ public class InviteResponseProcessor extends SIPResponseProcessorAbstract { // 下发ack if (statusCode == Response.OK) { ResponseEventExt event = (ResponseEventExt)evt; - SIPDialog dialog = new SIPDialog((SIPClientTransaction) event.getClientTransaction(), (SIPResponse) event.getResponse()); - CSeqHeader cseq = (CSeqHeader) response.getHeader(CSeqHeader.NAME); - Request reqAck = dialog.createAck(cseq.getSeqNumber()); - SipURI requestURI = (SipURI) reqAck.getRequestURI(); + String contentString = new String(response.getRawContent()); // jainSip不支持y=字段, 移除以解析。 int ssrcIndex = contentString.indexOf("y="); @@ -96,29 +117,15 @@ public class InviteResponseProcessor extends SIPResponseProcessorAbstract { } else { sdp = SdpFactory.getInstance().createSessionDescription(contentString); } - requestURI.setUser(sdp.getOrigin().getUsername()); - try { - requestURI.setHost(event.getRemoteIpAddress()); - } catch (ParseException e) { - e.printStackTrace(); - } - requestURI.setPort(event.getRemotePort()); - reqAck.setRequestURI(requestURI); - UserAgentHeader userAgentHeader = SipUtils.createUserAgentHeader(sipFactory, gitUtil); - reqAck.addHeader(userAgentHeader); - Address concatAddress = sipFactory.createAddressFactory().createAddress(sipFactory.createAddressFactory().createSipURI(sipConfig.getId(), sipConfig.getIp()+":"+sipConfig.getPort())); - reqAck.addHeader(sipFactory.createHeaderFactory().createContactHeader(concatAddress)); - logger.info("[回复ack] {}-> {}:{} ",requestURI, event.getRemoteIpAddress(), event.getRemotePort()); + SipURI requestUri = sipFactory.createAddressFactory().createSipURI(sdp.getOrigin().getUsername(), event.getRemoteIpAddress() + ":" + event.getRemotePort()); + Request reqAck = headerProvider.createAckRequest(requestUri, response); - dialog.sendAck(reqAck); + logger.info("[回复ack] {}-> {}:{} ", sdp.getOrigin().getUsername(), event.getRemoteIpAddress(), event.getRemotePort()); + commander.transmitRequest(response.getTopmostViaHeader().getTransport(), reqAck, null, null); } - } catch (InvalidArgumentException | SipException e) { - e.printStackTrace(); - } catch (ParseException e) { - throw new RuntimeException(e); - } catch (SdpParseException e) { - throw new RuntimeException(e); + } catch (InvalidArgumentException | ParseException | SipException | SdpParseException e) { + logger.info("[点播回复ACK],异常:", e ); } } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/response/impl/RegisterResponseProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/response/impl/RegisterResponseProcessor.java index a5cddaed..d0e15831 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/response/impl/RegisterResponseProcessor.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/response/impl/RegisterResponseProcessor.java @@ -15,10 +15,13 @@ import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; +import javax.sip.InvalidArgumentException; import javax.sip.ResponseEvent; +import javax.sip.SipException; import javax.sip.header.CallIdHeader; import javax.sip.header.WWWAuthenticateHeader; import javax.sip.message.Response; +import java.text.ParseException; /** * @description:Register响应处理器 @@ -87,7 +90,11 @@ public class RegisterResponseProcessor extends SIPResponseProcessorAbstract { if (response.getStatusCode() == Response.UNAUTHORIZED) { WWWAuthenticateHeader www = (WWWAuthenticateHeader)response.getHeader(WWWAuthenticateHeader.NAME); - sipCommanderForPlatform.register(parentPlatform, callId, www, null, null, true, platformRegisterInfo.isRegister()); + try { + sipCommanderForPlatform.register(parentPlatform, callId, www, null, null, true, platformRegisterInfo.isRegister()); + } catch (SipException | InvalidArgumentException | ParseException e) { + logger.error("[命令发送失败] 国标级联 再次注册: {}", e.getMessage()); + } }else if (response.getStatusCode() == Response.OK){ if (platformRegisterInfo.isRegister()) { diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/utils/SipUtils.java b/src/main/java/com/genersoft/iot/vmp/gb28181/utils/SipUtils.java index cf64a86a..bf2a0eef 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/utils/SipUtils.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/utils/SipUtils.java @@ -70,4 +70,47 @@ public class SipUtils { 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); + 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(); + } + } diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java index cbecf0fe..b043cadf 100644 --- a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java +++ b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java @@ -1,5 +1,6 @@ package com.genersoft.iot.vmp.media.zlm; +import java.text.ParseException; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -7,6 +8,7 @@ import java.util.Map; import com.alibaba.fastjson.JSON; import com.genersoft.iot.vmp.common.StreamInfo; import com.genersoft.iot.vmp.conf.UserSetting; +import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException; import com.genersoft.iot.vmp.gb28181.bean.*; import com.genersoft.iot.vmp.gb28181.event.EventPublisher; import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager; @@ -31,6 +33,8 @@ import com.alibaba.fastjson.JSONObject; import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; import javax.servlet.http.HttpServletRequest; +import javax.sip.InvalidArgumentException; +import javax.sip.SipException; /** * @description:针对 ZLMediaServer的hook事件监听 @@ -58,6 +62,9 @@ public class ZLMHttpHookListener { @Autowired private IRedisCatchStorage redisCatchStorage; + @Autowired + private IDeviceService deviceService; + @Autowired private IMediaServerService mediaServerService; @@ -515,7 +522,11 @@ public class ZLMHttpHookListener { String platformId = sendRtpItem.getPlatformId(); ParentPlatform platform = storager.queryParentPlatByServerGBId(platformId); - commanderFroPlatform.streamByeCmd(platform, sendRtpItem); + try { + commanderFroPlatform.streamByeCmd(platform, sendRtpItem); + } catch (SipException | InvalidArgumentException | ParseException e) { + logger.error("[命令发送失败] 国标级联 发送BYE: {}", e.getMessage()); + } } } } @@ -552,21 +563,41 @@ public class ZLMHttpHookListener { if (sendRtpItems.size() > 0) { for (SendRtpItem sendRtpItem : sendRtpItems) { ParentPlatform parentPlatform = storager.queryParentPlatByServerGBId(sendRtpItem.getPlatformId()); - commanderFroPlatform.streamByeCmd(parentPlatform, sendRtpItem.getCallId()); + try { + commanderFroPlatform.streamByeCmd(parentPlatform, sendRtpItem.getCallId()); + } catch (SipException | InvalidArgumentException | ParseException e) { + logger.error("[命令发送失败] 国标级联 发送BYE: {}", e.getMessage()); + } redisCatchStorage.deleteSendRTPServer(parentPlatform.getServerGBId(), sendRtpItem.getChannelId(), sendRtpItem.getCallId(), sendRtpItem.getStreamId()); } } } - cmder.streamByeCmd(streamInfoForPlayCatch.getDeviceID(), streamInfoForPlayCatch.getChannelId(), - streamInfoForPlayCatch.getStream(), null); + Device device = deviceService.queryDevice(streamInfoForPlayCatch.getDeviceID()); + if (device != null) { + try { + cmder.streamByeCmd(device, streamInfoForPlayCatch.getChannelId(), + streamInfoForPlayCatch.getStream(), null); + } catch (InvalidArgumentException | ParseException | SipException | SsrcTransactionNotFoundException e) { + logger.error("[无人观看]点播, 发送BYE失败 {}", e.getMessage()); + } + } + redisCatchStorage.stopPlay(streamInfoForPlayCatch); storager.stopPlay(streamInfoForPlayCatch.getDeviceID(), streamInfoForPlayCatch.getChannelId()); }else{ StreamInfo streamInfoForPlayBackCatch = redisCatchStorage.queryPlayback(null, null, streamId, null); if (streamInfoForPlayBackCatch != null) { - cmder.streamByeCmd(streamInfoForPlayBackCatch.getDeviceID(), - streamInfoForPlayBackCatch.getChannelId(), streamInfoForPlayBackCatch.getStream(), null); + Device device = deviceService.queryDevice(streamInfoForPlayCatch.getDeviceID()); + if (device != null) { + try { + cmder.streamByeCmd(device,streamInfoForPlayBackCatch.getChannelId(), + streamInfoForPlayBackCatch.getStream(), null); + } catch (InvalidArgumentException | ParseException | SipException | + SsrcTransactionNotFoundException e) { + logger.error("[无人观看]回放, 发送BYE失败 {}", e.getMessage()); + } + } redisCatchStorage.stopPlayback(streamInfoForPlayBackCatch.getDeviceID(), streamInfoForPlayBackCatch.getChannelId(), streamInfoForPlayBackCatch.getStream(), null); }else { @@ -689,7 +720,11 @@ public class ZLMHttpHookListener { if (sendRtpItems.size() > 0) { for (SendRtpItem sendRtpItem : sendRtpItems) { ParentPlatform parentPlatform = storager.queryParentPlatByServerGBId(sendRtpItem.getPlatformId()); - commanderFroPlatform.streamByeCmd(parentPlatform, sendRtpItem.getCallId()); + try { + commanderFroPlatform.streamByeCmd(parentPlatform, sendRtpItem.getCallId()); + } catch (SipException | InvalidArgumentException | ParseException e) { + logger.error("[命令发送失败] 国标级联 发送BYE: {}", e.getMessage()); + } redisCatchStorage.deleteSendRTPServer(parentPlatform.getServerGBId(), sendRtpItem.getChannelId(), sendRtpItem.getCallId(), sendRtpItem.getStreamId()); } diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMMediaListManager.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMMediaListManager.java index b545ccc9..d6159809 100644 --- a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMMediaListManager.java +++ b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMMediaListManager.java @@ -68,7 +68,6 @@ public class ZLMMediaListManager { private Map channelOnPublishEvents = new ConcurrentHashMap<>(); public StreamPushItem addPush(MediaItem mediaItem) { - // 查找此直播流是否存在redis预设gbId StreamPushItem transform = streamPushService.transform(mediaItem); StreamPushItem pushInDb = streamPushService.getPush(mediaItem.getApp(), mediaItem.getStream()); transform.setPushIng(mediaItem.isRegist()); @@ -82,15 +81,14 @@ public class ZLMMediaListManager { streamPushMapper.update(transform); gbStreamMapper.updateMediaServer(mediaItem.getApp(), mediaItem.getStream(), mediaItem.getMediaServerId()); } - if (transform != null) { - if (getChannelOnlineEventLister(transform.getApp(), transform.getStream()) != null) { - try { - getChannelOnlineEventLister(transform.getApp(), transform.getStream()).run(transform.getApp(), transform.getStream(), transform.getServerId()); - } catch (ParseException e) { - throw new RuntimeException(e); - } - removedChannelOnlineEventLister(transform.getApp(), transform.getStream()); + ChannelOnlineEvent channelOnlineEventLister = getChannelOnlineEventLister(transform.getApp(), transform.getStream()); + if ( channelOnlineEventLister != null) { + try { + channelOnlineEventLister.run(transform.getApp(), transform.getStream(), transform.getServerId());; + } catch (ParseException e) { + logger.error("addPush: ", e); } + removedChannelOnlineEventLister(transform.getApp(), transform.getStream()); } return transform; } @@ -99,11 +97,12 @@ public class ZLMMediaListManager { MediaServerItem mediaServerItem = mediaServerService.getOne(mediaServerId); // 查看推流状态 if (zlmrtpServerFactory.isStreamReady(mediaServerItem, app, stream)) { - if (getChannelOnlineEventLister(app, stream) != null) { + ChannelOnlineEvent channelOnlineEventLister = getChannelOnlineEventLister(app, stream); + if (channelOnlineEventLister != null) { try { - getChannelOnlineEventLister(app, stream).run(app, stream, mediaServerId); + channelOnlineEventLister.run(app, stream, mediaServerId); } catch (ParseException e) { - throw new RuntimeException(e); + logger.error("sendStreamEvent: ", e); } removedChannelOnlineEventLister(app, stream); } diff --git a/src/main/java/com/genersoft/iot/vmp/service/impl/DeviceServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/service/impl/DeviceServiceImpl.java index b1f8f2a4..70d824c7 100644 --- a/src/main/java/com/genersoft/iot/vmp/service/impl/DeviceServiceImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/service/impl/DeviceServiceImpl.java @@ -26,6 +26,9 @@ import org.springframework.stereotype.Service; import org.springframework.util.ObjectUtils; import org.springframework.util.StringUtils; +import javax.sip.InvalidArgumentException; +import javax.sip.SipException; +import java.text.ParseException; import java.time.Instant; import java.util.ArrayList; import java.util.Collections; @@ -95,7 +98,11 @@ public class DeviceServiceImpl implements IDeviceService { logger.info("[设备上线,首次注册]: {},查询设备信息以及通道信息", device.getDeviceId()); deviceMapper.add(device); redisCatchStorage.updateDevice(device); - commander.deviceInfoQuery(device); + try { + commander.deviceInfoQuery(device); + } catch (InvalidArgumentException | SipException | ParseException e) { + logger.error("[命令发送失败] 查询设备信息: {}", e.getMessage()); + } sync(device); }else { if(device.getOnline() == 0){ @@ -104,7 +111,11 @@ public class DeviceServiceImpl implements IDeviceService { logger.info("[设备上线,离线状态下重新注册]: {},查询设备信息以及通道信息", device.getDeviceId()); deviceMapper.update(device); redisCatchStorage.updateDevice(device); - commander.deviceInfoQuery(device); + try { + commander.deviceInfoQuery(device); + } catch (InvalidArgumentException | SipException | ParseException e) { + logger.error("[命令发送失败] 查询设备信息: {}", e.getMessage()); + } sync(device); // TODO 如果设备下的通道级联到了其他平台,那么需要发送事件或者notify给上级平台 }else { @@ -129,6 +140,7 @@ public class DeviceServiceImpl implements IDeviceService { @Override public void offline(String deviceId) { + logger.info("[设备离线], device:{}", deviceId); Device device = deviceMapper.getDeviceByDeviceId(deviceId); if (device == null) { return; @@ -238,15 +250,28 @@ public class DeviceServiceImpl implements IDeviceService { } int sn = (int)((Math.random()*9+1)*100000); catalogResponseMessageHandler.setChannelSyncReady(device, sn); - sipCommander.catalogQuery(device, sn, event -> { - String errorMsg = String.format("同步通道失败,错误码: %s, %s", event.statusCode, event.msg); + try { + sipCommander.catalogQuery(device, sn, event -> { + String errorMsg = String.format("同步通道失败,错误码: %s, %s", event.statusCode, event.msg); + catalogResponseMessageHandler.setChannelSyncEnd(device.getDeviceId(), errorMsg); + }); + } catch (SipException | InvalidArgumentException | ParseException e) { + logger.error("[同步通道], 信令发送失败:{}", e.getMessage() ); + String errorMsg = String.format("同步通道失败,信令发送失败: %s", e.getMessage()); catalogResponseMessageHandler.setChannelSyncEnd(device.getDeviceId(), errorMsg); - }); + } } @Override public Device queryDevice(String deviceId) { - return deviceMapper.getDeviceByDeviceId(deviceId); + Device device = redisCatchStorage.getDevice(deviceId); + if (device == null) { + device = deviceMapper.getDeviceByDeviceId(deviceId); + if (device != null) { + redisCatchStorage.updateDevice(device); + } + } + return device; } @Override @@ -266,7 +291,11 @@ public class DeviceServiceImpl implements IDeviceService { if (device == null || device.getOnline() == 0) { return; } - sipCommander.deviceStatusQuery(device, null); + try { + sipCommander.deviceStatusQuery(device, null); + } catch (InvalidArgumentException | SipException | ParseException e) { + logger.error("[命令发送失败] 设备状态查询: {}", e.getMessage()); + } } diff --git a/src/main/java/com/genersoft/iot/vmp/service/impl/PlatformServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/service/impl/PlatformServiceImpl.java index 3c5644b3..fe67ede9 100644 --- a/src/main/java/com/genersoft/iot/vmp/service/impl/PlatformServiceImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/service/impl/PlatformServiceImpl.java @@ -20,7 +20,10 @@ import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import javax.sip.InvalidArgumentException; +import javax.sip.SipException; import javax.sip.TimeoutEvent; +import java.text.ParseException; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -99,9 +102,13 @@ public class PlatformServiceImpl implements IPlatformService { if (parentPlatform.isEnable()) { // 保存时启用就发送注册 // 注册成功时由程序直接调用了online方法 - commanderForPlatform.register(parentPlatform, eventResult -> { - logger.info("[国标级联] {},添加向上级注册失败,请确定上级平台可用时重新保存", parentPlatform.getServerGBId()); - }, null); + try { + commanderForPlatform.register(parentPlatform, eventResult -> { + logger.info("[国标级联] {},添加向上级注册失败,请确定上级平台可用时重新保存", parentPlatform.getServerGBId()); + }, null); + } catch (InvalidArgumentException | ParseException | SipException e) { + logger.error("[命令发送失败] 国标级联: {}", e.getMessage()); + } } return result > 0; } @@ -130,46 +137,62 @@ public class PlatformServiceImpl implements IPlatformService { // 添加注册任务 dynamicTask.startDelay(registerTaskKey, // 注册失败(注册成功时由程序直接调用了online方法) - ()->commanderForPlatform.register(parentPlatform, eventResult -> offline(parentPlatform),null), + ()-> { + try { + commanderForPlatform.register(parentPlatform, eventResult -> offline(parentPlatform),null); + } catch (InvalidArgumentException | ParseException | SipException e) { + logger.error("[命令发送失败] 国标级联定时注册: {}", e.getMessage()); + } + }, (parentPlatform.getExpires() - 10) *1000); final String keepaliveTaskKey = KEEPALIVE_KEY_PREFIX + parentPlatform.getServerGBId(); if (!dynamicTask.contains(keepaliveTaskKey)) { // 添加心跳任务 dynamicTask.startCron(keepaliveTaskKey, - ()-> commanderForPlatform.keepalive(parentPlatform, eventResult -> { - // 心跳失败 - if (eventResult.type == SipSubscribe.EventResultType.timeout) { - // 心跳超时 - ParentPlatformCatch platformCatch = redisCatchStorage.queryPlatformCatchInfo(parentPlatform.getServerGBId()); - // 此时是第三次心跳超时, 平台离线 - if (platformCatch.getKeepAliveReply() == 2) { - // 设置平台离线,并重新注册 - offline(parentPlatform); - logger.info("[国标级联] {},三次心跳超时后再次发起注册", parentPlatform.getServerGBId()); - commanderForPlatform.register(parentPlatform, eventResult1 -> { - logger.info("[国标级联] {},三次心跳超时后再次发起注册仍然失败,开始定时发起注册,间隔为1分钟", parentPlatform.getServerGBId()); - // 添加注册任务 - dynamicTask.startCron(registerTaskKey, - // 注册失败(注册成功时由程序直接调用了online方法) - ()->logger.info("[国标级联] {},平台离线后持续发起注册,失败", parentPlatform.getServerGBId()), - 60*1000); - }, null); - } + ()-> { + try { + commanderForPlatform.keepalive(parentPlatform, eventResult -> { + // 心跳失败 + if (eventResult.type == SipSubscribe.EventResultType.timeout) { + // 心跳超时 + ParentPlatformCatch platformCatch = redisCatchStorage.queryPlatformCatchInfo(parentPlatform.getServerGBId()); + // 此时是第三次心跳超时, 平台离线 + if (platformCatch.getKeepAliveReply() == 2) { + // 设置平台离线,并重新注册 + offline(parentPlatform); + logger.info("[国标级联] {},三次心跳超时后再次发起注册", parentPlatform.getServerGBId()); + try { + commanderForPlatform.register(parentPlatform, eventResult1 -> { + logger.info("[国标级联] {},三次心跳超时后再次发起注册仍然失败,开始定时发起注册,间隔为1分钟", parentPlatform.getServerGBId()); + // 添加注册任务 + dynamicTask.startCron(registerTaskKey, + // 注册失败(注册成功时由程序直接调用了online方法) + ()->logger.info("[国标级联] {},平台离线后持续发起注册,失败", parentPlatform.getServerGBId()), + 60*1000); + }, null); + } catch (InvalidArgumentException | ParseException | SipException e) { + logger.error("[命令发送失败] 国标级联 注册: {}", e.getMessage()); + } + } - }else { - logger.warn("[国标级联]发送心跳收到错误,code: {}, msg: {}", eventResult.statusCode, eventResult.msg); - } + }else { + logger.warn("[国标级联]发送心跳收到错误,code: {}, msg: {}", eventResult.statusCode, eventResult.msg); + } - }, eventResult -> { - // 心跳成功 - // 清空之前的心跳超时计数 - ParentPlatformCatch platformCatch = redisCatchStorage.queryPlatformCatchInfo(parentPlatform.getServerGBId()); - if (platformCatch.getKeepAliveReply() > 0) { - platformCatch.setKeepAliveReply(0); - redisCatchStorage.updatePlatformCatchInfo(platformCatch); + }, eventResult -> { + // 心跳成功 + // 清空之前的心跳超时计数 + ParentPlatformCatch platformCatch = redisCatchStorage.queryPlatformCatchInfo(parentPlatform.getServerGBId()); + if (platformCatch.getKeepAliveReply() > 0) { + platformCatch.setKeepAliveReply(0); + redisCatchStorage.updatePlatformCatchInfo(platformCatch); + } + }); + } catch (SipException | InvalidArgumentException | ParseException e) { + logger.error("[命令发送失败] 国标级联 发送心跳: {}", e.getMessage()); } - }), + }, (parentPlatform.getKeepTimeout() - 10)*1000); } } @@ -225,14 +248,18 @@ public class PlatformServiceImpl implements IPlatformService { @Override public void login(ParentPlatform parentPlatform) { final String registerTaskKey = REGISTER_KEY_PREFIX + parentPlatform.getServerGBId(); - commanderForPlatform.register(parentPlatform, eventResult1 -> { - logger.info("[国标级联] {},开始定时发起注册,间隔为1分钟", parentPlatform.getServerGBId()); - // 添加注册任务 - dynamicTask.startCron(registerTaskKey, - // 注册失败(注册成功时由程序直接调用了online方法) - ()->logger.info("[国标级联] {},平台离线后持续发起注册,失败", parentPlatform.getServerGBId()), - 60*1000); - }, null); + try { + commanderForPlatform.register(parentPlatform, eventResult1 -> { + logger.info("[国标级联] {},开始定时发起注册,间隔为1分钟", parentPlatform.getServerGBId()); + // 添加注册任务 + dynamicTask.startCron(registerTaskKey, + // 注册失败(注册成功时由程序直接调用了online方法) + ()->logger.info("[国标级联] {},平台离线后持续发起注册,失败", parentPlatform.getServerGBId()), + 60*1000); + }, null); + } catch (InvalidArgumentException | ParseException | SipException e) { + logger.error("[命令发送失败] 国标级联注册: {}", e.getMessage()); + } } @Override @@ -259,7 +286,12 @@ public class PlatformServiceImpl implements IPlatformService { continue; } // 发送GPS消息 - commanderForPlatform.sendNotifyMobilePosition(platform, gpsMsgInfo, subscribe); + try { + commanderForPlatform.sendNotifyMobilePosition(platform, gpsMsgInfo, subscribe); + } catch (InvalidArgumentException | ParseException | NoSuchFieldException | SipException | + IllegalAccessException e) { + logger.error("[命令发送失败] 国标级联 移动位置通知: {}", e.getMessage()); + } } } } diff --git a/src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java index 6662738c..7908c038 100644 --- a/src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java @@ -2,11 +2,17 @@ package com.genersoft.iot.vmp.service.impl; import java.math.BigDecimal; import java.math.RoundingMode; +import java.text.ParseException; import java.util.*; +import javax.sip.InvalidArgumentException; import javax.sip.ResponseEvent; +import javax.sip.SipException; import com.genersoft.iot.vmp.conf.exception.ControllerException; +import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException; +import com.genersoft.iot.vmp.gb28181.bean.*; +import com.genersoft.iot.vmp.service.IDeviceService; import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -22,13 +28,6 @@ import com.alibaba.fastjson.JSONObject; import com.genersoft.iot.vmp.common.StreamInfo; import com.genersoft.iot.vmp.conf.DynamicTask; import com.genersoft.iot.vmp.conf.UserSetting; -import com.genersoft.iot.vmp.gb28181.bean.Device; -import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; -import com.genersoft.iot.vmp.gb28181.bean.InviteStreamCallback; -import com.genersoft.iot.vmp.gb28181.bean.InviteStreamInfo; -import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; -import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem; -import com.genersoft.iot.vmp.gb28181.bean.SsrcTransaction; import com.genersoft.iot.vmp.gb28181.event.SipSubscribe; import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager; import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; @@ -92,6 +91,10 @@ public class PlayServiceImpl implements IPlayService { @Autowired private VideoStreamSessionManager streamSession; + + @Autowired + private IDeviceService deviceService; + @Autowired private UserSetting userSetting; @@ -258,14 +261,14 @@ public class PlayServiceImpl implements IPlayService { System.out.println("设置超时任务: " + timeOutTaskKey); dynamicTask.startDelay( timeOutTaskKey,()->{ - SIPDialog dialog = streamSession.getDialogByStream(device.getDeviceId(), channelId, finalSsrcInfo.getStream()); - if (dialog != null) { - logger.info("[点播超时] 收流超时 deviceId: {}, channelId: {},端口:{}, SSRC: {}", device.getDeviceId(), channelId, finalSsrcInfo.getPort(), finalSsrcInfo.getSsrc()); - timeoutCallback.run(1, "收流超时"); - // 点播超时回复BYE 同时释放ssrc以及此次点播的资源 - cmder.streamByeCmd(device.getDeviceId(), channelId, finalSsrcInfo.getStream(), null); - }else { - logger.info("[点播超时] 消息未响应 deviceId: {}, channelId: {},端口:{}, SSRC: {}", device.getDeviceId(), channelId, finalSsrcInfo.getPort(), finalSsrcInfo.getSsrc()); + logger.info("[点播超时] 收流超时 deviceId: {}, channelId: {},端口:{}, SSRC: {}", device.getDeviceId(), channelId, finalSsrcInfo.getPort(), finalSsrcInfo.getSsrc()); + timeoutCallback.run(1, "收流超时"); + // 点播超时回复BYE 同时释放ssrc以及此次点播的资源 + try { + cmder.streamByeCmd(device, channelId, finalSsrcInfo.getStream(), null); + } catch (InvalidArgumentException | ParseException | SipException e) { + logger.error("[点播超时], 发送BYE失败 {}", e.getMessage()); + } catch (SsrcTransactionNotFoundException e) { timeoutCallback.run(0, "点播超时"); mediaServerService.releaseSsrc(mediaServerItem.getId(), finalSsrcInfo.getSsrc()); mediaServerService.closeRTPServer(mediaServerItem, finalSsrcInfo.getStream()); @@ -279,73 +282,87 @@ public class PlayServiceImpl implements IPlayService { logger.info("[点播端口分配异常],deviceId={},channelId={},ssrcInfo={}", device.getDeviceId(), channelId, ssrcInfo); return; } - cmder.playStreamCmd(mediaServerItem, ssrcInfo, device, channelId, (MediaServerItem mediaServerItemInuse, JSONObject response) -> { - logger.info("收到订阅消息: " + response.toJSONString()); - System.out.println("停止超时任务: " + timeOutTaskKey); - dynamicTask.stop(timeOutTaskKey); - // hook响应 - onPublishHandlerForPlay(mediaServerItemInuse, response, device.getDeviceId(), channelId, uuid); - hookEvent.response(mediaServerItemInuse, response); - logger.info("[点播成功] deviceId: {}, channelId: {}", device.getDeviceId(), channelId); + try { + cmder.playStreamCmd(mediaServerItem, ssrcInfo, device, channelId, (MediaServerItem mediaServerItemInuse, JSONObject response) -> { + logger.info("收到订阅消息: " + response.toJSONString()); + System.out.println("停止超时任务: " + timeOutTaskKey); + dynamicTask.stop(timeOutTaskKey); + // hook响应 + onPublishHandlerForPlay(mediaServerItemInuse, response, device.getDeviceId(), channelId, uuid); + hookEvent.response(mediaServerItemInuse, response); + logger.info("[点播成功] deviceId: {}, channelId: {}", device.getDeviceId(), channelId); - }, (event) -> { - ResponseEvent responseEvent = (ResponseEvent)event.event; - String contentString = new String(responseEvent.getResponse().getRawContent()); - // 获取ssrc - int ssrcIndex = contentString.indexOf("y="); - // 检查是否有y字段 - if (ssrcIndex >= 0) { - //ssrc规定长度为10字节,不取余下长度以避免后续还有“f=”字段 TODO 后续对不规范的非10位ssrc兼容 - String ssrcInResponse = contentString.substring(ssrcIndex + 2, ssrcIndex + 12); - // 查询到ssrc不一致且开启了ssrc校验则需要针对处理 - if (ssrc.equals(ssrcInResponse)) { - return; - } - logger.info("[点播消息] 收到invite 200, 发现下级自定义了ssrc: {}", ssrcInResponse ); - if (!mediaServerItem.isRtpEnable() || device.isSsrcCheck()) { - logger.info("[点播消息] SSRC修正 {}->{}", ssrc, ssrcInResponse); - - if (!mediaServerItem.getSsrcConfig().checkSsrc(ssrcInResponse)) { - // ssrc 不可用 - // 释放ssrc - mediaServerService.releaseSsrc(mediaServerItem.getId(), finalSsrcInfo.getSsrc()); - streamSession.remove(device.getDeviceId(), channelId, finalSsrcInfo.getStream()); - event.msg = "下级自定义了ssrc,但是此ssrc不可用"; - event.statusCode = 400; - errorEvent.response(event); + }, (event) -> { + ResponseEvent responseEvent = (ResponseEvent)event.event; + String contentString = new String(responseEvent.getResponse().getRawContent()); + // 获取ssrc + int ssrcIndex = contentString.indexOf("y="); + // 检查是否有y字段 + if (ssrcIndex >= 0) { + //ssrc规定长度为10字节,不取余下长度以避免后续还有“f=”字段 TODO 后续对不规范的非10位ssrc兼容 + String ssrcInResponse = contentString.substring(ssrcIndex + 2, ssrcIndex + 12); + // 查询到ssrc不一致且开启了ssrc校验则需要针对处理 + if (ssrc.equals(ssrcInResponse)) { return; } + logger.info("[点播消息] 收到invite 200, 发现下级自定义了ssrc: {}", ssrcInResponse ); + if (!mediaServerItem.isRtpEnable() || device.isSsrcCheck()) { + logger.info("[点播消息] SSRC修正 {}->{}", ssrc, ssrcInResponse); + + if (!mediaServerItem.getSsrcConfig().checkSsrc(ssrcInResponse)) { + // ssrc 不可用 + // 释放ssrc + mediaServerService.releaseSsrc(mediaServerItem.getId(), finalSsrcInfo.getSsrc()); + streamSession.remove(device.getDeviceId(), channelId, finalSsrcInfo.getStream()); + event.msg = "下级自定义了ssrc,但是此ssrc不可用"; + event.statusCode = 400; + errorEvent.response(event); + return; + } + + // 单端口模式streamId也有变化,需要重新设置监听 + if (!mediaServerItem.isRtpEnable()) { + // 添加订阅 + HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", stream, true, "rtsp", mediaServerItem.getId()); + subscribe.removeSubscribe(hookSubscribe); + hookSubscribe.getContent().put("stream", String.format("%08x", Integer.parseInt(ssrcInResponse)).toUpperCase()); + subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, JSONObject response)->{ + logger.info("[ZLM HOOK] ssrc修正后收到订阅消息: " + response.toJSONString()); + dynamicTask.stop(timeOutTaskKey); + // hook响应 + onPublishHandlerForPlay(mediaServerItemInUse, response, device.getDeviceId(), channelId, uuid); + hookEvent.response(mediaServerItemInUse, response); + }); + } + // 关闭rtp server + mediaServerService.closeRTPServer(mediaServerItem, finalSsrcInfo.getStream()); + // 重新开启ssrc server + mediaServerService.openRTPServer(mediaServerItem, finalSsrcInfo.getStream(), ssrcInResponse, device.isSsrcCheck(), false, finalSsrcInfo.getPort()); - // 单端口模式streamId也有变化,需要重新设置监听 - if (!mediaServerItem.isRtpEnable()) { - // 添加订阅 - HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", stream, true, "rtsp", mediaServerItem.getId()); - subscribe.removeSubscribe(hookSubscribe); - hookSubscribe.getContent().put("stream", String.format("%08x", Integer.parseInt(ssrcInResponse)).toUpperCase()); - subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, JSONObject response)->{ - logger.info("[ZLM HOOK] ssrc修正后收到订阅消息: " + response.toJSONString()); - dynamicTask.stop(timeOutTaskKey); - // hook响应 - onPublishHandlerForPlay(mediaServerItemInUse, response, device.getDeviceId(), channelId, uuid); - hookEvent.response(mediaServerItemInUse, response); - }); } - // 关闭rtp server - mediaServerService.closeRTPServer(mediaServerItem, finalSsrcInfo.getStream()); - // 重新开启ssrc server - mediaServerService.openRTPServer(mediaServerItem, finalSsrcInfo.getStream(), ssrcInResponse, device.isSsrcCheck(), false, finalSsrcInfo.getPort()); - } - } - }, (event) -> { + }, (event) -> { + dynamicTask.stop(timeOutTaskKey); + mediaServerService.closeRTPServer(mediaServerItem, finalSsrcInfo.getStream()); + // 释放ssrc + mediaServerService.releaseSsrc(mediaServerItem.getId(), finalSsrcInfo.getSsrc()); + + streamSession.remove(device.getDeviceId(), channelId, finalSsrcInfo.getStream()); + errorEvent.response(event); + }); + } catch (InvalidArgumentException | SipException | ParseException e) { + + logger.error("[命令发送失败] 点播消息: {}", e.getMessage()); dynamicTask.stop(timeOutTaskKey); mediaServerService.closeRTPServer(mediaServerItem, finalSsrcInfo.getStream()); // 释放ssrc mediaServerService.releaseSsrc(mediaServerItem.getId(), finalSsrcInfo.getSsrc()); streamSession.remove(device.getDeviceId(), channelId, finalSsrcInfo.getStream()); - errorEvent.response(event); - }); + SipSubscribe.EventResult eventResult = new SipSubscribe.EventResult(new CmdSendFailEvent(null)); + eventResult.msg = "命令发送失败"; + errorEvent.response(eventResult); + } } @Override @@ -436,17 +453,18 @@ public class PlayServiceImpl implements IPlayService { playBackResult.setCode(ErrorCode.ERROR100.getCode()); playBackResult.setMsg("回放超时"); playBackResult.setData(requestMessage); - SIPDialog dialog = streamSession.getDialogByStream(deviceId, channelId, ssrcInfo.getStream()); - // 点播超时回复BYE 同时释放ssrc以及此次点播的资源 - if (dialog != null) { + + try { + cmder.streamByeCmd(device, channelId, ssrcInfo.getStream(), null); + } catch (InvalidArgumentException | ParseException | SipException e) { + logger.error("[录像流]回放超时 发送BYE失败 {}", e.getMessage()); + } catch (SsrcTransactionNotFoundException e) { // 点播超时回复BYE 同时释放ssrc以及此次点播的资源 - cmder.streamByeCmd(device.getDeviceId(), channelId, ssrcInfo.getStream(), null); - }else { mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc()); mediaServerService.closeRTPServer(mediaServerItem, ssrcInfo.getStream()); streamSession.remove(deviceId, channelId, ssrcInfo.getStream()); } - cmder.streamByeCmd(device.getDeviceId(), channelId, ssrcInfo.getStream(), null); + // 回复之前所有的点播请求 playBackCallback.call(playBackResult); result.setResult(WVPResult.fail(ErrorCode.ERROR100.getCode(), "回放超时")); @@ -486,59 +504,67 @@ public class PlayServiceImpl implements IPlayService { playBackCallback.call(playBackResult); }; - cmder.playbackStreamCmd(mediaServerItem, ssrcInfo, device, channelId, startTime, endTime, infoCallBack, - hookEvent, eventResult -> { - if (eventResult.type == SipSubscribe.EventResultType.response) { - ResponseEvent responseEvent = (ResponseEvent)eventResult.event; - String contentString = new String(responseEvent.getResponse().getRawContent()); - // 获取ssrc - int ssrcIndex = contentString.indexOf("y="); - // 检查是否有y字段 - if (ssrcIndex >= 0) { - //ssrc规定长度为10字节,不取余下长度以避免后续还有“f=”字段 TODO 后续对不规范的非10位ssrc兼容 - String ssrcInResponse = contentString.substring(ssrcIndex + 2, ssrcIndex + 12); - // 查询到ssrc不一致且开启了ssrc校验则需要针对处理 - if (ssrcInfo.getSsrc().equals(ssrcInResponse)) { - return; - } - logger.info("[回放消息] 收到invite 200, 发现下级自定义了ssrc: {}", ssrcInResponse ); - if (!mediaServerItem.isRtpEnable() || device.isSsrcCheck()) { - logger.info("[回放消息] SSRC修正 {}->{}", ssrcInfo.getSsrc(), ssrcInResponse); - - if (!mediaServerItem.getSsrcConfig().checkSsrc(ssrcInResponse)) { - // ssrc 不可用 - // 释放ssrc - mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc()); - streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream()); - eventResult.msg = "下级自定义了ssrc,但是此ssrc不可用"; - eventResult.statusCode = 400; - errorEvent.response(eventResult); + try { + cmder.playbackStreamCmd(mediaServerItem, ssrcInfo, device, channelId, startTime, endTime, infoCallBack, + hookEvent, eventResult -> { + if (eventResult.type == SipSubscribe.EventResultType.response) { + ResponseEvent responseEvent = (ResponseEvent)eventResult.event; + String contentString = new String(responseEvent.getResponse().getRawContent()); + // 获取ssrc + int ssrcIndex = contentString.indexOf("y="); + // 检查是否有y字段 + if (ssrcIndex >= 0) { + //ssrc规定长度为10字节,不取余下长度以避免后续还有“f=”字段 TODO 后续对不规范的非10位ssrc兼容 + String ssrcInResponse = contentString.substring(ssrcIndex + 2, ssrcIndex + 12); + // 查询到ssrc不一致且开启了ssrc校验则需要针对处理 + if (ssrcInfo.getSsrc().equals(ssrcInResponse)) { return; } + logger.info("[回放消息] 收到invite 200, 发现下级自定义了ssrc: {}", ssrcInResponse ); + if (!mediaServerItem.isRtpEnable() || device.isSsrcCheck()) { + logger.info("[回放消息] SSRC修正 {}->{}", ssrcInfo.getSsrc(), ssrcInResponse); - // 单端口模式streamId也有变化,需要重新设置监听 - if (!mediaServerItem.isRtpEnable()) { - // 添加订阅 - HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", ssrcInfo.getStream(), true, "rtsp", mediaServerItem.getId()); - subscribe.removeSubscribe(hookSubscribe); - hookSubscribe.getContent().put("stream", String.format("%08x", Integer.parseInt(ssrcInResponse)).toUpperCase()); - subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, JSONObject response)->{ - logger.info("[ZLM HOOK] ssrc修正后收到订阅消息: " + response.toJSONString()); - dynamicTask.stop(playBackTimeOutTaskKey); - // hook响应 - onPublishHandlerForPlay(mediaServerItemInUse, response, device.getDeviceId(), channelId, uuid); - hookEvent.call(new InviteStreamInfo(mediaServerItem, null, eventResult.callId, "rtp", ssrcInfo.getStream())); - }); + if (!mediaServerItem.getSsrcConfig().checkSsrc(ssrcInResponse)) { + // ssrc 不可用 + // 释放ssrc + mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc()); + streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream()); + eventResult.msg = "下级自定义了ssrc,但是此ssrc不可用"; + eventResult.statusCode = 400; + errorEvent.response(eventResult); + return; + } + + // 单端口模式streamId也有变化,需要重新设置监听 + if (!mediaServerItem.isRtpEnable()) { + // 添加订阅 + HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", ssrcInfo.getStream(), true, "rtsp", mediaServerItem.getId()); + subscribe.removeSubscribe(hookSubscribe); + hookSubscribe.getContent().put("stream", String.format("%08x", Integer.parseInt(ssrcInResponse)).toUpperCase()); + subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, JSONObject response)->{ + logger.info("[ZLM HOOK] ssrc修正后收到订阅消息: " + response.toJSONString()); + dynamicTask.stop(playBackTimeOutTaskKey); + // hook响应 + onPublishHandlerForPlay(mediaServerItemInUse, response, device.getDeviceId(), channelId, uuid); + hookEvent.call(new InviteStreamInfo(mediaServerItem, null, eventResult.callId, "rtp", ssrcInfo.getStream())); + }); + } + // 关闭rtp server + mediaServerService.closeRTPServer(mediaServerItem, ssrcInfo.getStream()); + // 重新开启ssrc server + mediaServerService.openRTPServer(mediaServerItem, ssrcInfo.getStream(), ssrcInResponse, device.isSsrcCheck(), true, ssrcInfo.getPort()); } - // 关闭rtp server - mediaServerService.closeRTPServer(mediaServerItem, ssrcInfo.getStream()); - // 重新开启ssrc server - mediaServerService.openRTPServer(mediaServerItem, ssrcInfo.getStream(), ssrcInResponse, device.isSsrcCheck(), true, ssrcInfo.getPort()); } } - } - }, errorEvent); + }, errorEvent); + } catch (InvalidArgumentException | SipException | ParseException e) { + logger.error("[命令发送失败] 回放: {}", e.getMessage()); + + SipSubscribe.EventResult eventResult = new SipSubscribe.EventResult(new CmdSendFailEvent(null)); + eventResult.msg = "命令发送失败"; + errorEvent.response(eventResult); + } return result; } @@ -584,46 +610,57 @@ public class PlayServiceImpl implements IPlayService { downloadResult.setCode(ErrorCode.ERROR100.getCode()); downloadResult.setMsg("录像下载请求超时"); hookCallBack.call(downloadResult); - SIPDialog dialog = streamSession.getDialogByStream(deviceId, channelId, ssrcInfo.getStream()); + // 点播超时回复BYE 同时释放ssrc以及此次点播的资源 - if (dialog != null) { - // 点播超时回复BYE 同时释放ssrc以及此次点播的资源 - cmder.streamByeCmd(device.getDeviceId(), channelId, ssrcInfo.getStream(), null); - }else { + try { + cmder.streamByeCmd(device, channelId, ssrcInfo.getStream(), null); + } catch (InvalidArgumentException | ParseException | SipException e) { + logger.error("[录像流]录像下载请求超时, 发送BYE失败 {}", e.getMessage()); + } catch (SsrcTransactionNotFoundException e) { mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc()); mediaServerService.closeRTPServer(mediaServerItem, ssrcInfo.getStream()); streamSession.remove(deviceId, channelId, ssrcInfo.getStream()); } - cmder.streamByeCmd(device.getDeviceId(), channelId, ssrcInfo.getStream(), null); // 回复之前所有的点播请求 hookCallBack.call(downloadResult); }, userSetting.getPlayTimeout()); - cmder.downloadStreamCmd(mediaServerItem, ssrcInfo, device, channelId, startTime, endTime, downloadSpeed, infoCallBack, - inviteStreamInfo -> { - logger.info("收到订阅消息: " + inviteStreamInfo.getResponse().toJSONString()); - dynamicTask.stop(downLoadTimeOutTaskKey); - StreamInfo streamInfo = onPublishHandler(inviteStreamInfo.getMediaServerItem(), inviteStreamInfo.getResponse(), deviceId, channelId); - streamInfo.setStartTime(startTime); - streamInfo.setEndTime(endTime); - redisCatchStorage.startDownload(streamInfo, inviteStreamInfo.getCallId()); - wvpResult.setCode(ErrorCode.SUCCESS.getCode()); - wvpResult.setMsg(ErrorCode.SUCCESS.getMsg()); - wvpResult.setData(streamInfo); - downloadResult.setCode(ErrorCode.SUCCESS.getCode()); - downloadResult.setMsg(ErrorCode.SUCCESS.getMsg()); - downloadResult.setMediaServerItem(inviteStreamInfo.getMediaServerItem()); - downloadResult.setResponse(inviteStreamInfo.getResponse()); - hookCallBack.call(downloadResult); - }, event -> { - dynamicTask.stop(downLoadTimeOutTaskKey); - downloadResult.setCode(ErrorCode.ERROR100.getCode()); - downloadResult.setMsg(String.format("录像下载失败, 错误码: %s, %s", event.statusCode, event.msg)); - wvpResult.setCode(ErrorCode.ERROR100.getCode()); - wvpResult.setMsg(String.format("录像下载失败, 错误码: %s, %s", event.statusCode, event.msg)); - downloadResult.setEvent(event); - hookCallBack.call(downloadResult); - streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream()); - }); + + SipSubscribe.Event errorEvent = event -> { + dynamicTask.stop(downLoadTimeOutTaskKey); + downloadResult.setCode(ErrorCode.ERROR100.getCode()); + downloadResult.setMsg(String.format("录像下载失败, 错误码: %s, %s", event.statusCode, event.msg)); + wvpResult.setCode(ErrorCode.ERROR100.getCode()); + wvpResult.setMsg(String.format("录像下载失败, 错误码: %s, %s", event.statusCode, event.msg)); + downloadResult.setEvent(event); + hookCallBack.call(downloadResult); + streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream()); + }; + + try { + cmder.downloadStreamCmd(mediaServerItem, ssrcInfo, device, channelId, startTime, endTime, downloadSpeed, infoCallBack, + inviteStreamInfo -> { + logger.info("收到订阅消息: " + inviteStreamInfo.getResponse().toJSONString()); + dynamicTask.stop(downLoadTimeOutTaskKey); + StreamInfo streamInfo = onPublishHandler(inviteStreamInfo.getMediaServerItem(), inviteStreamInfo.getResponse(), deviceId, channelId); + streamInfo.setStartTime(startTime); + streamInfo.setEndTime(endTime); + redisCatchStorage.startDownload(streamInfo, inviteStreamInfo.getCallId()); + wvpResult.setCode(ErrorCode.SUCCESS.getCode()); + wvpResult.setMsg(ErrorCode.SUCCESS.getMsg()); + wvpResult.setData(streamInfo); + downloadResult.setCode(ErrorCode.SUCCESS.getCode()); + downloadResult.setMsg(ErrorCode.SUCCESS.getMsg()); + downloadResult.setMediaServerItem(inviteStreamInfo.getMediaServerItem()); + downloadResult.setResponse(inviteStreamInfo.getResponse()); + hookCallBack.call(downloadResult); + }, errorEvent); + } catch (InvalidArgumentException | SipException | ParseException e) { + logger.error("[命令发送失败] 录像下载: {}", e.getMessage()); + + SipSubscribe.EventResult eventResult = new SipSubscribe.EventResult(new CmdSendFailEvent(null)); + eventResult.msg = "命令发送失败"; + errorEvent.response(eventResult); + } return result; } @@ -702,7 +739,11 @@ public class PlayServiceImpl implements IPlayService { for (SendRtpItem sendRtpItem : sendRtpItems) { if (sendRtpItem.getMediaServerId().equals(mediaServerId)) { ParentPlatform platform = storager.queryParentPlatByServerGBId(sendRtpItem.getPlatformId()); - sipCommanderFroPlatform.streamByeCmd(platform, sendRtpItem.getCallId()); + try { + sipCommanderFroPlatform.streamByeCmd(platform, sendRtpItem.getCallId()); + } catch (SipException | InvalidArgumentException | ParseException e) { + logger.error("[命令发送失败] 国标级联 发送BYE: {}", e.getMessage()); + } } } } @@ -711,8 +752,17 @@ public class PlayServiceImpl implements IPlayService { if (allSsrc.size() > 0) { for (SsrcTransaction ssrcTransaction : allSsrc) { if(ssrcTransaction.getMediaServerId().equals(mediaServerId)) { - cmder.streamByeCmd(ssrcTransaction.getDeviceId(), ssrcTransaction.getChannelId(), - ssrcTransaction.getStream(), null); + Device device = deviceService.queryDevice(ssrcTransaction.getDeviceId()); + if (device == null) { + continue; + } + try { + cmder.streamByeCmd(device, ssrcTransaction.getChannelId(), + ssrcTransaction.getStream(), null); + } catch (InvalidArgumentException | ParseException | SipException | + SsrcTransactionNotFoundException e) { + logger.error("[zlm离线]为正在使用此zlm的设备, 发送BYE失败 {}", e.getMessage()); + } } } } diff --git a/src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisAlarmMsgListener.java b/src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisAlarmMsgListener.java index 84f5ef71..589e2bee 100644 --- a/src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisAlarmMsgListener.java +++ b/src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisAlarmMsgListener.java @@ -16,6 +16,9 @@ import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import org.springframework.stereotype.Component; import org.springframework.util.ObjectUtils; +import javax.sip.InvalidArgumentException; +import javax.sip.SipException; +import java.text.ParseException; import java.util.List; import java.util.concurrent.ConcurrentLinkedQueue; @@ -76,16 +79,28 @@ public class RedisAlarmMsgListener implements MessageListener { List parentPlatforms = storage.queryEnableParentPlatformList(true); if (parentPlatforms.size() > 0) { for (ParentPlatform parentPlatform : parentPlatforms) { - commanderForPlatform.sendAlarmMessage(parentPlatform, deviceAlarm); + try { + commanderForPlatform.sendAlarmMessage(parentPlatform, deviceAlarm); + } catch (SipException | InvalidArgumentException | ParseException e) { + logger.error("[命令发送失败] 国标级联 发送报警: {}", e.getMessage()); + } } } }else { Device device = storage.queryVideoDevice(gbId); ParentPlatform platform = storage.queryParentPlatByServerGBId(gbId); if (device != null && platform == null) { - commander.sendAlarmMessage(device, deviceAlarm); + try { + commander.sendAlarmMessage(device, deviceAlarm); + } catch (InvalidArgumentException | SipException | ParseException e) { + logger.error("[命令发送失败] 发送报警: {}", e.getMessage()); + } }else if (device == null && platform != null){ - commanderForPlatform.sendAlarmMessage(platform, deviceAlarm); + try { + commanderForPlatform.sendAlarmMessage(platform, deviceAlarm); + } catch (InvalidArgumentException | SipException | ParseException e) { + logger.error("[命令发送失败] 发送报警: {}", e.getMessage()); + } }else { logger.warn("无法确定" + gbId + "是平台还是设备"); } diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/MobilePosition/MobilePositionController.java b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/MobilePosition/MobilePositionController.java index e5d928a1..f399f300 100644 --- a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/MobilePosition/MobilePositionController.java +++ b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/MobilePosition/MobilePositionController.java @@ -1,5 +1,6 @@ package com.genersoft.iot.vmp.vmanager.gb28181.MobilePosition; +import java.text.ParseException; import java.util.List; import java.util.UUID; @@ -31,6 +32,9 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.context.request.async.DeferredResult; +import javax.sip.InvalidArgumentException; +import javax.sip.SipException; + /** * 位置信息管理 */ @@ -105,13 +109,18 @@ public class MobilePositionController { Device device = storager.queryVideoDevice(deviceId); String uuid = UUID.randomUUID().toString(); String key = DeferredResultHolder.CALLBACK_CMD_MOBILEPOSITION + deviceId; - cmder.mobilePostitionQuery(device, event -> { - RequestMessage msg = new RequestMessage(); - msg.setId(uuid); - msg.setKey(key); - msg.setData(String.format("获取移动位置信息失败,错误码: %s, %s", event.statusCode, event.msg)); - resultHolder.invokeResult(msg); - }); + try { + cmder.mobilePostitionQuery(device, event -> { + RequestMessage msg = new RequestMessage(); + msg.setId(uuid); + msg.setKey(key); + msg.setData(String.format("获取移动位置信息失败,错误码: %s, %s", event.statusCode, event.msg)); + resultHolder.invokeResult(msg); + }); + } catch (InvalidArgumentException | SipException | ParseException e) { + logger.error("[命令发送失败] 获取移动位置信息: {}", e.getMessage()); + throw new ControllerException(ErrorCode.ERROR100.getCode(), "命令发送失败: " + e.getMessage()); + } DeferredResult result = new DeferredResult(5*1000L); result.onTimeout(()->{ logger.warn(String.format("获取移动位置信息超时")); diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/alarm/AlarmController.java b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/alarm/AlarmController.java index c8bd3f46..e030b176 100644 --- a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/alarm/AlarmController.java +++ b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/alarm/AlarmController.java @@ -6,6 +6,7 @@ import com.genersoft.iot.vmp.gb28181.bean.DeviceAlarm; import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander; import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform; +import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookListener; import com.genersoft.iot.vmp.service.IDeviceAlarmService; import com.genersoft.iot.vmp.storager.IVideoManagerStorage; import com.genersoft.iot.vmp.utils.DateUtil; @@ -16,6 +17,8 @@ import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.tags.Tag; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; @@ -23,6 +26,9 @@ import org.springframework.util.ObjectUtils; import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.*; +import javax.sip.InvalidArgumentException; +import javax.sip.SipException; +import java.text.ParseException; import java.time.LocalDateTime; import java.util.Arrays; import java.util.List; @@ -33,6 +39,8 @@ import java.util.List; @RequestMapping("/api/alarm") public class AlarmController { + private final static Logger logger = LoggerFactory.getLogger(AlarmController.class); + @Autowired private IDeviceAlarmService deviceAlarmService; @@ -108,9 +116,19 @@ public class AlarmController { deviceAlarm.setLatitude(39.33333); if (device != null && platform == null) { - commander.sendAlarmMessage(device, deviceAlarm); + + try { + commander.sendAlarmMessage(device, deviceAlarm); + } catch (InvalidArgumentException | SipException | ParseException e) { + + } }else if (device == null && platform != null){ - commanderForPlatform.sendAlarmMessage(platform, deviceAlarm); + try { + commanderForPlatform.sendAlarmMessage(platform, deviceAlarm); + } catch (SipException | InvalidArgumentException | ParseException e) { + logger.error("[命令发送失败] 国标级联 发送BYE: {}", e.getMessage()); + throw new ControllerException(ErrorCode.ERROR100.getCode(), "命令发送失败: " + e.getMessage()); + } }else { throw new ControllerException(ErrorCode.ERROR100.getCode(),"无法确定" + deviceId + "是平台还是设备"); } diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceConfig.java b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceConfig.java index d0eb81d6..e39b3039 100644 --- a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceConfig.java +++ b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceConfig.java @@ -8,12 +8,14 @@ package com.genersoft.iot.vmp.vmanager.gb28181.device; import com.alibaba.fastjson.JSONObject; +import com.genersoft.iot.vmp.conf.exception.ControllerException; import com.genersoft.iot.vmp.gb28181.bean.Device; 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.cmd.impl.SIPCommander; import com.genersoft.iot.vmp.storager.IVideoManagerStorage; +import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; @@ -26,6 +28,9 @@ import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.*; import org.springframework.web.context.request.async.DeferredResult; +import javax.sip.InvalidArgumentException; +import javax.sip.SipException; +import java.text.ParseException; import java.util.UUID; @Tag(name = "国标设备配置") @@ -75,14 +80,19 @@ public class DeviceConfig { Device device = storager.queryVideoDevice(deviceId); String uuid = UUID.randomUUID().toString(); String key = DeferredResultHolder.CALLBACK_CMD_DEVICECONFIG + deviceId + channelId; - cmder.deviceBasicConfigCmd(device, channelId, name, expiration, heartBeatInterval, heartBeatCount, event -> { - RequestMessage msg = new RequestMessage(); - msg.setId(uuid); - msg.setKey(key); - msg.setData(String.format("设备配置操作失败,错误码: %s, %s", event.statusCode, event.msg)); - resultHolder.invokeResult(msg); - }); - DeferredResult result = new DeferredResult(3 * 1000L); + try { + cmder.deviceBasicConfigCmd(device, channelId, name, expiration, heartBeatInterval, heartBeatCount, event -> { + RequestMessage msg = new RequestMessage(); + msg.setId(uuid); + msg.setKey(key); + msg.setData(String.format("设备配置操作失败,错误码: %s, %s", event.statusCode, event.msg)); + resultHolder.invokeResult(msg); + }); + } catch (InvalidArgumentException | SipException | ParseException e) { + logger.error("[命令发送失败] 设备配置: {}", e.getMessage()); + throw new ControllerException(ErrorCode.ERROR100.getCode(), "命令发送失败: " + e.getMessage()); + } + DeferredResult result = new DeferredResult(3 * 1000L); result.onTimeout(() -> { logger.warn(String.format("设备配置操作超时, 设备未返回应答指令")); // 释放rtpserver @@ -121,14 +131,19 @@ public class DeviceConfig { String key = DeferredResultHolder.CALLBACK_CMD_CONFIGDOWNLOAD + (ObjectUtils.isEmpty(channelId) ? deviceId : channelId); String uuid = UUID.randomUUID().toString(); Device device = storager.queryVideoDevice(deviceId); - cmder.deviceConfigQuery(device, channelId, configType, event -> { - RequestMessage msg = new RequestMessage(); - msg.setId(uuid); - msg.setKey(key); - msg.setData(String.format("获取设备配置失败,错误码: %s, %s", event.statusCode, event.msg)); - resultHolder.invokeResult(msg); - }); - DeferredResult result = new DeferredResult (3 * 1000L); + try { + cmder.deviceConfigQuery(device, channelId, configType, event -> { + RequestMessage msg = new RequestMessage(); + msg.setId(uuid); + msg.setKey(key); + msg.setData(String.format("获取设备配置失败,错误码: %s, %s", event.statusCode, event.msg)); + resultHolder.invokeResult(msg); + }); + } catch (InvalidArgumentException | SipException | ParseException e) { + logger.error("[命令发送失败] 获取设备配置: {}", e.getMessage()); + throw new ControllerException(ErrorCode.ERROR100.getCode(), "命令发送失败: " + e.getMessage()); + } + DeferredResult result = new DeferredResult (3 * 1000L); result.onTimeout(()->{ logger.warn(String.format("获取设备配置超时")); // 释放rtpserver diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceControl.java b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceControl.java index fe363a6e..1b866b91 100644 --- a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceControl.java +++ b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceControl.java @@ -29,6 +29,9 @@ import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.*; import org.springframework.web.context.request.async.DeferredResult; +import javax.sip.InvalidArgumentException; +import javax.sip.SipException; +import java.text.ParseException; import java.util.UUID; @Tag(name = "国标设备控制") @@ -61,10 +64,12 @@ public class DeviceControl { logger.debug("设备远程启动API调用"); } Device device = storager.queryVideoDevice(deviceId); - if (!cmder.teleBootCmd(device)) { - logger.warn("设备远程启动API调用失败!"); - throw new ControllerException(ErrorCode.ERROR100); - } + try { + cmder.teleBootCmd(device); + } catch (InvalidArgumentException | SipException | ParseException e) { + logger.error("[命令发送失败] 远程启动: {}", e.getMessage()); + throw new ControllerException(ErrorCode.ERROR100.getCode(), "命令发送失败: " + e.getMessage()); + } } /** @@ -101,13 +106,18 @@ public class DeviceControl { return result; } resultHolder.put(key, uuid, result); - cmder.recordCmd(device, channelId, recordCmdStr, event -> { - RequestMessage msg = new RequestMessage(); - msg.setId(uuid); - msg.setKey(key); - msg.setData(String.format("开始/停止录像操作失败,错误码: %s, %s", event.statusCode, event.msg)); - resultHolder.invokeAllResult(msg); - }); + try { + cmder.recordCmd(device, channelId, recordCmdStr, event -> { + RequestMessage msg = new RequestMessage(); + msg.setId(uuid); + msg.setKey(key); + msg.setData(String.format("开始/停止录像操作失败,错误码: %s, %s", event.statusCode, event.msg)); + resultHolder.invokeAllResult(msg); + }); + } catch (InvalidArgumentException | SipException | ParseException e) { + logger.error("[命令发送失败] 开始/停止录像: {}", e.getMessage()); + throw new ControllerException(ErrorCode.ERROR100.getCode(), "命令发送失败: " + e.getMessage()); + } return result; } @@ -123,21 +133,26 @@ public class DeviceControl { @Parameter(name = "channelId", description = "通道国标编号", required = true) @Parameter(name = "guardCmdStr", description = "命令, 可选值:SetGuard(布防),ResetGuard(撤防)", required = true) @GetMapping("/guard/{deviceId}/{guardCmdStr}") - public DeferredResult> guardApi(@PathVariable String deviceId, String channelId, @PathVariable String guardCmdStr) { + public DeferredResult guardApi(@PathVariable String deviceId, String channelId, @PathVariable String guardCmdStr) { if (logger.isDebugEnabled()) { logger.debug("布防/撤防API调用"); } Device device = storager.queryVideoDevice(deviceId); String key = DeferredResultHolder.CALLBACK_CMD_DEVICECONTROL + deviceId + channelId; String uuid =UUID.randomUUID().toString(); - cmder.guardCmd(device, guardCmdStr, event -> { - RequestMessage msg = new RequestMessage(); - msg.setId(uuid); - msg.setKey(key); - msg.setData(String.format("布防/撤防操作失败,错误码: %s, %s", event.statusCode, event.msg)); - resultHolder.invokeResult(msg); - }); - DeferredResult> result = new DeferredResult>(3 * 1000L); + try { + cmder.guardCmd(device, guardCmdStr, event -> { + RequestMessage msg = new RequestMessage(); + msg.setId(uuid); + msg.setKey(key); + msg.setData(String.format("布防/撤防操作失败,错误码: %s, %s", event.statusCode, event.msg)); + resultHolder.invokeResult(msg); + }); + } catch (InvalidArgumentException | SipException | ParseException e) { + logger.error("[命令发送失败] 布防/撤防操作: {}", e.getMessage()); + throw new ControllerException(ErrorCode.ERROR100.getCode(), "命令发送: " + e.getMessage()); + } + DeferredResult result = new DeferredResult<>(3 * 1000L); resultHolder.put(key, uuid, result); result.onTimeout(() -> { logger.warn(String.format("布防/撤防操作超时, 设备未返回应答指令")); @@ -174,14 +189,19 @@ public class DeviceControl { Device device = storager.queryVideoDevice(deviceId); String uuid = UUID.randomUUID().toString(); String key = DeferredResultHolder.CALLBACK_CMD_DEVICECONTROL + deviceId + channelId; - cmder.alarmCmd(device, alarmMethod, alarmType, event -> { - RequestMessage msg = new RequestMessage(); - msg.setId(uuid); - msg.setKey(key); - msg.setData(String.format("报警复位操作失败,错误码: %s, %s", event.statusCode, event.msg)); - resultHolder.invokeResult(msg); - }); - DeferredResult> result = new DeferredResult>(3 * 1000L); + try { + cmder.alarmCmd(device, alarmMethod, alarmType, event -> { + RequestMessage msg = new RequestMessage(); + msg.setId(uuid); + msg.setKey(key); + msg.setData(String.format("报警复位操作失败,错误码: %s, %s", event.statusCode, event.msg)); + resultHolder.invokeResult(msg); + }); + } catch (InvalidArgumentException | SipException | ParseException e) { + logger.error("[命令发送失败] 报警复位: {}", e.getMessage()); + throw new ControllerException(ErrorCode.ERROR100.getCode(), "命令发送失败: " + e.getMessage()); + } + DeferredResult> result = new DeferredResult>(3 * 1000L); result.onTimeout(() -> { logger.warn(String.format("报警复位操作超时, 设备未返回应答指令")); // 释放rtpserver @@ -205,23 +225,23 @@ public class DeviceControl { @Parameter(name = "deviceId", description = "设备国标编号", required = true) @Parameter(name = "channelId", description = "通道国标编号") @GetMapping("/i_frame/{deviceId}") - public ResponseEntity iFrame(@PathVariable String deviceId, + public JSONObject iFrame(@PathVariable String deviceId, @RequestParam(required = false) String channelId) { if (logger.isDebugEnabled()) { logger.debug("强制关键帧API调用"); } Device device = storager.queryVideoDevice(deviceId); - boolean sucsess = cmder.iFrameCmd(device, channelId); - if (sucsess) { - JSONObject json = new JSONObject(); - json.put("DeviceID", deviceId); - json.put("ChannelID", channelId); - json.put("Result", "OK"); - return new ResponseEntity<>(json.toJSONString(), HttpStatus.OK); - } else { - logger.warn("强制关键帧API调用失败!"); - return new ResponseEntity("强制关键帧API调用失败!", HttpStatus.INTERNAL_SERVER_ERROR); + try { + cmder.iFrameCmd(device, channelId); + } catch (InvalidArgumentException | SipException | ParseException e) { + logger.error("[命令发送失败] 强制关键帧: {}", e.getMessage()); + throw new ControllerException(ErrorCode.ERROR100.getCode(), "命令发送失败: " + e.getMessage()); } + JSONObject json = new JSONObject(); + json.put("DeviceID", deviceId); + json.put("ChannelID", channelId); + json.put("Result", "OK"); + return json; } /** @@ -240,7 +260,7 @@ public class DeviceControl { @Parameter(name = "presetIndex", description = "调用预置位编号") @Parameter(name = "resetTime", description = "自动归位时间间隔") @GetMapping("/home_position/{deviceId}/{enabled}") - public DeferredResult> homePositionApi(@PathVariable String deviceId, + public DeferredResult homePositionApi(@PathVariable String deviceId, @PathVariable String enabled, @RequestParam(required = false) String resetTime, @RequestParam(required = false) String presetIndex, @@ -251,14 +271,19 @@ public class DeviceControl { String key = DeferredResultHolder.CALLBACK_CMD_DEVICECONTROL + (ObjectUtils.isEmpty(channelId) ? deviceId : channelId); String uuid = UUID.randomUUID().toString(); Device device = storager.queryVideoDevice(deviceId); - cmder.homePositionCmd(device, channelId, enabled, resetTime, presetIndex, event -> { - RequestMessage msg = new RequestMessage(); - msg.setId(uuid); - msg.setKey(key); - msg.setData(String.format("看守位控制操作失败,错误码: %s, %s", event.statusCode, event.msg)); - resultHolder.invokeResult(msg); - }); - DeferredResult> result = new DeferredResult>(3 * 1000L); + try { + cmder.homePositionCmd(device, channelId, enabled, resetTime, presetIndex, event -> { + RequestMessage msg = new RequestMessage(); + msg.setId(uuid); + msg.setKey(key); + msg.setData(String.format("看守位控制操作失败,错误码: %s, %s", event.statusCode, event.msg)); + resultHolder.invokeResult(msg); + }); + } catch (InvalidArgumentException | SipException | ParseException e) { + logger.error("[命令发送失败] 看守位控制: {}", e.getMessage()); + throw new ControllerException(ErrorCode.ERROR100.getCode(), "命令发送失败: " + e.getMessage()); + } + DeferredResult result = new DeferredResult<>(3 * 1000L); result.onTimeout(() -> { logger.warn(String.format("看守位控制操作超时, 设备未返回应答指令")); // 释放rtpserver @@ -297,14 +322,14 @@ public class DeviceControl { @Parameter(name = "lengthx", description = "拉框长度像素值", required = true) @Parameter(name = "lengthy", description = "lengthy", required = true) @GetMapping("drag_zoom/zoom_in") - public ResponseEntity dragZoomIn(@RequestParam String deviceId, + public void dragZoomIn(@RequestParam String deviceId, @RequestParam(required = false) String channelId, @RequestParam int length, @RequestParam int width, @RequestParam int midpointx, @RequestParam int midpointy, @RequestParam int lengthx, - @RequestParam int lengthy){ + @RequestParam int lengthy) throws RuntimeException { if (logger.isDebugEnabled()) { logger.debug(String.format("设备拉框放大 API调用,deviceId:%s ,channelId:%s ,length:%d ,width:%d ,midpointx:%d ,midpointy:%d ,lengthx:%d ,lengthy:%d",deviceId, channelId, length, width, midpointx, midpointy,lengthx, lengthy)); } @@ -318,8 +343,12 @@ public class DeviceControl { cmdXml.append("" + lengthx+ "\r\n"); cmdXml.append("" + lengthy+ "\r\n"); cmdXml.append("\r\n"); - cmder.dragZoomCmd(device, channelId, cmdXml.toString()); - return new ResponseEntity("success", HttpStatus.OK); + try { + cmder.dragZoomCmd(device, channelId, cmdXml.toString()); + } catch (InvalidArgumentException | SipException | ParseException e) { + logger.error("[命令发送失败] 拉框放大: {}", e.getMessage()); + throw new ControllerException(ErrorCode.ERROR100.getCode(), "命令发送失败: " + e.getMessage()); + } } /** @@ -344,7 +373,7 @@ public class DeviceControl { @Parameter(name = "lengthx", description = "拉框长度像素值", required = true) @Parameter(name = "lengthy", description = "拉框宽度像素值", required = true) @GetMapping("/drag_zoom/zoom_out") - public ResponseEntity dragZoomOut(@RequestParam String deviceId, + public void dragZoomOut(@RequestParam String deviceId, @RequestParam(required = false) String channelId, @RequestParam int length, @RequestParam int width, @@ -366,7 +395,11 @@ public class DeviceControl { cmdXml.append("" + lengthx+ "\r\n"); cmdXml.append("" + lengthy+ "\r\n"); cmdXml.append("\r\n"); - cmder.dragZoomCmd(device, channelId, cmdXml.toString()); - return new ResponseEntity("success",HttpStatus.OK); + try { + cmder.dragZoomCmd(device, channelId, cmdXml.toString()); + } catch (InvalidArgumentException | SipException | ParseException e) { + logger.error("[命令发送失败] 拉框缩小: {}", e.getMessage()); + throw new ControllerException(ErrorCode.ERROR100.getCode(), "命令发送失败: " + e.getMessage()); + } } } diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceQuery.java b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceQuery.java index eb79fc79..37fb98e0 100644 --- a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceQuery.java +++ b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceQuery.java @@ -39,8 +39,11 @@ import org.springframework.web.context.request.async.DeferredResult; import javax.servlet.http.HttpServletResponse; import javax.sip.DialogState; +import javax.sip.InvalidArgumentException; +import javax.sip.SipException; import java.io.*; import java.nio.file.Files; +import java.text.ParseException; import java.util.*; @Tag(name = "国标设备查询", description = "国标设备查询") @@ -315,13 +318,18 @@ public class DeviceQuery { result.setResult(new ResponseEntity(String.format("设备%s不存在", deviceId),HttpStatus.OK)); return result; } - cmder.deviceStatusQuery(device, event -> { - RequestMessage msg = new RequestMessage(); - msg.setId(uuid); - msg.setKey(key); - msg.setData(String.format("获取设备状态失败,错误码: %s, %s", event.statusCode, event.msg)); - resultHolder.invokeResult(msg); - }); + try { + cmder.deviceStatusQuery(device, event -> { + RequestMessage msg = new RequestMessage(); + msg.setId(uuid); + msg.setKey(key); + msg.setData(String.format("获取设备状态失败,错误码: %s, %s", event.statusCode, event.msg)); + resultHolder.invokeResult(msg); + }); + } catch (InvalidArgumentException | SipException | ParseException e) { + logger.error("[命令发送失败] 获取设备状态: {}", e.getMessage()); + throw new ControllerException(ErrorCode.ERROR100.getCode(), "命令发送失败: " + e.getMessage()); + } result.onTimeout(()->{ logger.warn(String.format("获取设备状态超时")); // 释放rtpserver @@ -368,14 +376,19 @@ public class DeviceQuery { Device device = storager.queryVideoDevice(deviceId); String key = DeferredResultHolder.CALLBACK_CMD_ALARM + deviceId; String uuid = UUID.randomUUID().toString(); - cmder.alarmInfoQuery(device, startPriority, endPriority, alarmMethod, alarmType, startTime, endTime, event -> { - RequestMessage msg = new RequestMessage(); - msg.setId(uuid); - msg.setKey(key); - msg.setData(String.format("设备报警查询失败,错误码: %s, %s",event.statusCode, event.msg)); - resultHolder.invokeResult(msg); - }); - DeferredResult> result = new DeferredResult> (3 * 1000L); + try { + cmder.alarmInfoQuery(device, startPriority, endPriority, alarmMethod, alarmType, startTime, endTime, event -> { + RequestMessage msg = new RequestMessage(); + msg.setId(uuid); + msg.setKey(key); + msg.setData(String.format("设备报警查询失败,错误码: %s, %s",event.statusCode, event.msg)); + resultHolder.invokeResult(msg); + }); + } catch (InvalidArgumentException | SipException | ParseException e) { + logger.error("[命令发送失败] 设备报警查询: {}", e.getMessage()); + throw new ControllerException(ErrorCode.ERROR100.getCode(), "命令发送失败: " + e.getMessage()); + } + DeferredResult> result = new DeferredResult> (3 * 1000L); result.onTimeout(()->{ logger.warn(String.format("设备报警查询超时")); // 释放rtpserver diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/platform/PlatformController.java b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/platform/PlatformController.java index fa1de004..a1cb8716 100644 --- a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/platform/PlatformController.java +++ b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/platform/PlatformController.java @@ -29,6 +29,9 @@ import org.springframework.util.ObjectUtils; import org.springframework.web.bind.annotation.*; import com.genersoft.iot.vmp.conf.SipConfig; +import javax.sip.InvalidArgumentException; +import javax.sip.SipException; +import java.text.ParseException; import java.util.List; /** @@ -212,20 +215,37 @@ public class PlatformController { // 保存时启用就发送注册 if (parentPlatform.isEnable()) { if (parentPlatformOld != null && parentPlatformOld.isStatus()) { - commanderForPlatform.unregister(parentPlatformOld, null, null); + try { + commanderForPlatform.unregister(parentPlatformOld, null, null); + } catch (InvalidArgumentException | ParseException | SipException e) { + logger.error("[命令发送失败] 国标级联 注销: {}", e.getMessage()); + } try { Thread.sleep(500); } catch (InterruptedException e) { - e.printStackTrace(); + logger.error("[线程休眠失败] : {}", e.getMessage()); } // 只要保存就发送注册 - commanderForPlatform.register(parentPlatform, null, null); + try { + commanderForPlatform.register(parentPlatform, null, null); + } catch (InvalidArgumentException | ParseException | SipException e) { + logger.error("[命令发送失败] 国标级联 注册: {}", e.getMessage()); + } + } else { // 只要保存就发送注册 - commanderForPlatform.register(parentPlatform, null, null); + try { + commanderForPlatform.register(parentPlatform, null, null); + } catch (InvalidArgumentException | ParseException | SipException e) { + logger.error("[命令发送失败] 国标级联 注册: {}", e.getMessage()); + } } } else if (parentPlatformOld != null && parentPlatformOld.isEnable() && !parentPlatform.isEnable()) { // 关闭启用时注销 - commanderForPlatform.unregister(parentPlatformOld, null, null); + try { + commanderForPlatform.unregister(parentPlatformOld, null, null); + } catch (InvalidArgumentException | ParseException | SipException e) { + logger.error("[命令发送失败] 国标级联 注销: {}", e.getMessage()); + } // 停止订阅相关的定时任务 subscribeHolder.removeAllSubscribe(parentPlatform.getServerGBId()); } @@ -258,17 +278,21 @@ public class PlatformController { throw new ControllerException(ErrorCode.ERROR100.getCode(), "平台不存在"); } // 发送离线消息,无论是否成功都删除缓存 - commanderForPlatform.unregister(parentPlatform, (event -> { - // 清空redis缓存 - redisCatchStorage.delPlatformCatchInfo(parentPlatform.getServerGBId()); - redisCatchStorage.delPlatformKeepalive(parentPlatform.getServerGBId()); - redisCatchStorage.delPlatformRegister(parentPlatform.getServerGBId()); - }), (event -> { - // 清空redis缓存 - redisCatchStorage.delPlatformCatchInfo(parentPlatform.getServerGBId()); - redisCatchStorage.delPlatformKeepalive(parentPlatform.getServerGBId()); - redisCatchStorage.delPlatformRegister(parentPlatform.getServerGBId()); - })); + try { + commanderForPlatform.unregister(parentPlatform, (event -> { + // 清空redis缓存 + redisCatchStorage.delPlatformCatchInfo(parentPlatform.getServerGBId()); + redisCatchStorage.delPlatformKeepalive(parentPlatform.getServerGBId()); + redisCatchStorage.delPlatformRegister(parentPlatform.getServerGBId()); + }), (event -> { + // 清空redis缓存 + redisCatchStorage.delPlatformCatchInfo(parentPlatform.getServerGBId()); + redisCatchStorage.delPlatformKeepalive(parentPlatform.getServerGBId()); + redisCatchStorage.delPlatformRegister(parentPlatform.getServerGBId()); + })); + } catch (InvalidArgumentException | ParseException | SipException e) { + logger.error("[命令发送失败] 国标级联 注销: {}", e.getMessage()); + } boolean deleteResult = storager.deleteParentPlatform(parentPlatform); storager.delCatalogByPlatformId(parentPlatform.getServerGBId()); diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/play/PlayController.java b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/play/PlayController.java index 5d9bb2b9..b9652541 100644 --- a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/play/PlayController.java +++ b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/play/PlayController.java @@ -3,6 +3,7 @@ package com.genersoft.iot.vmp.vmanager.gb28181.play; import com.alibaba.fastjson.JSONArray; import com.genersoft.iot.vmp.common.StreamInfo; import com.genersoft.iot.vmp.conf.exception.ControllerException; +import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException; import com.genersoft.iot.vmp.gb28181.bean.SsrcTransaction; import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager; import com.genersoft.iot.vmp.gb28181.bean.Device; @@ -36,6 +37,9 @@ import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; import com.genersoft.iot.vmp.storager.IVideoManagerStorage; import org.springframework.web.context.request.async.DeferredResult; +import javax.sip.InvalidArgumentException; +import javax.sip.SipException; +import java.text.ParseException; import java.util.List; import java.util.UUID; @@ -102,12 +106,23 @@ public class PlayController { throw new ControllerException(ErrorCode.ERROR400); } + Device device = storager.queryVideoDevice(deviceId); + if (device == null) { + throw new ControllerException(ErrorCode.ERROR100.getCode(), "设备[" + deviceId + "]不存在"); + } + StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(deviceId, channelId); if (streamInfo == null) { throw new ControllerException(ErrorCode.ERROR100.getCode(), "点播未找到"); } - cmder.streamByeCmd(deviceId, channelId, streamInfo.getStream(), null, null); + try { + logger.warn("[停止点播] {}/{}", device.getDeviceId(), channelId); + cmder.streamByeCmd(device, channelId, streamInfo.getStream(), null, null); + } catch (InvalidArgumentException | SipException | ParseException | SsrcTransactionNotFoundException e) { + logger.error("[命令发送失败] 停止点播, 发送BYE: {}", e.getMessage()); + throw new ControllerException(ErrorCode.ERROR100.getCode(), "命令发送失败: " + e.getMessage()); + } redisCatchStorage.stopPlay(streamInfo); storager.stopPlay(streamInfo.getDeviceID(), streamInfo.getChannelId()); @@ -221,18 +236,23 @@ public class PlayController { resultHolder.invokeResult(msg); return result; } - cmder.audioBroadcastCmd(device, (event) -> { - RequestMessage msg = new RequestMessage(); - msg.setKey(key); - msg.setId(uuid); - JSONObject json = new JSONObject(); - json.put("DeviceID", deviceId); - json.put("CmdType", "Broadcast"); - json.put("Result", "Failed"); - json.put("Description", String.format("语音广播操作失败,错误码: %s, %s", event.statusCode, event.msg)); - msg.setData(json); - resultHolder.invokeResult(msg); - }); + try { + cmder.audioBroadcastCmd(device, (event) -> { + RequestMessage msg = new RequestMessage(); + msg.setKey(key); + msg.setId(uuid); + JSONObject json = new JSONObject(); + json.put("DeviceID", deviceId); + json.put("CmdType", "Broadcast"); + json.put("Result", "Failed"); + json.put("Description", String.format("语音广播操作失败,错误码: %s, %s", event.statusCode, event.msg)); + msg.setData(json); + resultHolder.invokeResult(msg); + }); + } catch (InvalidArgumentException | SipException | ParseException e) { + logger.error("[命令发送失败] 语音广播: {}", e.getMessage()); + throw new ControllerException(ErrorCode.ERROR100.getCode(), "命令发送失败: " + e.getMessage()); + } result.onTimeout(() -> { logger.warn("语音广播操作超时, 设备未返回应答指令"); diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/playback/PlaybackController.java b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/playback/PlaybackController.java index 33c02ad6..20860bfb 100644 --- a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/playback/PlaybackController.java +++ b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/playback/PlaybackController.java @@ -2,6 +2,7 @@ package com.genersoft.iot.vmp.vmanager.gb28181.playback; import com.genersoft.iot.vmp.common.StreamInfo; import com.genersoft.iot.vmp.conf.exception.ControllerException; +import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException; import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage; import com.genersoft.iot.vmp.storager.IRedisCatchStorage; @@ -21,12 +22,15 @@ import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; -import com.alibaba.fastjson.JSONObject; import com.genersoft.iot.vmp.gb28181.bean.Device; import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; import com.genersoft.iot.vmp.storager.IVideoManagerStorage; import org.springframework.web.context.request.async.DeferredResult; +import javax.sip.InvalidArgumentException; +import javax.sip.SipException; +import java.text.ParseException; + /** * @author lin */ @@ -92,7 +96,15 @@ public class PlaybackController { if (ObjectUtils.isEmpty(deviceId) || ObjectUtils.isEmpty(channelId) || ObjectUtils.isEmpty(stream)) { throw new ControllerException(ErrorCode.ERROR400); } - cmder.streamByeCmd(deviceId, channelId, stream, null); + Device device = storager.queryVideoDevice(deviceId); + if (device == null) { + throw new ControllerException(ErrorCode.ERROR400.getCode(), "设备:" + deviceId + " 未找到"); + } + try { + cmder.streamByeCmd(device, channelId, stream, null); + } catch (InvalidArgumentException | ParseException | SipException | SsrcTransactionNotFoundException e) { + throw new ControllerException(ErrorCode.ERROR100.getCode(), "发送bye失败: " + e.getMessage()); + } } @@ -107,7 +119,11 @@ public class PlaybackController { throw new ControllerException(ErrorCode.ERROR400.getCode(), "streamId不存在"); } Device device = storager.queryVideoDevice(streamInfo.getDeviceID()); - cmder.playPauseCmd(device, streamInfo); + try { + cmder.playPauseCmd(device, streamInfo); + } catch (InvalidArgumentException | ParseException | SipException e) { + throw new ControllerException(ErrorCode.ERROR100.getCode(), e.getMessage()); + } } @@ -122,7 +138,11 @@ public class PlaybackController { throw new ControllerException(ErrorCode.ERROR400.getCode(), "streamId不存在"); } Device device = storager.queryVideoDevice(streamInfo.getDeviceID()); - cmder.playResumeCmd(device, streamInfo); + try { + cmder.playResumeCmd(device, streamInfo); + } catch (InvalidArgumentException | ParseException | SipException e) { + throw new ControllerException(ErrorCode.ERROR100.getCode(), e.getMessage()); + } } @@ -138,7 +158,11 @@ public class PlaybackController { throw new ControllerException(ErrorCode.ERROR400.getCode(), "streamId不存在"); } Device device = storager.queryVideoDevice(streamInfo.getDeviceID()); - cmder.playSeekCmd(device, streamInfo, seekTime); + try { + cmder.playSeekCmd(device, streamInfo, seekTime); + } catch (InvalidArgumentException | ParseException | SipException e) { + throw new ControllerException(ErrorCode.ERROR100.getCode(), e.getMessage()); + } } @Operation(summary = "回放倍速播放") @@ -157,6 +181,10 @@ public class PlaybackController { throw new ControllerException(ErrorCode.ERROR100.getCode(), "不支持的speed(0.25 0.5 1、2、4)"); } Device device = storager.queryVideoDevice(streamInfo.getDeviceID()); - cmder.playSpeedCmd(device, streamInfo, speed); + try { + cmder.playSpeedCmd(device, streamInfo, speed); + } catch (InvalidArgumentException | ParseException | SipException e) { + throw new ControllerException(ErrorCode.ERROR100.getCode(), e.getMessage()); + } } } diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/ptz/PtzController.java b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/ptz/PtzController.java index 6903e4d3..171f57ca 100644 --- a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/ptz/PtzController.java +++ b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/ptz/PtzController.java @@ -1,6 +1,8 @@ package com.genersoft.iot.vmp.vmanager.gb28181.ptz; +import com.genersoft.iot.vmp.conf.exception.ControllerException; +import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; @@ -18,6 +20,9 @@ import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage; import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; import com.genersoft.iot.vmp.storager.IVideoManagerStorage; +import javax.sip.InvalidArgumentException; +import javax.sip.SipException; +import java.text.ParseException; import java.util.UUID; @Tag(name = "云台控制") @@ -98,7 +103,12 @@ public class PtzController { default: break; } - cmder.frontEndCmd(device, channelId, cmdCode, horizonSpeed, verticalSpeed, zoomSpeed); + try { + cmder.frontEndCmd(device, channelId, cmdCode, horizonSpeed, verticalSpeed, zoomSpeed); + } catch (SipException | InvalidArgumentException | ParseException e) { + logger.error("[命令发送失败] 云台控制: {}", e.getMessage()); + throw new ControllerException(ErrorCode.ERROR100.getCode(), "命令发送失败: " + e.getMessage()); + } } @@ -117,7 +127,12 @@ public class PtzController { } Device device = storager.queryVideoDevice(deviceId); - cmder.frontEndCmd(device, channelId, cmdCode, parameter1, parameter2, combindCode2); + try { + cmder.frontEndCmd(device, channelId, cmdCode, parameter1, parameter2, combindCode2); + } catch (SipException | InvalidArgumentException | ParseException e) { + logger.error("[命令发送失败] 前端控制: {}", e.getMessage()); + throw new ControllerException(ErrorCode.ERROR100.getCode(), "命令发送失败: " + e.getMessage()); + } } @@ -146,13 +161,18 @@ public class PtzController { return result; } resultHolder.put(key, uuid, result); - cmder.presetQuery(device, channelId, event -> { - RequestMessage msg = new RequestMessage(); - msg.setId(uuid); - msg.setKey(key); - msg.setData(String.format("获取设备预置位失败,错误码: %s, %s", event.statusCode, event.msg)); - resultHolder.invokeResult(msg); - }); + try { + cmder.presetQuery(device, channelId, event -> { + RequestMessage msg = new RequestMessage(); + msg.setId(uuid); + msg.setKey(key); + msg.setData(String.format("获取设备预置位失败,错误码: %s, %s", event.statusCode, event.msg)); + resultHolder.invokeResult(msg); + }); + } catch (InvalidArgumentException | SipException | ParseException e) { + logger.error("[命令发送失败] 获取设备预置位: {}", e.getMessage()); + throw new ControllerException(ErrorCode.ERROR100.getCode(), "命令发送失败: " + e.getMessage()); + } return result; } } diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/record/GBRecordController.java b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/record/GBRecordController.java index 755b37b7..b09467ab 100644 --- a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/record/GBRecordController.java +++ b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/record/GBRecordController.java @@ -3,7 +3,9 @@ package com.genersoft.iot.vmp.vmanager.gb28181.record; import com.alibaba.fastjson.JSONObject; import com.genersoft.iot.vmp.common.StreamInfo; import com.genersoft.iot.vmp.conf.exception.ControllerException; +import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException; import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage; +import com.genersoft.iot.vmp.service.IDeviceService; import com.genersoft.iot.vmp.service.IMediaServerService; import com.genersoft.iot.vmp.service.IPlayService; import com.genersoft.iot.vmp.utils.DateUtil; @@ -31,6 +33,9 @@ import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; import com.genersoft.iot.vmp.storager.IVideoManagerStorage; +import javax.sip.InvalidArgumentException; +import javax.sip.SipException; +import java.text.ParseException; import java.time.LocalDate; import java.util.UUID; @@ -54,6 +59,12 @@ public class GBRecordController { @Autowired private IPlayService playService; + @Autowired + private IDeviceService deviceService; + + + + @Operation(summary = "录像查询") @Parameter(name = "deviceId", description = "设备国标编号", required = true) @Parameter(name = "channelId", description = "通道国标编号", required = true) @@ -81,13 +92,18 @@ public class GBRecordController { RequestMessage msg = new RequestMessage(); msg.setId(uuid); msg.setKey(key); - cmder.recordInfoQuery(device, channelId, startTime, endTime, sn, null, null, null, (eventResult -> { - WVPResult wvpResult = new WVPResult<>(); - wvpResult.setCode(ErrorCode.ERROR100.getCode()); - wvpResult.setMsg("查询录像失败, status: " + eventResult.statusCode + ", message: " + eventResult.msg); - msg.setData(wvpResult); - resultHolder.invokeResult(msg); - })); + try { + cmder.recordInfoQuery(device, channelId, startTime, endTime, sn, null, null, null, (eventResult -> { + WVPResult wvpResult = new WVPResult<>(); + wvpResult.setCode(ErrorCode.ERROR100.getCode()); + wvpResult.setMsg("查询录像失败, status: " + eventResult.statusCode + ", message: " + eventResult.msg); + msg.setData(wvpResult); + resultHolder.invokeResult(msg); + })); + } catch (InvalidArgumentException | SipException | ParseException e) { + logger.error("[命令发送失败] 查询录像: {}", e.getMessage()); + throw new ControllerException(ErrorCode.ERROR100.getCode(), "命令发送失败: " + e.getMessage()); + } // 录像查询以channelId作为deviceId查询 resultHolder.put(key, uuid, result); @@ -131,14 +147,24 @@ public class GBRecordController { @GetMapping("/download/stop/{deviceId}/{channelId}/{stream}") public void playStop(@PathVariable String deviceId, @PathVariable String channelId, @PathVariable String stream) { - cmder.streamByeCmd(deviceId, channelId, stream, null); - if (logger.isDebugEnabled()) { logger.debug(String.format("设备历史媒体下载停止 API调用,deviceId/channelId:%s_%s", deviceId, channelId)); } if (deviceId == null || channelId == null) { - throw new ControllerException(ErrorCode.ERROR100); + throw new ControllerException(ErrorCode.ERROR400); + } + + Device device = deviceService.queryDevice(deviceId); + if (device == null) { + throw new ControllerException(ErrorCode.ERROR400.getCode(), "设备:" + deviceId + "未找到"); + } + + try { + cmder.streamByeCmd(device, channelId, stream, null); + } catch (InvalidArgumentException | ParseException | SipException | SsrcTransactionNotFoundException e) { + logger.error("[停止历史媒体下载]停止历史媒体下载,发送BYE失败 {}", e.getMessage()); + throw new ControllerException(ErrorCode.ERROR100.getCode(), e.getMessage()); } } diff --git a/src/main/java/com/genersoft/iot/vmp/web/gb28181/ApiControlController.java b/src/main/java/com/genersoft/iot/vmp/web/gb28181/ApiControlController.java index 9bbe1d7e..c8173853 100644 --- a/src/main/java/com/genersoft/iot/vmp/web/gb28181/ApiControlController.java +++ b/src/main/java/com/genersoft/iot/vmp/web/gb28181/ApiControlController.java @@ -1,14 +1,20 @@ package com.genersoft.iot.vmp.web.gb28181; import com.alibaba.fastjson.JSONObject; +import com.genersoft.iot.vmp.conf.exception.ControllerException; import com.genersoft.iot.vmp.gb28181.bean.Device; import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; import com.genersoft.iot.vmp.storager.IVideoManagerStorage; +import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; +import javax.sip.InvalidArgumentException; +import javax.sip.SipException; +import java.text.ParseException; + /** * API兼容:设备控制 */ @@ -35,7 +41,7 @@ public class ApiControlController { * @return */ @RequestMapping(value = "/ptz") - private JSONObject list(String serial,String command, + private void list(String serial,String command, @RequestParam(required = false)Integer channel, @RequestParam(required = false)String code, @RequestParam(required = false)Integer speed){ @@ -48,9 +54,7 @@ public class ApiControlController { if (speed == null) {speed = 0;} Device device = storager.queryVideoDevice(serial); if (device == null) { - JSONObject result = new JSONObject(); - result.put("error","device[ " + serial + " ]未找到"); - return result; + throw new ControllerException(ErrorCode.ERROR100.getCode(), "device[ " + serial + " ]未找到"); } int cmdCode = 0; switch (command){ @@ -91,7 +95,11 @@ public class ApiControlController { break; } // 默认值 50 - cmder.frontEndCmd(device, code, cmdCode, speed, speed, speed); - return null; + try { + cmder.frontEndCmd(device, code, cmdCode, speed, speed, speed); + } catch (SipException | InvalidArgumentException | ParseException e) { + logger.error("[命令发送失败] 云台控制: {}", e.getMessage()); + throw new ControllerException(ErrorCode.ERROR100.getCode(), "命令发送失败: " + e.getMessage()); + } } } diff --git a/src/main/java/com/genersoft/iot/vmp/web/gb28181/ApiStreamController.java b/src/main/java/com/genersoft/iot/vmp/web/gb28181/ApiStreamController.java index 9b722004..07c93fbb 100644 --- a/src/main/java/com/genersoft/iot/vmp/web/gb28181/ApiStreamController.java +++ b/src/main/java/com/genersoft/iot/vmp/web/gb28181/ApiStreamController.java @@ -3,10 +3,12 @@ package com.genersoft.iot.vmp.web.gb28181; import com.alibaba.fastjson.JSONObject; import com.genersoft.iot.vmp.common.StreamInfo; import com.genersoft.iot.vmp.conf.UserSetting; +import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException; import com.genersoft.iot.vmp.gb28181.bean.Device; import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; +import com.genersoft.iot.vmp.service.IDeviceService; import com.genersoft.iot.vmp.service.IPlayService; import com.genersoft.iot.vmp.storager.IRedisCatchStorage; import com.genersoft.iot.vmp.storager.IVideoManagerStorage; @@ -17,6 +19,10 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; import org.springframework.web.context.request.async.DeferredResult; +import javax.sip.InvalidArgumentException; +import javax.sip.SipException; +import java.text.ParseException; + /** * API兼容:实时直播 */ @@ -40,6 +46,9 @@ public class ApiStreamController { @Autowired private IRedisCatchStorage redisCatchStorage; + @Autowired + private IDeviceService deviceService; + @Autowired private IPlayService playService; @@ -177,7 +186,19 @@ public class ApiStreamController { result.put("error","未找到流信息"); return result; } - cmder.streamByeCmd(serial, code, streamInfo.getStream(), null); + Device device = deviceService.queryDevice(serial); + if (device == null) { + JSONObject result = new JSONObject(); + result.put("error","未找到设备"); + return result; + } + try { + cmder.streamByeCmd(device, code, streamInfo.getStream(), null); + } catch (InvalidArgumentException | ParseException | SipException | SsrcTransactionNotFoundException e) { + JSONObject result = new JSONObject(); + result.put("error","发送BYE失败:" + e.getMessage()); + return result; + } redisCatchStorage.stopPlay(streamInfo); storager.stopPlay(streamInfo.getDeviceID(), streamInfo.getChannelId()); return null; From e44e3dc9400a0c11572ec62651cb586640dc1725 Mon Sep 17 00:00:00 2001 From: 648540858 <648540858@qq.com> Date: Fri, 23 Sep 2022 23:08:58 +0800 Subject: [PATCH 2/2] =?UTF-8?q?=E5=BC=82=E5=B8=B8=E6=83=85=E5=86=B5?= =?UTF-8?q?=E6=89=93=E5=8D=B0=E4=BF=A1=E6=81=AF=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../iot/vmp/conf/SystemInfoTimerTask.java | 7 +- .../genersoft/iot/vmp/conf/VersionInfo.java | 14 +--- .../gb28181/auth/RegisterLogicHandler.java | 44 ----------- .../event/alarm/AlarmEventListener.java | 1 - .../session/VideoStreamSessionManager.java | 8 -- .../cmd/impl/SIPCommanderFroPlatform.java | 5 -- .../request/impl/InviteRequestProcessor.java | 16 +--- .../impl/info/InfoRequestProcessor.java | 16 +--- .../notify/cmd/AlarmNotifyMessageHandler.java | 8 +- .../cmd/KeepaliveNotifyMessageHandler.java | 8 +- .../cmd/MediaStatusNotifyMessageHandler.java | 8 +- .../query/cmd/AlarmQueryMessageHandler.java | 8 +- .../query/cmd/CatalogQueryMessageHandler.java | 8 +- .../cmd/BroadcastResponseMessageHandler.java | 2 +- .../ConfigDownloadResponseMessageHandler.java | 8 +- .../DeviceControlResponseMessageHandler.java | 8 +- .../DeviceStatusResponseMessageHandler.java | 8 +- .../cmd/RecordInfoResponseMessageHandler.java | 12 +-- .../timeout/impl/TimeoutProcessorImpl.java | 7 +- .../impl/StreamPushUploadFileHandler.java | 1 - .../redisMsg/RedisGbPlayMsgListener.java | 2 +- .../com/genersoft/iot/vmp/utils/GpsUtil.java | 43 ----------- .../com/genersoft/iot/vmp/utils/IpUtil.java | 48 ------------ .../genersoft/iot/vmp/utils/JarFileUtils.java | 73 ------------------- .../iot/vmp/utils/SerializeUtils.java | 31 -------- .../gb28181/media/MediaController.java | 2 +- 26 files changed, 44 insertions(+), 352 deletions(-) delete mode 100644 src/main/java/com/genersoft/iot/vmp/gb28181/auth/RegisterLogicHandler.java delete mode 100644 src/main/java/com/genersoft/iot/vmp/utils/IpUtil.java delete mode 100644 src/main/java/com/genersoft/iot/vmp/utils/JarFileUtils.java delete mode 100644 src/main/java/com/genersoft/iot/vmp/utils/SerializeUtils.java diff --git a/src/main/java/com/genersoft/iot/vmp/conf/SystemInfoTimerTask.java b/src/main/java/com/genersoft/iot/vmp/conf/SystemInfoTimerTask.java index 13ec6927..74a90c24 100644 --- a/src/main/java/com/genersoft/iot/vmp/conf/SystemInfoTimerTask.java +++ b/src/main/java/com/genersoft/iot/vmp/conf/SystemInfoTimerTask.java @@ -1,7 +1,10 @@ package com.genersoft.iot.vmp.conf; +import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.query.cmd.AlarmQueryMessageHandler; import com.genersoft.iot.vmp.storager.IRedisCatchStorage; import com.genersoft.iot.vmp.utils.SystemInfoUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; @@ -14,6 +17,8 @@ import java.util.Map; @Component public class SystemInfoTimerTask { + private Logger logger = LoggerFactory.getLogger(SystemInfoTimerTask.class); + @Autowired private IRedisCatchStorage redisCatchStorage; @@ -27,7 +32,7 @@ public class SystemInfoTimerTask { Map networkInterfaces = SystemInfoUtils.getNetworkInterfaces(); redisCatchStorage.addNetInfo(networkInterfaces); } catch (InterruptedException e) { - e.printStackTrace(); + logger.error("[获取系统信息失败] {}", e.getMessage()); } } diff --git a/src/main/java/com/genersoft/iot/vmp/conf/VersionInfo.java b/src/main/java/com/genersoft/iot/vmp/conf/VersionInfo.java index 4ff5eba6..5551b4f3 100644 --- a/src/main/java/com/genersoft/iot/vmp/conf/VersionInfo.java +++ b/src/main/java/com/genersoft/iot/vmp/conf/VersionInfo.java @@ -2,35 +2,23 @@ package com.genersoft.iot.vmp.conf; import com.genersoft.iot.vmp.common.VersionPo; import com.genersoft.iot.vmp.utils.GitUtil; -import com.genersoft.iot.vmp.utils.JarFileUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; -import java.util.Map; - @Component public class VersionInfo { - @Autowired - VersionConfig config; @Autowired GitUtil gitUtil; - @Autowired - JarFileUtils jarFileUtils; public VersionPo getVersion() { VersionPo versionPo = new VersionPo(); - Map map=jarFileUtils.readJarFile(); versionPo.setGIT_Revision(gitUtil.getGitCommitId()); - versionPo.setCreate_By(map.get("Created-By")); versionPo.setGIT_BRANCH(gitUtil.getBranch()); versionPo.setGIT_URL(gitUtil.getGitUrl()); versionPo.setBUILD_DATE(gitUtil.getBuildDate()); - versionPo.setArtifactId(config.getArtifactId()); versionPo.setGIT_Revision_SHORT(gitUtil.getCommitIdShort()); - versionPo.setVersion(config.getVersion()); - versionPo.setProject(config.getDescription()); - versionPo.setBuild_Jdk(map.get("Build-Jdk")); + versionPo.setVersion(gitUtil.getBuildVersion()); return versionPo; } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/auth/RegisterLogicHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/auth/RegisterLogicHandler.java deleted file mode 100644 index 8731228a..00000000 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/auth/RegisterLogicHandler.java +++ /dev/null @@ -1,44 +0,0 @@ -package com.genersoft.iot.vmp.gb28181.auth; - -import com.genersoft.iot.vmp.storager.impl.VideoManagerStorageImpl; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -import com.genersoft.iot.vmp.gb28181.bean.Device; -import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; - -/** - * @description:注册逻辑处理,当设备注册后触发逻辑。 - * @author: swwheihei - * @date: 2020年5月8日 下午9:41:46 - */ -@Component -public class RegisterLogicHandler { - - private Logger logger = LoggerFactory.getLogger(RegisterLogicHandler.class); - - @Autowired - private SIPCommander cmder; - - @Autowired - private VideoManagerStorageImpl storager; - - public void onRegister(Device device) { - // 只有第一次注册时调用查询设备信息,如需更新调用更新API接口 -// // TODO 此处错误无法获取到通道 -// Device device1 = storager.queryVideoDevice(device.getDeviceId()); -// if (device.isFirsRegister()) { -// logger.info("[{}] 首次注册,查询设备信息以及通道信息", device.getDeviceId()); -// try { -// Thread.sleep(100); -// cmder.deviceInfoQuery(device); -// Thread.sleep(100); -// cmder.catalogQuery(device, null); -// } catch (InterruptedException e) { -// e.printStackTrace(); -// } -// } - } -} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/event/alarm/AlarmEventListener.java b/src/main/java/com/genersoft/iot/vmp/gb28181/event/alarm/AlarmEventListener.java index 2b563269..9ee64773 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/event/alarm/AlarmEventListener.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/event/alarm/AlarmEventListener.java @@ -51,7 +51,6 @@ public class AlarmEventListener implements ApplicationListener { } // 移除已关闭的连接 it.remove(); - // e.printStackTrace(); } } } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/session/VideoStreamSessionManager.java b/src/main/java/com/genersoft/iot/vmp/gb28181/session/VideoStreamSessionManager.java index 6e7b3dcc..9bd3d57d 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/session/VideoStreamSessionManager.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/session/VideoStreamSessionManager.java @@ -3,23 +3,15 @@ package com.genersoft.iot.vmp.gb28181.session; import java.util.ArrayList; import java.util.List; -import javax.sip.ClientTransaction; -import javax.sip.Dialog; - import com.genersoft.iot.vmp.common.VideoManagerConstants; import com.genersoft.iot.vmp.conf.UserSetting; -import com.genersoft.iot.vmp.gb28181.bean.SipMsgInfo; import com.genersoft.iot.vmp.gb28181.bean.SipTransactionInfo; import com.genersoft.iot.vmp.gb28181.bean.SsrcTransaction; -import com.genersoft.iot.vmp.utils.SerializeUtils; import com.genersoft.iot.vmp.utils.redis.RedisUtil; -import gov.nist.javax.sip.message.SIPRequest; import gov.nist.javax.sip.message.SIPResponse; -import gov.nist.javax.sip.stack.SIPDialog; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.util.ObjectUtils; -import org.springframework.util.StringUtils; /** * @description:视频流session管理器,管理视频预览、预览回放的通信句柄 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java index bfc1ea9d..4b67c1b2 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java @@ -13,11 +13,7 @@ import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; import com.genersoft.iot.vmp.service.IMediaServerService; import com.genersoft.iot.vmp.service.bean.GPSMsgInfo; import com.genersoft.iot.vmp.storager.IRedisCatchStorage; -import com.genersoft.iot.vmp.utils.GitUtil; -import com.genersoft.iot.vmp.utils.SerializeUtils; -import gov.nist.javax.sip.SIPConstants; import gov.nist.javax.sip.SipProviderImpl; -import gov.nist.javax.sip.SipStackImpl; import gov.nist.javax.sip.message.MessageFactoryImpl; import gov.nist.javax.sip.message.SIPRequest; import org.slf4j.Logger; @@ -27,7 +23,6 @@ import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.DependsOn; import org.springframework.context.annotation.Lazy; import org.springframework.lang.Nullable; -import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import org.springframework.stereotype.Component; import org.springframework.util.ObjectUtils; diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java index 09436edb..57231810 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java @@ -661,12 +661,8 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements mediaListManager.removedChannelOnlineEventLister(gbStream.getApp(), gbStream.getStream()); try { responseAck(serverTransaction, Response.TEMPORARILY_UNAVAILABLE, response.getMsg()); - } catch (SipException e) { - throw new RuntimeException(e); - } catch (InvalidArgumentException e) { - throw new RuntimeException(e); - } catch (ParseException e) { - throw new RuntimeException(e); + } catch (SipException | InvalidArgumentException | ParseException e) { + logger.error("[命令发送失败] 国标级联 点播回复: {}", e.getMessage()); } } }); @@ -733,12 +729,8 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements mediaTransmissionTCP, channelId, addressStr, ssrc, requesterId); } } - } catch (InvalidArgumentException e) { - throw new RuntimeException(e); - } catch (ParseException e) { - throw new RuntimeException(e); - } catch (SipException e) { - throw new RuntimeException(e); + } catch (InvalidArgumentException | ParseException | SipException e) { + logger.error("[命令发送失败] 国标级联 点播回复: {}", e.getMessage()); } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/info/InfoRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/info/InfoRequestProcessor.java index b5f16ac9..66f54420 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/info/InfoRequestProcessor.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/info/InfoRequestProcessor.java @@ -115,23 +115,15 @@ public class InfoRequestProcessor extends SIPRequestProcessorParent implements I // 失败的回复 try { responseAck(serverTransaction, eventResult.statusCode, eventResult.msg); - } catch (SipException e) { - e.printStackTrace(); - } catch (InvalidArgumentException e) { - e.printStackTrace(); - } catch (ParseException e) { - e.printStackTrace(); + } catch (SipException | InvalidArgumentException | ParseException e) { + logger.error("[命令发送失败] 国标级联 录像控制: {}", e.getMessage()); } }, eventResult -> { // 成功的回复 try { responseAck(serverTransaction, eventResult.statusCode); - } catch (SipException e) { - e.printStackTrace(); - } catch (InvalidArgumentException e) { - e.printStackTrace(); - } catch (ParseException e) { - e.printStackTrace(); + } catch (SipException | InvalidArgumentException | ParseException e) { + logger.error("[命令发送失败] 国标级联 录像控制: {}", e.getMessage()); } }); } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/AlarmNotifyMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/AlarmNotifyMessageHandler.java index da2cb9c3..bc80c589 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/AlarmNotifyMessageHandler.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/AlarmNotifyMessageHandler.java @@ -216,12 +216,8 @@ public class AlarmNotifyMessageHandler extends SIPRequestProcessorParent impleme // 回复200 OK try { responseAck(getServerTransaction(evt), Response.OK); - } catch (SipException e) { - throw new RuntimeException(e); - } catch (InvalidArgumentException e) { - throw new RuntimeException(e); - } catch (ParseException e) { - throw new RuntimeException(e); + } catch (SipException | InvalidArgumentException | ParseException e) { + logger.error("[命令发送失败] 国标级联 报警通知回复: {}", e.getMessage()); } Element deviceIdElement = rootElement.element("DeviceID"); String channelId = deviceIdElement.getText().toString(); diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/KeepaliveNotifyMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/KeepaliveNotifyMessageHandler.java index 63dc7d8f..289f1628 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/KeepaliveNotifyMessageHandler.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/KeepaliveNotifyMessageHandler.java @@ -78,12 +78,8 @@ public class KeepaliveNotifyMessageHandler extends SIPRequestProcessorParent imp deviceService.online(device); } } - } catch (SipException e) { - e.printStackTrace(); - } catch (InvalidArgumentException e) { - e.printStackTrace(); - } catch (ParseException e) { - e.printStackTrace(); + } catch (SipException | InvalidArgumentException | ParseException e) { + logger.error("[命令发送失败] 国标级联 心跳回复: {}", e.getMessage()); } } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/MediaStatusNotifyMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/MediaStatusNotifyMessageHandler.java index 98d42d6e..041f7391 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/MediaStatusNotifyMessageHandler.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/MediaStatusNotifyMessageHandler.java @@ -68,12 +68,8 @@ public class MediaStatusNotifyMessageHandler extends SIPRequestProcessorParent i // 回复200 OK try { responseAck(getServerTransaction(evt), Response.OK); - } catch (SipException e) { - e.printStackTrace(); - } catch (InvalidArgumentException e) { - e.printStackTrace(); - } catch (ParseException e) { - e.printStackTrace(); + } catch (SipException | InvalidArgumentException | ParseException e) { + logger.error("[命令发送失败] 国标级联 录像流推送完毕,回复200OK: {}", e.getMessage()); } CallIdHeader callIdHeader = (CallIdHeader)evt.getRequest().getHeader(CallIdHeader.NAME); String NotifyType =getText(rootElement, "NotifyType"); diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/AlarmQueryMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/AlarmQueryMessageHandler.java index e35da0ea..be24faa2 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/AlarmQueryMessageHandler.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/AlarmQueryMessageHandler.java @@ -59,12 +59,8 @@ public class AlarmQueryMessageHandler extends SIPRequestProcessorParent implemen logger.info("不支持alarm查询"); try { responseAck(getServerTransaction(evt), Response.NOT_FOUND, "not support alarm query"); - } catch (SipException e) { - e.printStackTrace(); - } catch (InvalidArgumentException e) { - e.printStackTrace(); - } catch (ParseException e) { - e.printStackTrace(); + } catch (SipException | InvalidArgumentException | ParseException e) { + logger.error("[命令发送失败] 国标级联 alarm查询回复200OK: {}", e.getMessage()); } } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/CatalogQueryMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/CatalogQueryMessageHandler.java index cd98094d..82f4a257 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/CatalogQueryMessageHandler.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/CatalogQueryMessageHandler.java @@ -100,12 +100,8 @@ public class CatalogQueryMessageHandler extends SIPRequestProcessorParent implem // 回复无通道 cmderFroPlatform.catalogQuery(null, parentPlatform, sn, fromHeader.getTag(), 0); } - } catch (SipException e) { - e.printStackTrace(); - } catch (InvalidArgumentException e) { - e.printStackTrace(); - } catch (ParseException e) { - e.printStackTrace(); + } catch (SipException | InvalidArgumentException | ParseException e) { + logger.error("[命令发送失败] 国标级联 目录查询: {}", e.getMessage()); } } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/BroadcastResponseMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/BroadcastResponseMessageHandler.java index b1bd489d..8192043c 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/BroadcastResponseMessageHandler.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/BroadcastResponseMessageHandler.java @@ -63,7 +63,7 @@ public class BroadcastResponseMessageHandler extends SIPRequestProcessorParent i } catch (ParseException | SipException | InvalidArgumentException e) { - e.printStackTrace(); + logger.error("[命令发送失败] 国标级联 语音喊话: {}", e.getMessage()); } } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/ConfigDownloadResponseMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/ConfigDownloadResponseMessageHandler.java index 200677a1..1c4aa8a8 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/ConfigDownloadResponseMessageHandler.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/ConfigDownloadResponseMessageHandler.java @@ -63,12 +63,8 @@ public class ConfigDownloadResponseMessageHandler extends SIPRequestProcessorPar msg.setKey(key); msg.setData(json); deferredResultHolder.invokeAllResult(msg); - } catch (SipException e) { - e.printStackTrace(); - } catch (InvalidArgumentException e) { - e.printStackTrace(); - } catch (ParseException e) { - e.printStackTrace(); + } catch (SipException | InvalidArgumentException | ParseException e) { + logger.error("[命令发送失败] 国标级联 设备配置查询: {}", e.getMessage()); } } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/DeviceControlResponseMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/DeviceControlResponseMessageHandler.java index cd6d1b83..12c84686 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/DeviceControlResponseMessageHandler.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/DeviceControlResponseMessageHandler.java @@ -58,12 +58,8 @@ public class DeviceControlResponseMessageHandler extends SIPRequestProcessorPare msg.setKey(key); msg.setData(json); deferredResultHolder.invokeAllResult(msg); - } catch (SipException e) { - e.printStackTrace(); - } catch (InvalidArgumentException e) { - e.printStackTrace(); - } catch (ParseException e) { - e.printStackTrace(); + } catch (SipException | InvalidArgumentException | ParseException e) { + logger.error("[命令发送失败] 国标级联 设备控制: {}", e.getMessage()); } } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/DeviceStatusResponseMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/DeviceStatusResponseMessageHandler.java index b324b5d2..e96ecec9 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/DeviceStatusResponseMessageHandler.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/DeviceStatusResponseMessageHandler.java @@ -60,12 +60,8 @@ public class DeviceStatusResponseMessageHandler extends SIPRequestProcessorParen // 回复200 OK try { responseAck(getServerTransaction(evt), Response.OK); - } catch (SipException e) { - e.printStackTrace(); - } catch (InvalidArgumentException e) { - e.printStackTrace(); - } catch (ParseException e) { - e.printStackTrace(); + } catch (SipException | InvalidArgumentException | ParseException e) { + logger.error("[命令发送失败] 国标级联 设备状态应答回复200OK: {}", e.getMessage()); } Element deviceIdElement = element.element("DeviceID"); Element onlineElement = element.element("Online"); diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/RecordInfoResponseMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/RecordInfoResponseMessageHandler.java index e9ee32d9..fa741de4 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/RecordInfoResponseMessageHandler.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/RecordInfoResponseMessageHandler.java @@ -147,7 +147,7 @@ public class RecordInfoResponseMessageHandler extends SIPRequestProcessorParent } } } catch (DocumentException e) { - throw new RuntimeException(e); + logger.error("xml解析异常: ", e); } finally { taskQueueHandlerRun = false; } @@ -155,13 +155,9 @@ public class RecordInfoResponseMessageHandler extends SIPRequestProcessorParent }); } - } catch (SipException e) { - e.printStackTrace(); - } catch (InvalidArgumentException e) { - e.printStackTrace(); - } catch (ParseException e) { - e.printStackTrace(); - }finally { + } catch (SipException | InvalidArgumentException | ParseException e) { + logger.error("[命令发送失败] 国标级联 国标录像: {}", e.getMessage()); + } finally { taskQueueHandlerRun = false; } } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/timeout/impl/TimeoutProcessorImpl.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/timeout/impl/TimeoutProcessorImpl.java index 86861af1..531505d2 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/timeout/impl/TimeoutProcessorImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/timeout/impl/TimeoutProcessorImpl.java @@ -1,8 +1,11 @@ package com.genersoft.iot.vmp.gb28181.transmit.event.timeout.impl; +import com.genersoft.iot.vmp.conf.SystemInfoTimerTask; import com.genersoft.iot.vmp.gb28181.event.SipSubscribe; import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver; import com.genersoft.iot.vmp.gb28181.transmit.event.timeout.ITimeoutProcessor; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -13,6 +16,8 @@ import javax.sip.header.CallIdHeader; @Component public class TimeoutProcessorImpl implements InitializingBean, ITimeoutProcessor { + private Logger logger = LoggerFactory.getLogger(TimeoutProcessorImpl.class); + @Autowired private SIPProcessorObserver processorObserver; @@ -36,7 +41,7 @@ public class TimeoutProcessorImpl implements InitializingBean, ITimeoutProcessor sipSubscribe.removeErrorSubscribe(callId); sipSubscribe.removeOkSubscribe(callId); } catch (Exception e) { - e.printStackTrace(); + logger.error("[超时事件失败]: {}", e.getMessage()); } } } diff --git a/src/main/java/com/genersoft/iot/vmp/service/impl/StreamPushUploadFileHandler.java b/src/main/java/com/genersoft/iot/vmp/service/impl/StreamPushUploadFileHandler.java index 3e13f48e..1b21995b 100644 --- a/src/main/java/com/genersoft/iot/vmp/service/impl/StreamPushUploadFileHandler.java +++ b/src/main/java/com/genersoft/iot/vmp/service/impl/StreamPushUploadFileHandler.java @@ -93,7 +93,6 @@ public class StreamPushUploadFileHandler extends AnalysisEventListener 15) { // "***.***.***.***".length() - // = 15 - if (ipAddress.indexOf(",") > 0) { - ipAddress = ipAddress.substring(0, ipAddress.indexOf(",")); - } - } - } catch (Exception e) { - ipAddress=""; - } - // ipAddress = this.getRequest().getRemoteAddr(); - - return ipAddress; - } -} - - diff --git a/src/main/java/com/genersoft/iot/vmp/utils/JarFileUtils.java b/src/main/java/com/genersoft/iot/vmp/utils/JarFileUtils.java deleted file mode 100644 index 686b562d..00000000 --- a/src/main/java/com/genersoft/iot/vmp/utils/JarFileUtils.java +++ /dev/null @@ -1,73 +0,0 @@ -package com.genersoft.iot.vmp.utils; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.stereotype.Component; -import org.springframework.util.ClassUtils; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.util.HashMap; -import java.util.Map; -import java.util.jar.JarEntry; -import java.util.jar.JarFile; - -/** - * 一个优秀的颓废程序猿 - */ -@Component -public class JarFileUtils { - private static Logger log = LoggerFactory.getLogger(JarFileUtils.class); - private static Map map = new HashMap<>(); - - public Map readJarFile() { - JarFile jarFile = null; - BufferedReader br = null; - try { - // 获取jar的运行路径,因linux下jar的路径为”file:/app/.../test.jar!/BOOT-INF/class!/“这种格式,所以需要去掉”file:“和”!/BOOT-INF/class!/“ - String jarFilePath = ClassUtils.getDefaultClassLoader().getResource("").getPath().replace("!/BOOT-INF/classes!/", ""); - if (jarFilePath.startsWith("file")) { - jarFilePath = jarFilePath.substring(5); - } - log.debug("jarFilePath:" + jarFilePath); - // 通过JarFile的getJarEntry方法读取META-INF/MANIFEST.MF - jarFile = new JarFile(jarFilePath); - JarEntry entry = jarFile.getJarEntry("META-INF/MANIFEST.MF"); - log.info("读取的内容:" + entry.toString()); - // 如果读取到MANIFEST.MF文件内容,则转换为string - if (entry != null) { - InputStream in = jarFile.getInputStream(entry); - - StringBuilder sb = new StringBuilder(); - br = new BufferedReader(new InputStreamReader(in)); - String line = ""; - while ((line = br.readLine()) != null) { - if (line != null && line.contains(":")) { - int index = line.indexOf(":"); - map.put(line.substring(0, index).trim(), line.substring(index + 1, line.length()).trim()); - } - } - return map; - } - } catch (IOException e) { - log.debug("读取MANIFEST.MF文件异常:" + e.getMessage()); - } finally { - try { - if (null != br) { - br.close(); - } - if (null != jarFile) { - jarFile.close(); - } - } catch (IOException e) { - e.printStackTrace(); - } - } - - return map; - - } - -} diff --git a/src/main/java/com/genersoft/iot/vmp/utils/SerializeUtils.java b/src/main/java/com/genersoft/iot/vmp/utils/SerializeUtils.java deleted file mode 100644 index ae91ad59..00000000 --- a/src/main/java/com/genersoft/iot/vmp/utils/SerializeUtils.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.genersoft.iot.vmp.utils; - -import java.io.*; - -public class SerializeUtils { - public static byte[] serialize(Object obj){ - byte[] bytes = null; - try { - ByteArrayOutputStream baos=new ByteArrayOutputStream();; - ObjectOutputStream oos=new ObjectOutputStream(baos); - oos.writeObject(obj); - bytes=baos.toByteArray(); - baos.close(); - oos.close(); - } catch (IOException e) { - e.printStackTrace(); - } - return bytes; - } - public static Object deSerialize(byte[] bytes){ - Object obj=null; - try { - ByteArrayInputStream bais=new ByteArrayInputStream(bytes); - ObjectInputStream ois=new ObjectInputStream(bais); - obj=ois.readObject(); - } catch (Exception e) { - e.printStackTrace(); - } - return obj; - } -} diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/media/MediaController.java b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/media/MediaController.java index b876cf9c..6f7132e7 100644 --- a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/media/MediaController.java +++ b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/media/MediaController.java @@ -96,7 +96,7 @@ public class MediaController { try { Thread.sleep(1000); } catch (InterruptedException e) { - e.printStackTrace(); + logger.error("[线程休眠失败], {}", e.getMessage()); } if (useSourceIpAsStreamIp != null && useSourceIpAsStreamIp) { String host = request.getHeader("Host");