Commit cd117ed22825b8f442e0f2281678f4549be3e109

Authored by 648540858
1 parent a574ff09

dialog去除以及异常情况处理优化

Too many changes to show.

To preserve performance only 18 of 53 files are displayed.

src/main/java/com/genersoft/iot/vmp/conf/MediaConfig.java
... ... @@ -2,6 +2,9 @@ package com.genersoft.iot.vmp.conf;
2 2  
3 3 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
4 4 import com.genersoft.iot.vmp.utils.DateUtil;
  5 +import com.genersoft.iot.vmp.vmanager.gb28181.device.DeviceQuery;
  6 +import org.slf4j.Logger;
  7 +import org.slf4j.LoggerFactory;
5 8 import org.springframework.beans.factory.annotation.Value;
6 9 import org.springframework.context.annotation.Configuration;
7 10 import org.springframework.util.ObjectUtils;
... ... @@ -15,6 +18,8 @@ import java.util.regex.Pattern;
15 18 @Configuration("mediaConfig")
16 19 public class MediaConfig{
17 20  
  21 + private final static Logger logger = LoggerFactory.getLogger(MediaConfig.class);
  22 +
18 23 // 修改必须配置,不再支持自动获取
19 24 @Value("${media.id}")
20 25 private String id;
... ... @@ -174,7 +179,7 @@ public class MediaConfig{
174 179 try {
175 180 hostAddress = InetAddress.getByName(sdpIp).getHostAddress();
176 181 } catch (UnknownHostException e) {
177   - throw new RuntimeException(e);
  182 + logger.error("[获取SDP IP]: 域名解析失败");
178 183 }
179 184 return hostAddress;
180 185 }
... ...
src/main/java/com/genersoft/iot/vmp/conf/exception/SsrcTransactionNotFoundException.java 0 → 100644
  1 +package com.genersoft.iot.vmp.conf.exception;
  2 +
  3 +import com.sun.javafx.binding.StringFormatter;
  4 +
  5 +/**
  6 + * @author lin
  7 + */
  8 +public class SsrcTransactionNotFoundException extends Exception{
  9 + private String deviceId;
  10 + private String channelId;
  11 + private String callId;
  12 + private String stream;
  13 +
  14 +
  15 +
  16 + public SsrcTransactionNotFoundException(String deviceId, String channelId, String callId, String stream) {
  17 + this.deviceId = deviceId;
  18 + this.channelId = channelId;
  19 + this.callId = callId;
  20 + this.stream = stream;
  21 + }
  22 +
  23 + public String getDeviceId() {
  24 + return deviceId;
  25 + }
  26 +
  27 + public String getChannelId() {
  28 + return channelId;
  29 + }
  30 +
  31 + public String getCallId() {
  32 + return callId;
  33 + }
  34 +
  35 + public String getStream() {
  36 + return stream;
  37 + }
  38 +
  39 + @Override
  40 + public String getMessage() {
  41 + StringBuffer msg = new StringBuffer();
  42 + msg.append(StringFormatter.format("缓存事务信息未找到,device:%s channel: %s ", deviceId, channelId));
  43 + if (callId != null) {
  44 + msg.append("callId: " + callId);
  45 + }
  46 + if (stream != null) {
  47 + msg.append("stream: " + stream);
  48 + }
  49 + return msg.toString();
  50 + }
  51 +}
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/SipLayer.java
... ... @@ -41,7 +41,7 @@ public class SipLayer{
41 41  
42 42 @Bean("sipStack")
43 43 @DependsOn({"sipFactory"})
44   - SipStack createSipStack() throws PeerUnavailableException {
  44 + SipStackImpl createSipStack() throws PeerUnavailableException {
45 45 sipStack = ( SipStackImpl )sipFactory.createSipStack(DefaultProperties.getProperties(sipConfig.getMonitorIp(), false));
46 46 return sipStack;
47 47 }
... ... @@ -56,7 +56,6 @@ public class SipLayer{
56 56 tcpSipProvider = (SipProviderImpl)sipStack.createSipProvider(tcpListeningPoint);
57 57 tcpSipProvider.setDialogErrorsAutomaticallyHandled();
58 58 tcpSipProvider.addSipListener(sipProcessorObserver);
59   -// tcpSipProvider.setAutomaticDialogSupportEnabled(false);
60 59 logger.info("[Sip Server] TCP 启动成功 {}:{}", sipConfig.getMonitorIp(), sipConfig.getPort());
61 60 } catch (TransportNotSupportedException e) {
62 61 e.printStackTrace();
... ... @@ -80,7 +79,6 @@ public class SipLayer{
80 79 udpListeningPoint = sipStack.createListeningPoint(sipConfig.getMonitorIp(), sipConfig.getPort(), "UDP");
81 80 udpSipProvider = (SipProviderImpl)sipStack.createSipProvider(udpListeningPoint);
82 81 udpSipProvider.addSipListener(sipProcessorObserver);
83   -// udpSipProvider.setAutomaticDialogSupportEnabled(false);
84 82 } catch (TransportNotSupportedException e) {
85 83 e.printStackTrace();
86 84 } catch (InvalidArgumentException e) {
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/bean/CmdSendFailEvent.java 0 → 100644
  1 +package com.genersoft.iot.vmp.gb28181.bean;
  2 +
  3 +import javax.sip.Dialog;
  4 +import java.util.EventObject;
  5 +
  6 +public class CmdSendFailEvent extends EventObject {
  7 +
  8 + private String callId;
  9 +
  10 + /**
  11 + * Constructs a prototypical Event.
  12 + *
  13 + * @param dialog
  14 + * @throws IllegalArgumentException if source is null.
  15 + */
  16 + public CmdSendFailEvent(Dialog dialog) {
  17 + super(dialog);
  18 + }
  19 +
  20 + public String getCallId() {
  21 + return callId;
  22 + }
  23 +
  24 + public void setCallId(String callId) {
  25 + this.callId = callId;
  26 + }
  27 +}
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/bean/DeviceNotFoundEvent.java
... ... @@ -4,6 +4,9 @@ import javax.sip.Dialog;
4 4 import java.util.EventObject;
5 5  
6 6 public class DeviceNotFoundEvent extends EventObject {
  7 +
  8 + private String callId;
  9 +
7 10 /**
8 11 * Constructs a prototypical Event.
9 12 *
... ... @@ -14,8 +17,11 @@ public class DeviceNotFoundEvent extends EventObject {
14 17 super(dialog);
15 18 }
16 19  
  20 + public String getCallId() {
  21 + return callId;
  22 + }
17 23  
18   - public Dialog getDialog() {
19   - return (Dialog)super.getSource();
  24 + public void setCallId(String callId) {
  25 + this.callId = callId;
20 26 }
21 27 }
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/bean/SipTransactionInfo.java
1 1 package com.genersoft.iot.vmp.gb28181.bean;
2 2  
3 3 import gov.nist.javax.sip.message.SIPRequest;
  4 +import gov.nist.javax.sip.message.SIPResponse;
4 5  
5 6 public class SipTransactionInfo {
6 7  
... ... @@ -9,11 +10,11 @@ public class SipTransactionInfo {
9 10 private String toTag;
10 11 private String viaBranch;
11 12  
12   - public SipTransactionInfo(SIPRequest request) {
13   - this.callId = request.getCallIdHeader().getCallId();
14   - this.fromTag = request.getFromTag();
15   - this.toTag = request.getToTag();
16   - this.viaBranch = request.getTopmostViaHeader().getBranch();
  13 + public SipTransactionInfo(SIPResponse response) {
  14 + this.callId = response.getCallIdHeader().getCallId();
  15 + this.fromTag = response.getFromTag();
  16 + this.toTag = response.getToTag();
  17 + this.viaBranch = response.getTopmostViaHeader().getBranch();
17 18 }
18 19  
19 20 public SipTransactionInfo() {
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/bean/SsrcTransaction.java
... ... @@ -8,10 +8,11 @@ public class SsrcTransaction {
8 8 private String channelId;
9 9 private String callId;
10 10 private String stream;
11   - private byte[] transaction;
12   - private byte[] dialog;
13 11 private String mediaServerId;
14 12 private String ssrc;
  13 +
  14 + private SipTransactionInfo sipTransactionInfo;
  15 +
15 16 private VideoStreamSessionManager.SessionType type;
16 17  
17 18 public String getDeviceId() {
... ... @@ -46,22 +47,6 @@ public class SsrcTransaction {
46 47 this.stream = stream;
47 48 }
48 49  
49   - public byte[] getTransaction() {
50   - return transaction;
51   - }
52   -
53   - public void setTransaction(byte[] transaction) {
54   - this.transaction = transaction;
55   - }
56   -
57   - public byte[] getDialog() {
58   - return dialog;
59   - }
60   -
61   - public void setDialog(byte[] dialog) {
62   - this.dialog = dialog;
63   - }
64   -
65 50 public String getMediaServerId() {
66 51 return mediaServerId;
67 52 }
... ... @@ -85,4 +70,12 @@ public class SsrcTransaction {
85 70 public void setType(VideoStreamSessionManager.SessionType type) {
86 71 this.type = type;
87 72 }
  73 +
  74 + public SipTransactionInfo getSipTransactionInfo() {
  75 + return sipTransactionInfo;
  76 + }
  77 +
  78 + public void setSipTransactionInfo(SipTransactionInfo sipTransactionInfo) {
  79 + this.sipTransactionInfo = sipTransactionInfo;
  80 + }
88 81 }
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/bean/SubscribeInfo.java
1 1 package com.genersoft.iot.vmp.gb28181.bean;
2 2  
3   -import com.genersoft.iot.vmp.utils.SerializeUtils;
4 3 import gov.nist.javax.sip.message.SIPRequest;
5 4 import gov.nist.javax.sip.message.SIPResponse;
6 5  
7   -import javax.sip.ClientTransaction;
8   -import javax.sip.Dialog;
9   -import javax.sip.RequestEvent;
10 6 import javax.sip.ServerTransaction;
11 7 import javax.sip.header.*;
12   -import javax.sip.message.Request;
13 8  
14 9 public class SubscribeInfo {
15 10  
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/event/SipSubscribe.java
... ... @@ -10,6 +10,7 @@ import org.springframework.stereotype.Component;
10 10 import javax.sip.*;
11 11 import javax.sip.header.CallIdHeader;
12 12 import javax.sip.message.Response;
  13 +import java.text.ParseException;
13 14 import java.time.Instant;
14 15 import java.util.Map;
15 16 import java.util.concurrent.ConcurrentHashMap;
... ... @@ -56,8 +57,7 @@ public class SipSubscribe {
56 57 logger.debug("errorSubscribes.size:{}",errorSubscribes.size());
57 58 }
58 59  
59   - public interface Event {
60   - void response(EventResult eventResult);
  60 + public interface Event { void response(EventResult eventResult) ;
61 61 }
62 62  
63 63 /**
... ... @@ -81,18 +81,13 @@ public class SipSubscribe {
81 81 public EventResultType type;
82 82 public String msg;
83 83 public String callId;
84   - public Dialog dialog;
85 84 public EventObject event;
86 85  
87   - public EventResult() {
88   - }
89   -
90 86 public EventResult(EventObject event) {
91 87 this.event = event;
92 88 if (event instanceof ResponseEvent) {
93 89 ResponseEvent responseEvent = (ResponseEvent)event;
94 90 Response response = responseEvent.getResponse();
95   - this.dialog = responseEvent.getDialog();
96 91 this.type = EventResultType.response;
97 92 if (response != null) {
98 93 this.msg = response.getReasonPhrase();
... ... @@ -127,12 +122,10 @@ public class SipSubscribe {
127 122 this.statusCode = -1024;
128 123 this.callId = dialogTerminatedEvent.getDialog().getCallId().getCallId();
129 124 }else if (event instanceof DeviceNotFoundEvent) {
130   - DeviceNotFoundEvent deviceNotFoundEvent = (DeviceNotFoundEvent)event;
131 125 this.type = EventResultType.deviceNotFoundEvent;
132 126 this.msg = "设备未找到";
133 127 this.statusCode = -1024;
134   - this.dialog = deviceNotFoundEvent.getDialog();
135   - this.callId = this.dialog != null ?deviceNotFoundEvent.getDialog().getCallId().getCallId() : null;
  128 + this.callId = ((DeviceNotFoundEvent) event).getCallId();
136 129 }
137 130 }
138 131 }
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/event/device/RequestTimeoutEventImpl.java
... ... @@ -36,6 +36,7 @@ public class RequestTimeoutEventImpl implements ApplicationListener<RequestTimeo
36 36 }
37 37 deviceService.offline(device.getDeviceId());
38 38 }
  39 +
39 40 }
40 41 }
41 42 }
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/event/subscribe/catalog/CatalogEventLister.java
... ... @@ -18,6 +18,9 @@ import org.springframework.stereotype.Component;
18 18 import org.springframework.util.ObjectUtils;
19 19 import org.springframework.util.StringUtils;
20 20  
  21 +import javax.sip.InvalidArgumentException;
  22 +import javax.sip.SipException;
  23 +import java.text.ParseException;
21 24 import java.util.*;
22 25  
23 26 /**
... ... @@ -96,7 +99,12 @@ public class CatalogEventLister implements ApplicationListener<CatalogEvent> {
96 99 }
97 100 if (deviceChannelList.size() > 0) {
98 101 logger.info("[Catalog事件: {}]平台:{},影响通道{}个", event.getType(), event.getPlatformId(), deviceChannelList.size());
99   - sipCommanderFroPlatform.sendNotifyForCatalogOther(event.getType(), parentPlatform, deviceChannelList, subscribe, null);
  102 + try {
  103 + sipCommanderFroPlatform.sendNotifyForCatalogOther(event.getType(), parentPlatform, deviceChannelList, subscribe, null);
  104 + } catch (InvalidArgumentException | ParseException | NoSuchFieldException | SipException |
  105 + IllegalAccessException e) {
  106 + logger.error("[命令发送失败] 国标级联 Catalog通知: {}", e.getMessage());
  107 + }
100 108 }
101 109 }else if (parentPlatformMap.keySet().size() > 0) {
102 110 for (String gbId : parentPlatformMap.keySet()) {
... ... @@ -112,7 +120,12 @@ public class CatalogEventLister implements ApplicationListener<CatalogEvent> {
112 120 DeviceChannel deviceChannel = new DeviceChannel();
113 121 deviceChannel.setChannelId(gbId);
114 122 deviceChannelList.add(deviceChannel);
115   - sipCommanderFroPlatform.sendNotifyForCatalogOther(event.getType(), platform, deviceChannelList, subscribeInfo, null);
  123 + try {
  124 + sipCommanderFroPlatform.sendNotifyForCatalogOther(event.getType(), platform, deviceChannelList, subscribeInfo, null);
  125 + } catch (InvalidArgumentException | ParseException | NoSuchFieldException | SipException |
  126 + IllegalAccessException e) {
  127 + logger.error("[命令发送失败] 国标级联 Catalog通知: {}", e.getMessage());
  128 + }
116 129 }
117 130 }
118 131 }
... ... @@ -137,7 +150,12 @@ public class CatalogEventLister implements ApplicationListener<CatalogEvent> {
137 150 }
138 151 if (deviceChannelList.size() > 0) {
139 152 logger.info("[Catalog事件: {}]平台:{},影响通道{}个", event.getType(), event.getPlatformId(), deviceChannelList.size());
140   - sipCommanderFroPlatform.sendNotifyForCatalogAddOrUpdate(event.getType(), parentPlatform, deviceChannelList, subscribe, null);
  153 + try {
  154 + sipCommanderFroPlatform.sendNotifyForCatalogAddOrUpdate(event.getType(), parentPlatform, deviceChannelList, subscribe, null);
  155 + } catch (InvalidArgumentException | ParseException | NoSuchFieldException | SipException |
  156 + IllegalAccessException e) {
  157 + logger.error("[命令发送失败] 国标级联 Catalog通知: {}", e.getMessage());
  158 + }
141 159 }
142 160 }else if (parentPlatformMap.keySet().size() > 0) {
143 161 for (String gbId : parentPlatformMap.keySet()) {
... ... @@ -157,7 +175,12 @@ public class CatalogEventLister implements ApplicationListener<CatalogEvent> {
157 175 DeviceChannel deviceChannelByStream = gbStreamService.getDeviceChannelListByStreamWithStatus(gbStream, gbStream.getCatalogId(), platform);
158 176 deviceChannelList.add(deviceChannelByStream);
159 177 }
160   - sipCommanderFroPlatform.sendNotifyForCatalogAddOrUpdate(event.getType(), platform, deviceChannelList, subscribeInfo, null);
  178 + try {
  179 + sipCommanderFroPlatform.sendNotifyForCatalogAddOrUpdate(event.getType(), platform, deviceChannelList, subscribeInfo, null);
  180 + } catch (InvalidArgumentException | ParseException | NoSuchFieldException |
  181 + SipException | IllegalAccessException e) {
  182 + logger.error("[命令发送失败] 国标级联 Catalog通知: {}", e.getMessage());
  183 + }
161 184 }
162 185 }
163 186 }
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/session/VideoStreamSessionManager.java
... ... @@ -8,9 +8,13 @@ import javax.sip.Dialog;
8 8  
9 9 import com.genersoft.iot.vmp.common.VideoManagerConstants;
10 10 import com.genersoft.iot.vmp.conf.UserSetting;
  11 +import com.genersoft.iot.vmp.gb28181.bean.SipMsgInfo;
  12 +import com.genersoft.iot.vmp.gb28181.bean.SipTransactionInfo;
11 13 import com.genersoft.iot.vmp.gb28181.bean.SsrcTransaction;
12 14 import com.genersoft.iot.vmp.utils.SerializeUtils;
13 15 import com.genersoft.iot.vmp.utils.redis.RedisUtil;
  16 +import gov.nist.javax.sip.message.SIPRequest;
  17 +import gov.nist.javax.sip.message.SIPResponse;
14 18 import gov.nist.javax.sip.stack.SIPDialog;
15 19 import org.springframework.beans.factory.annotation.Autowired;
16 20 import org.springframework.stereotype.Component;
... ... @@ -42,15 +46,14 @@ public class VideoStreamSessionManager {
42 46 * @param callId 一次请求的CallID
43 47 * @param stream 流名称
44 48 * @param mediaServerId 所使用的流媒体ID
45   - * @param transaction 事务
  49 + * @param response 回复
46 50 */
47   - public void put(String deviceId, String channelId, String callId, String stream, String ssrc, String mediaServerId, ClientTransaction transaction, SessionType type){
  51 + public void put(String deviceId, String channelId, String callId, String stream, String ssrc, String mediaServerId, SIPResponse response, SessionType type){
48 52 SsrcTransaction ssrcTransaction = new SsrcTransaction();
49 53 ssrcTransaction.setDeviceId(deviceId);
50 54 ssrcTransaction.setChannelId(channelId);
51 55 ssrcTransaction.setStream(stream);
52   - byte[] transactionByteArray = SerializeUtils.serialize(transaction);
53   - ssrcTransaction.setTransaction(transactionByteArray);
  56 + ssrcTransaction.setSipTransactionInfo(new SipTransactionInfo(response));
54 57 ssrcTransaction.setCallId(callId);
55 58 ssrcTransaction.setSsrc(ssrc);
56 59 ssrcTransaction.setMediaServerId(mediaServerId);
... ... @@ -62,53 +65,6 @@ public class VideoStreamSessionManager {
62 65 + "_" + deviceId + "_" + channelId + "_" + callId + "_" + stream, ssrcTransaction);
63 66 }
64 67  
65   - public void put(String deviceId, String channelId, String callId, Dialog dialog){
66   - SsrcTransaction ssrcTransaction = getSsrcTransaction(deviceId, channelId, callId, null);
67   - if (ssrcTransaction != null) {
68   - byte[] dialogByteArray = SerializeUtils.serialize(dialog);
69   - ssrcTransaction.setDialog(dialogByteArray);
70   - }
71   - RedisUtil.set(VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX + userSetting.getServerId()
72   - + "_" + deviceId + "_" + channelId + "_" + ssrcTransaction.getCallId() + "_"
73   - + ssrcTransaction.getStream(), ssrcTransaction);
74   - }
75   -
76   -
77   - public ClientTransaction getTransaction(String deviceId, String channelId, String stream, String callId){
78   - SsrcTransaction ssrcTransaction = getSsrcTransaction(deviceId, channelId, callId, stream);
79   - if (ssrcTransaction == null) {
80   - return null;
81   - }
82   - byte[] transactionByteArray = ssrcTransaction.getTransaction();
83   - ClientTransaction clientTransaction = (ClientTransaction)SerializeUtils.deSerialize(transactionByteArray);
84   - return clientTransaction;
85   - }
86   -
87   - public SIPDialog getDialogByStream(String deviceId, String channelId, String stream){
88   - SsrcTransaction ssrcTransaction = getSsrcTransaction(deviceId, channelId, null, stream);
89   - if (ssrcTransaction == null) {
90   - return null;
91   - }
92   - byte[] dialogByteArray = ssrcTransaction.getDialog();
93   - if (dialogByteArray == null) {
94   - return null;
95   - }
96   - SIPDialog dialog = (SIPDialog)SerializeUtils.deSerialize(dialogByteArray);
97   - return dialog;
98   - }
99   -
100   - public SIPDialog getDialogByCallId(String deviceId, String channelId, String callId){
101   - SsrcTransaction ssrcTransaction = getSsrcTransaction(deviceId, channelId, callId, null);
102   - if (ssrcTransaction == null) {
103   - return null;
104   - }
105   - byte[] dialogByteArray = ssrcTransaction.getDialog();
106   - if (dialogByteArray == null) {
107   - return null;
108   - }
109   - return (SIPDialog)SerializeUtils.deSerialize(dialogByteArray);
110   - }
111   -
112 68 public SsrcTransaction getSsrcTransaction(String deviceId, String channelId, String callId, String stream){
113 69  
114 70 if (ObjectUtils.isEmpty(deviceId)) {
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/task/impl/CatalogSubscribeTask.java
... ... @@ -10,9 +10,7 @@ import org.slf4j.LoggerFactory;
10 10 import org.springframework.scheduling.annotation.Async;
11 11 import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
12 12  
13   -import javax.sip.Dialog;
14   -import javax.sip.DialogState;
15   -import javax.sip.ResponseEvent;
  13 +import javax.sip.*;
16 14 import javax.sip.header.ToHeader;
17 15 import java.text.ParseException;
18 16 import java.util.Timer;
... ... @@ -44,23 +42,29 @@ public class CatalogSubscribeTask implements ISubscribeTask {
44 42 if (dynamicTask.get(taskKey) != null) {
45 43 dynamicTask.stop(taskKey);
46 44 }
47   - SIPRequest sipRequest = sipCommander.catalogSubscribe(device, request, eventResult -> {
48   - ResponseEvent event = (ResponseEvent) eventResult.event;
49   - // 成功
50   - logger.info("[目录订阅]成功: {}", device.getDeviceId());
51   - ToHeader toHeader = (ToHeader)event.getResponse().getHeader(ToHeader.NAME);
52   - try {
53   - this.request.getToHeader().setTag(toHeader.getTag());
54   - } catch (ParseException e) {
55   - logger.info("[目录订阅]成功: 但为request设置ToTag失败");
  45 + SIPRequest sipRequest = null;
  46 + try {
  47 + sipRequest = sipCommander.catalogSubscribe(device, request, eventResult -> {
  48 + ResponseEvent event = (ResponseEvent) eventResult.event;
  49 + // 成功
  50 + logger.info("[目录订阅]成功: {}", device.getDeviceId());
  51 + ToHeader toHeader = (ToHeader)event.getResponse().getHeader(ToHeader.NAME);
  52 + try {
  53 + this.request.getToHeader().setTag(toHeader.getTag());
  54 + } catch (ParseException e) {
  55 + logger.info("[目录订阅]成功: 但为request设置ToTag失败");
  56 + this.request = null;
  57 + }
  58 + },eventResult -> {
56 59 this.request = null;
57   - }
58   - },eventResult -> {
59   - this.request = null;
60   - // 失败
61   - logger.warn("[目录订阅]失败,信令发送失败: {}-{} ", device.getDeviceId(), eventResult.msg);
62   - dynamicTask.startDelay(taskKey, CatalogSubscribeTask.this, 2000);
63   - });
  60 + // 失败
  61 + logger.warn("[目录订阅]失败,信令发送失败: {}-{} ", device.getDeviceId(), eventResult.msg);
  62 + dynamicTask.startDelay(taskKey, CatalogSubscribeTask.this, 2000);
  63 + });
  64 + } catch (InvalidArgumentException | SipException | ParseException e) {
  65 + logger.error("[命令发送失败] 目录订阅: {}", e.getMessage());
  66 +
  67 + }
64 68 if (sipRequest != null) {
65 69 this.request = sipRequest;
66 70 }
... ... @@ -80,18 +84,22 @@ public class CatalogSubscribeTask implements ISubscribeTask {
80 84 dynamicTask.stop(taskKey);
81 85 }
82 86 device.setSubscribeCycleForCatalog(0);
83   - sipCommander.catalogSubscribe(device, request, eventResult -> {
84   - ResponseEvent event = (ResponseEvent) eventResult.event;
85   - if (event.getResponse().getRawContent() != null) {
86   - // 成功
87   - logger.info("[取消目录订阅订阅]成功: {}", device.getDeviceId());
88   - }else {
89   - // 成功
90   - logger.info("[取消目录订阅订阅]成功: {}", device.getDeviceId());
91   - }
92   - },eventResult -> {
93   - // 失败
94   - logger.warn("[取消目录订阅订阅]失败,信令发送失败: {}-{} ", device.getDeviceId(), eventResult.msg);
95   - });
  87 + try {
  88 + sipCommander.catalogSubscribe(device, request, eventResult -> {
  89 + ResponseEvent event = (ResponseEvent) eventResult.event;
  90 + if (event.getResponse().getRawContent() != null) {
  91 + // 成功
  92 + logger.info("[取消目录订阅订阅]成功: {}", device.getDeviceId());
  93 + }else {
  94 + // 成功
  95 + logger.info("[取消目录订阅订阅]成功: {}", device.getDeviceId());
  96 + }
  97 + },eventResult -> {
  98 + // 失败
  99 + logger.warn("[取消目录订阅订阅]失败,信令发送失败: {}-{} ", device.getDeviceId(), eventResult.msg);
  100 + });
  101 + } catch (InvalidArgumentException | SipException | ParseException e) {
  102 + logger.error("[命令发送失败] 取消目录订阅订阅: {}", e.getMessage());
  103 + }
96 104 }
97 105 }
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/task/impl/MobilePositionSubscribeTask.java
... ... @@ -11,9 +11,7 @@ import org.slf4j.Logger;
11 11 import org.slf4j.LoggerFactory;
12 12 import org.springframework.scheduling.annotation.Async;
13 13  
14   -import javax.sip.Dialog;
15   -import javax.sip.DialogState;
16   -import javax.sip.ResponseEvent;
  14 +import javax.sip.*;
17 15 import javax.sip.header.ToHeader;
18 16 import java.text.ParseException;
19 17 import java.util.Timer;
... ... @@ -43,23 +41,28 @@ public class MobilePositionSubscribeTask implements ISubscribeTask {
43 41 if (dynamicTask.get(taskKey) != null) {
44 42 dynamicTask.stop(taskKey);
45 43 }
46   - SIPRequest sipRequest = sipCommander.mobilePositionSubscribe(device, request, eventResult -> {
47   - // 成功
48   - logger.info("[移动位置订阅]成功: {}", device.getDeviceId());
49   - ResponseEvent event = (ResponseEvent) eventResult.event;
50   - ToHeader toHeader = (ToHeader)event.getResponse().getHeader(ToHeader.NAME);
51   - try {
52   - this.request.getToHeader().setTag(toHeader.getTag());
53   - } catch (ParseException e) {
54   - logger.info("[移动位置订阅]成功: 为request设置ToTag失败");
  44 + SIPRequest sipRequest = null;
  45 + try {
  46 + sipRequest = sipCommander.mobilePositionSubscribe(device, request, eventResult -> {
  47 + // 成功
  48 + logger.info("[移动位置订阅]成功: {}", device.getDeviceId());
  49 + ResponseEvent event = (ResponseEvent) eventResult.event;
  50 + ToHeader toHeader = (ToHeader)event.getResponse().getHeader(ToHeader.NAME);
  51 + try {
  52 + this.request.getToHeader().setTag(toHeader.getTag());
  53 + } catch (ParseException e) {
  54 + logger.info("[移动位置订阅]成功: 为request设置ToTag失败");
  55 + this.request = null;
  56 + }
  57 + },eventResult -> {
55 58 this.request = null;
56   - }
57   - },eventResult -> {
58   - this.request = null;
59   - // 失败
60   - logger.warn("[移动位置订阅]失败,信令发送失败: {}-{} ", device.getDeviceId(), eventResult.msg);
61   - dynamicTask.startDelay(taskKey, MobilePositionSubscribeTask.this, 2000);
62   - });
  59 + // 失败
  60 + logger.warn("[移动位置订阅]失败,信令发送失败: {}-{} ", device.getDeviceId(), eventResult.msg);
  61 + dynamicTask.startDelay(taskKey, MobilePositionSubscribeTask.this, 2000);
  62 + });
  63 + } catch (InvalidArgumentException | SipException | ParseException e) {
  64 + logger.error("[命令发送失败] 移动位置订阅: {}", e.getMessage());
  65 + }
63 66 if (sipRequest != null) {
64 67 this.request = sipRequest;
65 68 }
... ... @@ -79,18 +82,22 @@ public class MobilePositionSubscribeTask implements ISubscribeTask {
79 82 dynamicTask.stop(taskKey);
80 83 }
81 84 device.setSubscribeCycleForMobilePosition(0);
82   - sipCommander.mobilePositionSubscribe(device, request, eventResult -> {
83   - ResponseEvent event = (ResponseEvent) eventResult.event;
84   - if (event.getResponse().getRawContent() != null) {
85   - // 成功
86   - logger.info("[取消移动位置订阅]成功: {}", device.getDeviceId());
87   - }else {
88   - // 成功
89   - logger.info("[取消移动位置订阅]成功: {}", device.getDeviceId());
90   - }
91   - },eventResult -> {
92   - // 失败
93   - logger.warn("[取消移动位置订阅]失败,信令发送失败: {}-{} ", device.getDeviceId(), eventResult.msg);
94   - });
  85 + try {
  86 + sipCommander.mobilePositionSubscribe(device, request, eventResult -> {
  87 + ResponseEvent event = (ResponseEvent) eventResult.event;
  88 + if (event.getResponse().getRawContent() != null) {
  89 + // 成功
  90 + logger.info("[取消移动位置订阅]成功: {}", device.getDeviceId());
  91 + }else {
  92 + // 成功
  93 + logger.info("[取消移动位置订阅]成功: {}", device.getDeviceId());
  94 + }
  95 + },eventResult -> {
  96 + // 失败
  97 + logger.warn("[取消移动位置订阅]失败,信令发送失败: {}-{} ", device.getDeviceId(), eventResult.msg);
  98 + });
  99 + } catch (InvalidArgumentException | SipException | ParseException e) {
  100 + logger.error("[命令发送失败] 取消移动位置订阅: {}", e.getMessage());
  101 + }
95 102 }
96 103 }
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java
1 1 package com.genersoft.iot.vmp.gb28181.transmit.cmd;
2 2  
3 3 import com.genersoft.iot.vmp.common.StreamInfo;
  4 +import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException;
4 5 import com.genersoft.iot.vmp.gb28181.bean.*;
5 6 import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
6 7 import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe;
... ... @@ -9,6 +10,11 @@ import com.genersoft.iot.vmp.service.bean.SSRCInfo;
9 10 import gov.nist.javax.sip.message.SIPRequest;
10 11  
11 12 import javax.sip.Dialog;
  13 +import javax.sip.InvalidArgumentException;
  14 +import javax.sip.PeerUnavailableException;
  15 +import javax.sip.SipException;
  16 +import javax.sip.message.Request;
  17 +import java.text.ParseException;
12 18  
13 19 /**
14 20 * @description:设备能力接口,用于定义设备的控制、查询能力
... ... @@ -25,7 +31,7 @@ public interface ISIPCommander {
25 31 * @param leftRight 镜头左移右移 0:停止 1:左移 2:右移
26 32 * @param upDown 镜头上移下移 0:停止 1:上移 2:下移
27 33 */
28   - boolean ptzdirectCmd(Device device,String channelId,int leftRight, int upDown);
  34 + void ptzdirectCmd(Device device,String channelId,int leftRight, int upDown) throws InvalidArgumentException, ParseException, SipException;
29 35  
30 36 /**
31 37 * 云台方向放控制
... ... @@ -36,7 +42,7 @@ public interface ISIPCommander {
36 42 * @param upDown 镜头上移下移 0:停止 1:上移 2:下移
37 43 * @param moveSpeed 镜头移动速度
38 44 */
39   - boolean ptzdirectCmd(Device device,String channelId,int leftRight, int upDown, int moveSpeed);
  45 + void ptzdirectCmd(Device device,String channelId,int leftRight, int upDown, int moveSpeed) throws InvalidArgumentException, ParseException, SipException;
40 46  
41 47 /**
42 48 * 云台缩放控制,使用配置文件中的默认镜头缩放速度
... ... @@ -45,7 +51,7 @@ public interface ISIPCommander {
45 51 * @param channelId 预览通道
46 52 * @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大
47 53 */
48   - boolean ptzZoomCmd(Device device,String channelId,int inOut);
  54 + void ptzZoomCmd(Device device,String channelId,int inOut) throws InvalidArgumentException, ParseException, SipException;
49 55  
50 56 /**
51 57 * 云台缩放控制
... ... @@ -54,7 +60,7 @@ public interface ISIPCommander {
54 60 * @param channelId 预览通道
55 61 * @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大
56 62 */
57   - boolean ptzZoomCmd(Device device,String channelId,int inOut, int moveSpeed);
  63 + void ptzZoomCmd(Device device,String channelId,int inOut, int moveSpeed) throws InvalidArgumentException, ParseException, SipException;
58 64  
59 65 /**
60 66 * 云台控制,支持方向与缩放控制
... ... @@ -67,7 +73,7 @@ public interface ISIPCommander {
67 73 * @param moveSpeed 镜头移动速度
68 74 * @param zoomSpeed 镜头缩放速度
69 75 */
70   - boolean ptzCmd(Device device,String channelId,int leftRight, int upDown, int inOut, int moveSpeed, int zoomSpeed);
  76 + void ptzCmd(Device device,String channelId,int leftRight, int upDown, int inOut, int moveSpeed, int zoomSpeed) throws InvalidArgumentException, SipException, ParseException;
71 77  
72 78 /**
73 79 * 前端控制,包括PTZ指令、FI指令、预置位指令、巡航指令、扫描指令和辅助开关指令
... ... @@ -79,7 +85,7 @@ public interface ISIPCommander {
79 85 * @param parameter2 数据2
80 86 * @param combineCode2 组合码2
81 87 */
82   - boolean frontEndCmd(Device device, String channelId, int cmdCode, int parameter1, int parameter2, int combineCode2);
  88 + void frontEndCmd(Device device, String channelId, int cmdCode, int parameter1, int parameter2, int combineCode2) throws SipException, InvalidArgumentException, ParseException;
83 89  
84 90 /**
85 91 * 前端控制指令(用于转发上级指令)
... ... @@ -87,14 +93,14 @@ public interface ISIPCommander {
87 93 * @param channelId 预览通道
88 94 * @param cmdString 前端控制指令串
89 95 */
90   - boolean fronEndCmd(Device device, String channelId, String cmdString, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent);
  96 + void fronEndCmd(Device device, String channelId, String cmdString, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException;
91 97  
92 98 /**
93 99 * 请求预览视频流
94 100 * @param device 视频设备
95 101 * @param channelId 预览通道
96 102 */
97   - void playStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, ZlmHttpHookSubscribe.Event event, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent);
  103 + void playStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, ZlmHttpHookSubscribe.Event event, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException;
98 104  
99 105 /**
100 106 * 请求回放视频流
... ... @@ -104,7 +110,7 @@ public interface ISIPCommander {
104 110 * @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss
105 111 * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss
106 112 */
107   - void playbackStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInf, Device device, String channelId, String startTime, String endTime,InviteStreamCallback inviteStreamCallback, InviteStreamCallback event, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent);
  113 + 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;
108 114  
109 115 /**
110 116 * 请求历史媒体下载
... ... @@ -117,33 +123,33 @@ public interface ISIPCommander {
117 123 */
118 124 void downloadStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId,
119 125 String startTime, String endTime, int downloadSpeed, InviteStreamCallback inviteStreamCallback, InviteStreamCallback hookEvent,
120   - SipSubscribe.Event errorEvent);
  126 + SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException;
121 127  
122 128 /**
123 129 * 视频流停止
124 130 */
125   - void streamByeCmd(String deviceId, String channelId, String stream, String callId, SipSubscribe.Event okEvent);
126   - void streamByeCmd(String deviceId, String channelId, String stream, String callId);
  131 + void streamByeCmd(Device device, String channelId, String stream, String callId, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException, SsrcTransactionNotFoundException;
  132 + void streamByeCmd(Device device, String channelId, String stream, String callId) throws InvalidArgumentException, ParseException, SipException, SsrcTransactionNotFoundException;
127 133  
128 134 /**
129 135 * 回放暂停
130 136 */
131   - void playPauseCmd(Device device, StreamInfo streamInfo);
  137 + void playPauseCmd(Device device, StreamInfo streamInfo) throws InvalidArgumentException, ParseException, SipException;
132 138  
133 139 /**
134 140 * 回放恢复
135 141 */
136   - void playResumeCmd(Device device, StreamInfo streamInfo);
  142 + void playResumeCmd(Device device, StreamInfo streamInfo) throws InvalidArgumentException, ParseException, SipException;
137 143  
138 144 /**
139 145 * 回放拖动播放
140 146 */
141   - void playSeekCmd(Device device, StreamInfo streamInfo, long seekTime);
  147 + void playSeekCmd(Device device, StreamInfo streamInfo, long seekTime) throws InvalidArgumentException, ParseException, SipException;
142 148  
143 149 /**
144 150 * 回放倍速播放
145 151 */
146   - void playSpeedCmd(Device device, StreamInfo streamInfo, Double speed);
  152 + void playSpeedCmd(Device device, StreamInfo streamInfo, Double speed) throws InvalidArgumentException, ParseException, SipException;
147 153  
148 154 /**
149 155 * 回放控制
... ... @@ -151,23 +157,24 @@ public interface ISIPCommander {
151 157 * @param streamInfo
152 158 * @param content
153 159 */
154   - void playbackControlCmd(Device device, StreamInfo streamInfo, String content,SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent);
  160 + void playbackControlCmd(Device device, StreamInfo streamInfo, String content,SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws SipException, InvalidArgumentException, ParseException;
155 161  
156   - /**
  162 +
  163 + /**
157 164 * 语音广播
158 165 *
159 166 * @param device 视频设备
160 167 * @param channelId 预览通道
161 168 */
162   - boolean audioBroadcastCmd(Device device,String channelId);
  169 + void audioBroadcastCmd(Device device,String channelId);
163 170  
164 171 /**
165 172 * 语音广播
166 173 *
167 174 * @param device 视频设备
168 175 */
169   - void audioBroadcastCmd(Device device, SipSubscribe.Event okEvent);
170   - boolean audioBroadcastCmd(Device device);
  176 + void audioBroadcastCmd(Device device, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException;
  177 + void audioBroadcastCmd(Device device) throws InvalidArgumentException, SipException, ParseException;
171 178  
172 179 /**
173 180 * 音视频录像控制
... ... @@ -176,21 +183,21 @@ public interface ISIPCommander {
176 183 * @param channelId 预览通道
177 184 * @param recordCmdStr 录像命令:Record / StopRecord
178 185 */
179   - boolean recordCmd(Device device, String channelId, String recordCmdStr, SipSubscribe.Event errorEvent);
  186 + void recordCmd(Device device, String channelId, String recordCmdStr, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException;
180 187  
181 188 /**
182 189 * 远程启动控制命令
183 190 *
184 191 * @param device 视频设备
185 192 */
186   - boolean teleBootCmd(Device device);
  193 + void teleBootCmd(Device device) throws InvalidArgumentException, SipException, ParseException;
187 194  
188 195 /**
189 196 * 报警布防/撤防命令
190 197 *
191 198 * @param device 视频设备
192 199 */
193   - boolean guardCmd(Device device, String guardCmdStr, SipSubscribe.Event errorEvent);
  200 + void guardCmd(Device device, String guardCmdStr, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException;
194 201  
195 202 /**
196 203 * 报警复位命令
... ... @@ -199,7 +206,7 @@ public interface ISIPCommander {
199 206 * @param alarmMethod 报警方式(可选)
200 207 * @param alarmType 报警类型(可选)
201 208 */
202   - boolean alarmCmd(Device device, String alarmMethod, String alarmType, SipSubscribe.Event errorEvent);
  209 + void alarmCmd(Device device, String alarmMethod, String alarmType, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException;
203 210  
204 211 /**
205 212 * 强制关键帧命令,设备收到此命令应立刻发送一个IDR帧
... ... @@ -207,7 +214,7 @@ public interface ISIPCommander {
207 214 * @param device 视频设备
208 215 * @param channelId 预览通道
209 216 */
210   - boolean iFrameCmd(Device device, String channelId);
  217 + void iFrameCmd(Device device, String channelId) throws InvalidArgumentException, SipException, ParseException;
211 218  
212 219 /**
213 220 * 看守位控制命令
... ... @@ -217,14 +224,14 @@ public interface ISIPCommander {
217 224 * @param resetTime 自动归位时间间隔,开启看守位时使用,单位:秒(s)
218 225 * @param presetIndex 调用预置位编号,开启看守位时使用,取值范围0~255
219 226 */
220   - boolean homePositionCmd(Device device, String channelId, String enabled, String resetTime, String presetIndex, SipSubscribe.Event errorEvent);
  227 + void homePositionCmd(Device device, String channelId, String enabled, String resetTime, String presetIndex, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException;
221 228  
222 229 /**
223 230 * 设备配置命令
224 231 *
225 232 * @param device 视频设备
226 233 */
227   - boolean deviceConfigCmd(Device device);
  234 + void deviceConfigCmd(Device device);
228 235  
229 236 /**
230 237 * 设备配置命令:basicParam
... ... @@ -236,14 +243,14 @@ public interface ISIPCommander {
236 243 * @param heartBeatInterval 心跳间隔时间(可选)
237 244 * @param heartBeatCount 心跳超时次数(可选)
238 245 */
239   - boolean deviceBasicConfigCmd(Device device, String channelId, String name, String expiration, String heartBeatInterval, String heartBeatCount, SipSubscribe.Event errorEvent);
  246 + void deviceBasicConfigCmd(Device device, String channelId, String name, String expiration, String heartBeatInterval, String heartBeatCount, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException;
240 247  
241 248 /**
242 249 * 查询设备状态
243 250 *
244 251 * @param device 视频设备
245 252 */
246   - boolean deviceStatusQuery(Device device, SipSubscribe.Event errorEvent);
  253 + void deviceStatusQuery(Device device, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException;
247 254  
248 255 /**
249 256 * 查询设备信息
... ... @@ -251,14 +258,14 @@ public interface ISIPCommander {
251 258 * @param device 视频设备
252 259 * @return
253 260 */
254   - boolean deviceInfoQuery(Device device);
  261 + void deviceInfoQuery(Device device) throws InvalidArgumentException, SipException, ParseException;
255 262  
256 263 /**
257 264 * 查询目录列表
258 265 *
259 266 * @param device 视频设备
260 267 */
261   - boolean catalogQuery(Device device, int sn, SipSubscribe.Event errorEvent);
  268 + void catalogQuery(Device device, int sn, SipSubscribe.Event errorEvent) throws SipException, InvalidArgumentException, ParseException;
262 269  
263 270 /**
264 271 * 查询录像信息
... ... @@ -268,7 +275,7 @@ public interface ISIPCommander {
268 275 * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss
269 276 * @param sn
270 277 */
271   - boolean recordInfoQuery(Device device, String channelId, String startTime, String endTime, int sn, Integer Secrecy, String type, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent);
  278 + 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;
272 279  
273 280 /**
274 281 * 查询报警信息
... ... @@ -282,8 +289,8 @@ public interface ISIPCommander {
282 289 * @param endTime 报警发生终止时间(可选)
283 290 * @return true = 命令发送成功
284 291 */
285   - boolean alarmInfoQuery(Device device, String startPriority, String endPriority, String alarmMethod,
286   - String alarmType, String startTime, String endTime, SipSubscribe.Event errorEvent);
  292 + void alarmInfoQuery(Device device, String startPriority, String endPriority, String alarmMethod,
  293 + String alarmType, String startTime, String endTime, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException;
287 294  
288 295 /**
289 296 * 查询设备配置
... ... @@ -292,21 +299,21 @@ public interface ISIPCommander {
292 299 * @param channelId 通道编码(可选)
293 300 * @param configType 配置类型:
294 301 */
295   - boolean deviceConfigQuery(Device device, String channelId, String configType, SipSubscribe.Event errorEvent);
  302 + void deviceConfigQuery(Device device, String channelId, String configType, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException;
296 303  
297 304 /**
298 305 * 查询设备预置位置
299 306 *
300 307 * @param device 视频设备
301 308 */
302   - boolean presetQuery(Device device, String channelId, SipSubscribe.Event errorEvent);
  309 + void presetQuery(Device device, String channelId, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException;
303 310  
304 311 /**
305 312 * 查询移动设备位置数据
306 313 *
307 314 * @param device 视频设备
308 315 */
309   - boolean mobilePostitionQuery(Device device, SipSubscribe.Event errorEvent);
  316 + void mobilePostitionQuery(Device device, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException;
310 317  
311 318 /**
312 319 * 订阅、取消订阅移动位置
... ... @@ -314,7 +321,7 @@ public interface ISIPCommander {
314 321 * @param device 视频设备
315 322 * @return true = 命令发送成功
316 323 */
317   - SIPRequest mobilePositionSubscribe(Device device, SIPRequest request, SipSubscribe.Event okEvent , SipSubscribe.Event errorEvent);
  324 + SIPRequest mobilePositionSubscribe(Device device, SIPRequest request, SipSubscribe.Event okEvent , SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException;
318 325  
319 326 /**
320 327 * 订阅、取消订阅报警信息
... ... @@ -327,14 +334,14 @@ public interface ISIPCommander {
327 334 * @param endTime 报警发生终止时间(可选)
328 335 * @return true = 命令发送成功
329 336 */
330   - boolean alarmSubscribe(Device device, int expires, String startPriority, String endPriority, String alarmMethod, String alarmType, String startTime, String endTime);
  337 + void alarmSubscribe(Device device, int expires, String startPriority, String endPriority, String alarmMethod, String alarmType, String startTime, String endTime) throws InvalidArgumentException, SipException, ParseException;
331 338  
332 339 /**
333 340 * 订阅、取消订阅目录信息
334 341 * @param device 视频设备
335 342 * @return true = 命令发送成功
336 343 */
337   - SIPRequest catalogSubscribe(Device device, SIPRequest request, SipSubscribe.Event okEvent ,SipSubscribe.Event errorEvent);
  344 + SIPRequest catalogSubscribe(Device device, SIPRequest request, SipSubscribe.Event okEvent ,SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException;
338 345  
339 346 /**
340 347 * 拉框控制命令
... ... @@ -343,7 +350,7 @@ public interface ISIPCommander {
343 350 * @param channelId 通道id
344 351 * @param cmdString 前端控制指令串
345 352 */
346   - boolean dragZoomCmd(Device device, String channelId, String cmdString);
  353 + void dragZoomCmd(Device device, String channelId, String cmdString) throws InvalidArgumentException, SipException, ParseException;
347 354  
348 355  
349 356 /**
... ... @@ -352,5 +359,11 @@ public interface ISIPCommander {
352 359 * @param deviceAlarm 报警信息信息
353 360 * @return
354 361 */
355   - boolean sendAlarmMessage(Device device, DeviceAlarm deviceAlarm);
  362 + void sendAlarmMessage(Device device, DeviceAlarm deviceAlarm) throws InvalidArgumentException, SipException, ParseException;
  363 +
  364 + void transmitRequest(String transport, Request request) throws SipException, ParseException ;
  365 +
  366 + void transmitRequest(String transport, Request request, SipSubscribe.Event errorEvent) throws SipException, ParseException;
  367 +
  368 + void transmitRequest(String transport, Request request, SipSubscribe.Event errorEvent , SipSubscribe.Event okEvent) throws SipException, ParseException;
356 369 }
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommanderForPlatform.java
... ... @@ -4,7 +4,10 @@ import com.genersoft.iot.vmp.gb28181.bean.*;
4 4 import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
5 5 import com.genersoft.iot.vmp.service.bean.GPSMsgInfo;
6 6  
  7 +import javax.sip.InvalidArgumentException;
  8 +import javax.sip.SipException;
7 9 import javax.sip.header.WWWAuthenticateHeader;
  10 +import java.text.ParseException;
8 11 import java.util.List;
9 12  
10 13 public interface ISIPCommanderForPlatform {
... ... @@ -14,15 +17,15 @@ public interface ISIPCommanderForPlatform {
14 17 * @param parentPlatform
15 18 * @return
16 19 */
17   - boolean register(ParentPlatform parentPlatform, SipSubscribe.Event errorEvent , SipSubscribe.Event okEvent);
18   - boolean register(ParentPlatform parentPlatform, String callId, WWWAuthenticateHeader www, SipSubscribe.Event errorEvent , SipSubscribe.Event okEvent, boolean registerAgain, boolean isRegister);
  20 + void register(ParentPlatform parentPlatform, SipSubscribe.Event errorEvent , SipSubscribe.Event okEvent) throws InvalidArgumentException, ParseException, SipException;
  21 + void register(ParentPlatform parentPlatform, String callId, WWWAuthenticateHeader www, SipSubscribe.Event errorEvent , SipSubscribe.Event okEvent, boolean registerAgain, boolean isRegister) throws SipException, InvalidArgumentException, ParseException;
19 22  
20 23 /**
21 24 * 向上级平台注销
22 25 * @param parentPlatform
23 26 * @return
24 27 */
25   - boolean unregister(ParentPlatform parentPlatform, SipSubscribe.Event errorEvent , SipSubscribe.Event okEvent);
  28 + void unregister(ParentPlatform parentPlatform, SipSubscribe.Event errorEvent , SipSubscribe.Event okEvent) throws InvalidArgumentException, ParseException, SipException;
26 29  
27 30  
28 31 /**
... ... @@ -30,7 +33,7 @@ public interface ISIPCommanderForPlatform {
30 33 * @param parentPlatform
31 34 * @return callId(作为接受回复的判定)
32 35 */
33   - String keepalive(ParentPlatform parentPlatform,SipSubscribe.Event errorEvent , SipSubscribe.Event okEvent);
  36 + String keepalive(ParentPlatform parentPlatform,SipSubscribe.Event errorEvent , SipSubscribe.Event okEvent) throws SipException, InvalidArgumentException, ParseException;
34 37  
35 38  
36 39 /**
... ... @@ -42,8 +45,8 @@ public interface ISIPCommanderForPlatform {
42 45 * @param size
43 46 * @return
44 47 */
45   - boolean catalogQuery(DeviceChannel channel, ParentPlatform parentPlatform, String sn, String fromTag, int size);
46   - boolean catalogQuery(List<DeviceChannel> channels, ParentPlatform parentPlatform, String sn, String fromTag);
  48 + void catalogQuery(DeviceChannel channel, ParentPlatform parentPlatform, String sn, String fromTag, int size) throws SipException, InvalidArgumentException, ParseException;
  49 + void catalogQuery(List<DeviceChannel> channels, ParentPlatform parentPlatform, String sn, String fromTag) throws InvalidArgumentException, ParseException, SipException;
47 50  
48 51 /**
49 52 * 向上级回复DeviceInfo查询信息
... ... @@ -52,7 +55,7 @@ public interface ISIPCommanderForPlatform {
52 55 * @param fromTag
53 56 * @return
54 57 */
55   - boolean deviceInfoResponse(ParentPlatform parentPlatform, String sn, String fromTag);
  58 + void deviceInfoResponse(ParentPlatform parentPlatform, String sn, String fromTag) throws SipException, InvalidArgumentException, ParseException;
56 59  
57 60 /**
58 61 * 向上级回复DeviceStatus查询信息
... ... @@ -61,7 +64,7 @@ public interface ISIPCommanderForPlatform {
61 64 * @param fromTag
62 65 * @return
63 66 */
64   - boolean deviceStatusResponse(ParentPlatform parentPlatform, String sn, String fromTag);
  67 + void deviceStatusResponse(ParentPlatform parentPlatform, String sn, String fromTag) throws SipException, InvalidArgumentException, ParseException;
65 68  
66 69 /**
67 70 * 向上级回复移动位置订阅消息
... ... @@ -70,7 +73,7 @@ public interface ISIPCommanderForPlatform {
70 73 * @param subscribeInfo 订阅相关的信息
71 74 * @return
72 75 */
73   - boolean sendNotifyMobilePosition(ParentPlatform parentPlatform, GPSMsgInfo gpsMsgInfo, SubscribeInfo subscribeInfo);
  76 + void sendNotifyMobilePosition(ParentPlatform parentPlatform, GPSMsgInfo gpsMsgInfo, SubscribeInfo subscribeInfo) throws InvalidArgumentException, ParseException, NoSuchFieldException, SipException, IllegalAccessException;
74 77  
75 78 /**
76 79 * 向上级回复报警消息
... ... @@ -78,21 +81,21 @@ public interface ISIPCommanderForPlatform {
78 81 * @param deviceAlarm 报警信息信息
79 82 * @return
80 83 */
81   - boolean sendAlarmMessage(ParentPlatform parentPlatform, DeviceAlarm deviceAlarm);
  84 + void sendAlarmMessage(ParentPlatform parentPlatform, DeviceAlarm deviceAlarm) throws SipException, InvalidArgumentException, ParseException;
82 85  
83 86 /**
84 87 * 回复catalog事件-增加/更新
85 88 * @param parentPlatform
86 89 * @param deviceChannels
87 90 */
88   - boolean sendNotifyForCatalogAddOrUpdate(String type, ParentPlatform parentPlatform, List<DeviceChannel> deviceChannels, SubscribeInfo subscribeInfo, Integer index);
  91 + void sendNotifyForCatalogAddOrUpdate(String type, ParentPlatform parentPlatform, List<DeviceChannel> deviceChannels, SubscribeInfo subscribeInfo, Integer index) throws InvalidArgumentException, ParseException, NoSuchFieldException, SipException, IllegalAccessException;
89 92  
90 93 /**
91 94 * 回复catalog事件-删除
92 95 * @param parentPlatform
93 96 * @param deviceChannels
94 97 */
95   - boolean sendNotifyForCatalogOther(String type, ParentPlatform parentPlatform, List<DeviceChannel> deviceChannels, SubscribeInfo subscribeInfo, Integer index);
  98 + void sendNotifyForCatalogOther(String type, ParentPlatform parentPlatform, List<DeviceChannel> deviceChannels, SubscribeInfo subscribeInfo, Integer index) throws InvalidArgumentException, ParseException, NoSuchFieldException, SipException, IllegalAccessException;
96 99  
97 100 /**
98 101 * 回复recordInfo
... ... @@ -101,7 +104,7 @@ public interface ISIPCommanderForPlatform {
101 104 * @param fromTag fromTag
102 105 * @param recordInfo 录像信息
103 106 */
104   - boolean recordInfo(DeviceChannel deviceChannel, ParentPlatform parentPlatform, String fromTag, RecordInfo recordInfo);
  107 + void recordInfo(DeviceChannel deviceChannel, ParentPlatform parentPlatform, String fromTag, RecordInfo recordInfo) throws SipException, InvalidArgumentException, ParseException;
105 108  
106 109 /**
107 110 * 录像播放推送完成时发送MediaStatus消息
... ... @@ -109,13 +112,13 @@ public interface ISIPCommanderForPlatform {
109 112 * @param sendRtpItem
110 113 * @return
111 114 */
112   - boolean sendMediaStatusNotify(ParentPlatform platform, SendRtpItem sendRtpItem);
  115 + void sendMediaStatusNotify(ParentPlatform platform, SendRtpItem sendRtpItem) throws SipException, InvalidArgumentException, ParseException;
113 116  
114 117 /**
115 118 * 向发起点播的上级回复bye
116 119 * @param platform 平台信息
117 120 * @param callId callId
118 121 */
119   - void streamByeCmd(ParentPlatform platform, String callId);
120   - void streamByeCmd(ParentPlatform platform, SendRtpItem sendRtpItem);
  122 + void streamByeCmd(ParentPlatform platform, String callId) throws SipException, InvalidArgumentException, ParseException;
  123 + void streamByeCmd(ParentPlatform platform, SendRtpItem sendRtpItem) throws SipException, InvalidArgumentException, ParseException;
121 124 }
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderProvider.java
... ... @@ -10,6 +10,9 @@ import javax.sip.header.*;
10 10 import javax.sip.message.Request;
11 11  
12 12 import com.genersoft.iot.vmp.common.StreamInfo;
  13 +import com.genersoft.iot.vmp.gb28181.bean.SipMsgInfo;
  14 +import com.genersoft.iot.vmp.gb28181.bean.SipTransactionInfo;
  15 +import com.genersoft.iot.vmp.gb28181.bean.SsrcTransaction;
13 16 import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
14 17 import com.genersoft.iot.vmp.gb28181.utils.SipUtils;
15 18 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
... ... @@ -17,6 +20,7 @@ import com.genersoft.iot.vmp.utils.GitUtil;
17 20 import gov.nist.javax.sip.SipProviderImpl;
18 21 import gov.nist.javax.sip.SipStackImpl;
19 22 import gov.nist.javax.sip.message.SIPRequest;
  23 +import gov.nist.javax.sip.message.SIPResponse;
20 24 import gov.nist.javax.sip.stack.SIPDialog;
21 25 import org.springframework.beans.factory.annotation.Autowired;
22 26 import org.springframework.beans.factory.annotation.Qualifier;
... ... @@ -168,34 +172,37 @@ public class SIPRequestHeaderProvider {
168 172 return request;
169 173 }
170 174  
171   - public Request createByteRequest(Device device, String channelId, String viaTag, String fromTag, String toTag, String callId) throws ParseException, InvalidArgumentException, PeerUnavailableException {
  175 + public Request createByteRequest(Device device, String channelId, SipTransactionInfo transactionInfo) throws ParseException, InvalidArgumentException, PeerUnavailableException {
172 176 Request request = null;
173 177 //请求行
174 178 SipURI requestLine = sipFactory.createAddressFactory().createSipURI(channelId, device.getHostAddress());
175 179 // via
176 180 ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();
177   - ViaHeader viaHeader = sipFactory.createHeaderFactory().createViaHeader(sipConfig.getIp(), sipConfig.getPort(), device.getTransport(), viaTag);
  181 + ViaHeader viaHeader = sipFactory.createHeaderFactory().createViaHeader(sipConfig.getIp(), sipConfig.getPort(), device.getTransport(), SipUtils.getNewViaTag());
178 182 viaHeaders.add(viaHeader);
179 183 //from
180 184 SipURI fromSipURI = sipFactory.createAddressFactory().createSipURI(sipConfig.getId(),sipConfig.getDomain());
181 185 Address fromAddress = sipFactory.createAddressFactory().createAddress(fromSipURI);
182   - FromHeader fromHeader = sipFactory.createHeaderFactory().createFromHeader(fromAddress, fromTag); //必须要有标记,否则无法创建会话,无法回应ack
  186 + FromHeader fromHeader = sipFactory.createHeaderFactory().createFromHeader(fromAddress, transactionInfo.getFromTag());
183 187 //to
184 188 SipURI toSipURI = sipFactory.createAddressFactory().createSipURI(channelId,device.getHostAddress());
185 189 Address toAddress = sipFactory.createAddressFactory().createAddress(toSipURI);
186   - ToHeader toHeader = sipFactory.createHeaderFactory().createToHeader(toAddress,toTag);
  190 + ToHeader toHeader = sipFactory.createHeaderFactory().createToHeader(toAddress, transactionInfo.getToTag());
187 191  
188 192 //Forwards
189 193 MaxForwardsHeader maxForwards = sipFactory.createHeaderFactory().createMaxForwardsHeader(70);
190 194  
191 195 //ceq
192 196 CSeqHeader cSeqHeader = sipFactory.createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(), Request.BYE);
193   - CallIdHeader callIdHeader = sipFactory.createHeaderFactory().createCallIdHeader(callId);
  197 + CallIdHeader callIdHeader = sipFactory.createHeaderFactory().createCallIdHeader(transactionInfo.getCallId());
194 198 request = sipFactory.createMessageFactory().createRequest(requestLine, Request.BYE, callIdHeader, cSeqHeader,fromHeader, toHeader, viaHeaders, maxForwards);
195 199  
196 200 request.addHeader(SipUtils.createUserAgentHeader(sipFactory, gitUtil));
197 201  
198 202 Address concatAddress = sipFactory.createAddressFactory().createAddress(sipFactory.createAddressFactory().createSipURI(sipConfig.getId(), sipConfig.getIp()+":"+sipConfig.getPort()));
  203 + request.addHeader(sipFactory.createHeaderFactory().createContactHeader(concatAddress));
  204 +
  205 + request.addHeader(SipUtils.createUserAgentHeader(sipFactory, gitUtil));
199 206  
200 207 return request;
201 208 }
... ... @@ -251,47 +258,72 @@ public class SIPRequestHeaderProvider {
251 258 return request;
252 259 }
253 260  
254   - public Request createInfoRequest(Device device, StreamInfo streamInfo, String content)
  261 + public SIPRequest createInfoRequest(Device device, String channelId, String content, SipTransactionInfo transactionInfo)
255 262 throws SipException, ParseException, InvalidArgumentException {
256   - if (streamInfo == null) {
257   - return null;
258   - }
259   - Request request = null;
260   - SIPDialog dialog = streamSession.getDialogByStream(streamInfo.getDeviceID(), streamInfo.getChannelId(), streamInfo.getStream());
261   - if (dialog == null) {
  263 + if (device == null || transactionInfo == null) {
262 264 return null;
263 265 }
  266 + SIPRequest request = null;
  267 + //请求行
  268 + SipURI requestLine = sipFactory.createAddressFactory().createSipURI(channelId, device.getHostAddress());
  269 + // via
  270 + ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();
  271 + ViaHeader viaHeader = sipFactory.createHeaderFactory().createViaHeader(sipConfig.getIp(), sipConfig.getPort(), device.getTransport(), SipUtils.getNewViaTag());
  272 + viaHeaders.add(viaHeader);
  273 + //from
  274 + SipURI fromSipURI = sipFactory.createAddressFactory().createSipURI(sipConfig.getId(),sipConfig.getDomain());
  275 + Address fromAddress = sipFactory.createAddressFactory().createAddress(fromSipURI);
  276 + FromHeader fromHeader = sipFactory.createHeaderFactory().createFromHeader(fromAddress, transactionInfo.getFromTag());
  277 + //to
  278 + SipURI toSipURI = sipFactory.createAddressFactory().createSipURI(channelId,device.getHostAddress());
  279 + Address toAddress = sipFactory.createAddressFactory().createAddress(toSipURI);
  280 + ToHeader toHeader = sipFactory.createHeaderFactory().createToHeader(toAddress, transactionInfo.getToTag());
  281 +
  282 + //Forwards
  283 + MaxForwardsHeader maxForwards = sipFactory.createHeaderFactory().createMaxForwardsHeader(70);
  284 +
  285 + //ceq
  286 + CSeqHeader cSeqHeader = sipFactory.createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(), Request.INFO);
  287 + CallIdHeader callIdHeader = sipFactory.createHeaderFactory().createCallIdHeader(transactionInfo.getCallId());
  288 + request = (SIPRequest)sipFactory.createMessageFactory().createRequest(requestLine, Request.INFO, callIdHeader, cSeqHeader,fromHeader, toHeader, viaHeaders, maxForwards);
264 289  
265   - SipStack sipStack = udpSipProvider.getSipStack();
266   - SIPDialog sipDialog = ((SipStackImpl) sipStack).putDialog(dialog);
267   - if (dialog != sipDialog) {
268   - dialog = sipDialog;
269   - }else {
270   - dialog.setSipProvider(udpSipProvider);
  290 + request.addHeader(SipUtils.createUserAgentHeader(sipFactory, gitUtil));
  291 +
  292 + Address concatAddress = sipFactory.createAddressFactory().createAddress(sipFactory.createAddressFactory().createSipURI(sipConfig.getId(), sipConfig.getIp()+":"+sipConfig.getPort()));
  293 + request.addHeader(sipFactory.createHeaderFactory().createContactHeader(concatAddress));
  294 +
  295 + request.addHeader(SipUtils.createUserAgentHeader(sipFactory, gitUtil));
  296 +
  297 + if (content != null) {
  298 + ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader("Application",
  299 + "MANSRTSP");
  300 + request.setContent(content, contentTypeHeader);
271 301 }
272   - streamSession.put(streamInfo.getDeviceID(), streamInfo.getChannelId(), dialog.getCallId().getCallId(), dialog);
273   - Request infoRequest = dialog.createRequest(Request.INFO);
274   - SipURI sipURI = (SipURI) infoRequest.getRequestURI();
275   - sipURI.setHost(device.getIp());
276   - sipURI.setPort(device.getPort());
277   - sipURI.setUser(streamInfo.getChannelId());
278   -
279   - ViaHeader viaHeader = (ViaHeader) infoRequest.getHeader(ViaHeader.NAME);
280   - viaHeader.setRPort();
281   - // 增加Contact header
282   - Address concatAddress = sipFactory.createAddressFactory().createAddress(sipFactory.createAddressFactory()
283   - .createSipURI(sipConfig.getId(), sipConfig.getIp() + ":" + sipConfig.getPort()));
284   - infoRequest.addHeader(sipFactory.createHeaderFactory().createContactHeader(concatAddress));
285   - infoRequest.addHeader(SipUtils.createUserAgentHeader(sipFactory, gitUtil));
286   -
287   - ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader("Application",
288   - "MANSRTSP");
289   - infoRequest.setContent(content, contentTypeHeader);
290   -
291   - CSeqHeader cSeqHeader = (CSeqHeader)infoRequest.getHeader(CSeqHeader.NAME);
292   - cSeqHeader.setSeqNumber(redisCatchStorage.getCSEQ());
293   - // ceq
294   - infoRequest.addHeader(cSeqHeader);
295   - return infoRequest;
  302 + return request;
  303 + }
  304 +
  305 + public Request createAckRequest(SipURI sipURI, SIPResponse sipResponse) throws ParseException, InvalidArgumentException, PeerUnavailableException {
  306 +
  307 + // via
  308 + ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();
  309 + ViaHeader viaHeader = sipFactory.createHeaderFactory().createViaHeader(sipConfig.getIp(), sipConfig.getPort(), sipResponse.getTopmostViaHeader().getTransport(), SipUtils.getNewViaTag());
  310 + viaHeaders.add(viaHeader);
  311 +
  312 + //Forwards
  313 + MaxForwardsHeader maxForwards = sipFactory.createHeaderFactory().createMaxForwardsHeader(70);
  314 +
  315 + //ceq
  316 + CSeqHeader cSeqHeader = sipFactory.createHeaderFactory().createCSeqHeader(sipResponse.getCSeqHeader().getSeqNumber(), Request.ACK);
  317 +
  318 + Request request = sipFactory.createMessageFactory().createRequest(sipURI, Request.ACK, sipResponse.getCallIdHeader(), cSeqHeader, sipResponse.getFromHeader(), sipResponse.getToHeader(), viaHeaders, maxForwards);
  319 +
  320 + request.addHeader(SipUtils.createUserAgentHeader(sipFactory, gitUtil));
  321 +
  322 + Address concatAddress = sipFactory.createAddressFactory().createAddress(sipFactory.createAddressFactory().createSipURI(sipConfig.getId(), sipConfig.getIp()+":"+sipConfig.getPort()));
  323 + request.addHeader(sipFactory.createHeaderFactory().createContactHeader(concatAddress));
  324 +
  325 + request.addHeader(SipUtils.createUserAgentHeader(sipFactory, gitUtil));
  326 +
  327 + return request;
296 328 }
297 329 }
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java
... ... @@ -5,6 +5,7 @@ import com.genersoft.iot.vmp.common.StreamInfo;
5 5 import com.genersoft.iot.vmp.conf.DynamicTask;
6 6 import com.genersoft.iot.vmp.conf.SipConfig;
7 7 import com.genersoft.iot.vmp.conf.UserSetting;
  8 +import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException;
8 9 import com.genersoft.iot.vmp.gb28181.bean.*;
9 10 import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
10 11 import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
... ... @@ -22,17 +23,20 @@ import com.genersoft.iot.vmp.service.bean.SSRCInfo;
22 23 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
23 24 import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
24 25 import com.genersoft.iot.vmp.utils.GitUtil;
  26 +import gov.nist.javax.sip.SIPConstants;
25 27 import gov.nist.javax.sip.SipProviderImpl;
26 28 import gov.nist.javax.sip.SipStackImpl;
27   -import gov.nist.javax.sip.message.MessageFactoryImpl;
28 29 import gov.nist.javax.sip.message.SIPRequest;
  30 +import gov.nist.javax.sip.message.SIPResponse;
29 31 import gov.nist.javax.sip.stack.SIPClientTransaction;
  32 +import gov.nist.javax.sip.stack.SIPClientTransactionImpl;
30 33 import gov.nist.javax.sip.stack.SIPDialog;
31 34 import org.slf4j.Logger;
32 35 import org.slf4j.LoggerFactory;
33 36 import org.springframework.beans.factory.annotation.Autowired;
34 37 import org.springframework.beans.factory.annotation.Qualifier;
35 38 import org.springframework.context.annotation.DependsOn;
  39 +import org.springframework.context.annotation.Lazy;
36 40 import org.springframework.stereotype.Component;
37 41 import org.springframework.util.ObjectUtils;
38 42  
... ... @@ -41,1791 +45,1444 @@ import javax.sip.address.Address;
41 45 import javax.sip.address.SipURI;
42 46 import javax.sip.header.*;
43 47 import javax.sip.message.Request;
  48 +import javax.sip.message.Response;
44 49 import java.lang.reflect.Field;
45 50 import java.text.ParseException;
46 51 import java.util.HashSet;
47 52  
48   -/**
49   - * @description:设备能力接口,用于定义设备的控制、查询能力
  53 +/**
  54 + * @description:设备能力接口,用于定义设备的控制、查询能力
50 55 * @author: swwheihei
51   - * @date: 2020年5月3日 下午9:22:48
  56 + * @date: 2020年5月3日 下午9:22:48
52 57 */
53 58 @Component
54 59 @DependsOn("sipLayer")
55 60 public class SIPCommander implements ISIPCommander {
56 61  
57   - private final Logger logger = LoggerFactory.getLogger(SIPCommander.class);
58   -
59   - @Autowired
60   - private SipConfig sipConfig;
61   -
62   - @Autowired
63   - private SipFactory sipFactory;
64   -
65   - @Autowired
66   - private GitUtil gitUtil;
67   -
68   - @Autowired
69   - @Qualifier(value="tcpSipProvider")
70   - private SipProviderImpl tcpSipProvider;
71   -
72   - @Autowired
73   - @Qualifier(value="udpSipProvider")
74   - private SipProviderImpl udpSipProvider;
75   -
76   - @Autowired
77   - private SIPRequestHeaderProvider headerProvider;
78   -
79   - @Autowired
80   - private VideoStreamSessionManager streamSession;
81   -
82   - @Autowired
83   - private IVideoManagerStorage storager;
84   -
85   - @Autowired
86   - private IRedisCatchStorage redisCatchStorage;
87   -
88   - @Autowired
89   - private UserSetting userSetting;
90   -
91   - @Autowired
92   - private ZlmHttpHookSubscribe subscribe;
93   -
94   - @Autowired
95   - private SipSubscribe sipSubscribe;
96   -
97   - @Autowired
98   - private IMediaServerService mediaServerService;
99   -
100   - @Autowired
101   - private DynamicTask dynamicTask;
102   -
103   -
104   - /**
105   - * 云台方向放控制,使用配置文件中的默认镜头移动速度
106   - *
107   - * @param device 控制设备
108   - * @param channelId 预览通道
109   - * @param leftRight 镜头左移右移 0:停止 1:左移 2:右移
110   - * @param upDown 镜头上移下移 0:停止 1:上移 2:下移
111   - */
112   - @Override
113   - public boolean ptzdirectCmd(Device device, String channelId, int leftRight, int upDown) {
114   - return ptzCmd(device, channelId, leftRight, upDown, 0, sipConfig.getPtzSpeed(), 0);
115   - }
116   -
117   - /**
118   - * 云台方向放控制
119   - *
120   - * @param device 控制设备
121   - * @param channelId 预览通道
122   - * @param leftRight 镜头左移右移 0:停止 1:左移 2:右移
123   - * @param upDown 镜头上移下移 0:停止 1:上移 2:下移
124   - * @param moveSpeed 镜头移动速度
125   - */
126   - @Override
127   - public boolean ptzdirectCmd(Device device, String channelId, int leftRight, int upDown, int moveSpeed) {
128   - return ptzCmd(device, channelId, leftRight, upDown, 0, moveSpeed, 0);
129   - }
130   -
131   - /**
132   - * 云台缩放控制,使用配置文件中的默认镜头缩放速度
133   - *
134   - * @param device 控制设备
135   - * @param channelId 预览通道
136   - * @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大
137   - */
138   - @Override
139   - public boolean ptzZoomCmd(Device device, String channelId, int inOut) {
140   - return ptzCmd(device, channelId, 0, 0, inOut, 0, sipConfig.getPtzSpeed());
141   - }
142   -
143   - /**
144   - * 云台缩放控制
145   - *
146   - * @param device 控制设备
147   - * @param channelId 预览通道
148   - * @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大
149   - * @param zoomSpeed 镜头缩放速度
150   - */
151   - @Override
152   - public boolean ptzZoomCmd(Device device, String channelId, int inOut, int zoomSpeed) {
153   - return ptzCmd(device, channelId, 0, 0, inOut, 0, zoomSpeed);
154   - }
155   -
156   - /**
157   - * 云台指令码计算
158   - *
159   - * @param leftRight 镜头左移右移 0:停止 1:左移 2:右移
160   - * @param upDown 镜头上移下移 0:停止 1:上移 2:下移
161   - * @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大
162   - * @param moveSpeed 镜头移动速度 默认 0XFF (0-255)
163   - * @param zoomSpeed 镜头缩放速度 默认 0X1 (0-255)
164   - */
165   - public static String cmdString(int leftRight, int upDown, int inOut, int moveSpeed, int zoomSpeed) {
166   - int cmdCode = 0;
167   - if (leftRight == 2) {
168   - cmdCode|=0x01; // 右移
169   - } else if(leftRight == 1) {
170   - cmdCode|=0x02; // 左移
171   - }
172   - if (upDown == 2) {
173   - cmdCode|=0x04; // 下移
174   - } else if(upDown == 1) {
175   - cmdCode|=0x08; // 上移
176   - }
177   - if (inOut == 2) {
178   - cmdCode |= 0x10; // 放大
179   - } else if(inOut == 1) {
180   - cmdCode |= 0x20; // 缩小
181   - }
182   - StringBuilder builder = new StringBuilder("A50F01");
183   - String strTmp;
184   - strTmp = String.format("%02X", cmdCode);
185   - builder.append(strTmp, 0, 2);
186   - strTmp = String.format("%02X", moveSpeed);
187   - builder.append(strTmp, 0, 2);
188   - builder.append(strTmp, 0, 2);
189   - strTmp = String.format("%X", zoomSpeed);
190   - builder.append(strTmp, 0, 1).append("0");
191   - //计算校验码
192   - int checkCode = (0XA5 + 0X0F + 0X01 + cmdCode + moveSpeed + moveSpeed + (zoomSpeed /*<< 4*/ & 0XF0)) % 0X100;
193   - strTmp = String.format("%02X", checkCode);
194   - builder.append(strTmp, 0, 2);
195   - return builder.toString();
196   -}
197   -
198   - /**
199   - * 云台指令码计算
200   - *
201   - * @param cmdCode 指令码
202   - * @param parameter1 数据1
203   - * @param parameter2 数据2
204   - * @param combineCode2 组合码2
205   - */
  62 + private final Logger logger = LoggerFactory.getLogger(SIPCommander.class);
  63 +
  64 + @Autowired
  65 + private SipConfig sipConfig;
  66 +
  67 + @Autowired
  68 + private SipFactory sipFactory;
  69 +
  70 + @Autowired
  71 + private GitUtil gitUtil;
  72 +
  73 + @Autowired
  74 + @Qualifier(value = "tcpSipProvider")
  75 + private SipProviderImpl tcpSipProvider;
  76 +
  77 + @Autowired
  78 + @Qualifier(value = "udpSipProvider")
  79 + private SipProviderImpl udpSipProvider;
  80 +
  81 + @Autowired
  82 + private SIPRequestHeaderProvider headerProvider;
  83 +
  84 + @Autowired
  85 + private VideoStreamSessionManager streamSession;
  86 +
  87 + @Autowired
  88 + private UserSetting userSetting;
  89 +
  90 + @Autowired
  91 + private ZlmHttpHookSubscribe subscribe;
  92 +
  93 + @Autowired
  94 + private SipSubscribe sipSubscribe;
  95 +
  96 + @Autowired
  97 + private IMediaServerService mediaServerService;
  98 +
  99 +
  100 + /**
  101 + * 云台方向放控制,使用配置文件中的默认镜头移动速度
  102 + *
  103 + * @param device 控制设备
  104 + * @param channelId 预览通道
  105 + * @param leftRight 镜头左移右移 0:停止 1:左移 2:右移
  106 + * @param upDown 镜头上移下移 0:停止 1:上移 2:下移
  107 + */
  108 + @Override
  109 + public void ptzdirectCmd(Device device, String channelId, int leftRight, int upDown) throws InvalidArgumentException, ParseException, SipException {
  110 + ptzCmd(device, channelId, leftRight, upDown, 0, sipConfig.getPtzSpeed(), 0);
  111 + }
  112 +
  113 + /**
  114 + * 云台方向放控制
  115 + *
  116 + * @param device 控制设备
  117 + * @param channelId 预览通道
  118 + * @param leftRight 镜头左移右移 0:停止 1:左移 2:右移
  119 + * @param upDown 镜头上移下移 0:停止 1:上移 2:下移
  120 + * @param moveSpeed 镜头移动速度
  121 + */
  122 + @Override
  123 + public void ptzdirectCmd(Device device, String channelId, int leftRight, int upDown, int moveSpeed) throws InvalidArgumentException, ParseException, SipException {
  124 + ptzCmd(device, channelId, leftRight, upDown, 0, moveSpeed, 0);
  125 + }
  126 +
  127 + /**
  128 + * 云台缩放控制,使用配置文件中的默认镜头缩放速度
  129 + *
  130 + * @param device 控制设备
  131 + * @param channelId 预览通道
  132 + * @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大
  133 + */
  134 + @Override
  135 + public void ptzZoomCmd(Device device, String channelId, int inOut) throws InvalidArgumentException, ParseException, SipException {
  136 + ptzCmd(device, channelId, 0, 0, inOut, 0, sipConfig.getPtzSpeed());
  137 + }
  138 +
  139 + /**
  140 + * 云台缩放控制
  141 + *
  142 + * @param device 控制设备
  143 + * @param channelId 预览通道
  144 + * @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大
  145 + * @param zoomSpeed 镜头缩放速度
  146 + */
  147 + @Override
  148 + public void ptzZoomCmd(Device device, String channelId, int inOut, int zoomSpeed) throws InvalidArgumentException, ParseException, SipException {
  149 + ptzCmd(device, channelId, 0, 0, inOut, 0, zoomSpeed);
  150 + }
  151 +
  152 + /**
  153 + * 云台指令码计算
  154 + *
  155 + * @param cmdCode 指令码
  156 + * @param parameter1 数据1
  157 + * @param parameter2 数据2
  158 + * @param combineCode2 组合码2
  159 + */
206 160 public static String frontEndCmdString(int cmdCode, int parameter1, int parameter2, int combineCode2) {
207   - StringBuilder builder = new StringBuilder("A50F01");
208   - String strTmp;
209   - strTmp = String.format("%02X", cmdCode);
210   - builder.append(strTmp, 0, 2);
211   - strTmp = String.format("%02X", parameter1);
212   - builder.append(strTmp, 0, 2);
213   - strTmp = String.format("%02X", parameter2);
214   - builder.append(strTmp, 0, 2);
215   - strTmp = String.format("%X", combineCode2);
216   - builder.append(strTmp, 0, 1).append("0");
217   - //计算校验码
218   - int checkCode = (0XA5 + 0X0F + 0X01 + cmdCode + parameter1 + parameter2 + (combineCode2 & 0XF0)) % 0X100;
219   - strTmp = String.format("%02X", checkCode);
220   - builder.append(strTmp, 0, 2);
221   - return builder.toString();
222   - }
223   -
224   - /**
225   - * 云台控制,支持方向与缩放控制
226   - *
227   - * @param device 控制设备
228   - * @param channelId 预览通道
229   - * @param leftRight 镜头左移右移 0:停止 1:左移 2:右移
230   - * @param upDown 镜头上移下移 0:停止 1:上移 2:下移
231   - * @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大
232   - * @param moveSpeed 镜头移动速度
233   - * @param zoomSpeed 镜头缩放速度
234   - */
235   - @Override
236   - public boolean ptzCmd(Device device, String channelId, int leftRight, int upDown, int inOut, int moveSpeed,
237   - int zoomSpeed) {
238   - try {
239   - String cmdStr= cmdString(leftRight, upDown, inOut, moveSpeed, zoomSpeed);
240   - StringBuffer ptzXml = new StringBuffer(200);
241   - String charset = device.getCharset();
242   - ptzXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
243   - ptzXml.append("<Control>\r\n");
244   - ptzXml.append("<CmdType>DeviceControl</CmdType>\r\n");
245   - ptzXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
246   - ptzXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
247   - ptzXml.append("<PTZCmd>" + cmdStr + "</PTZCmd>\r\n");
248   - ptzXml.append("<Info>\r\n");
249   - ptzXml.append("<ControlPriority>5</ControlPriority>\r\n");
250   - ptzXml.append("</Info>\r\n");
251   - ptzXml.append("</Control>\r\n");
252   -
253   - CallIdHeader callIdHeader = device.getTransport().equalsIgnoreCase("TCP") ? tcpSipProvider.getNewCallId()
254   - : udpSipProvider.getNewCallId();
255   -
256   - Request request = headerProvider.createMessageRequest(device, ptzXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null, callIdHeader);
257   -
258   - transmitRequest(device, request);
259   - return true;
260   - } catch (SipException | ParseException | InvalidArgumentException e) {
261   - e.printStackTrace();
262   - }
263   - return false;
264   - }
265   -
266   - /**
267   - * 前端控制,包括PTZ指令、FI指令、预置位指令、巡航指令、扫描指令和辅助开关指令
268   - *
269   - * @param device 控制设备
270   - * @param channelId 预览通道
271   - * @param cmdCode 指令码
272   - * @param parameter1 数据1
273   - * @param parameter2 数据2
274   - * @param combineCode2 组合码2
275   - */
276   - @Override
277   - public boolean frontEndCmd(Device device, String channelId, int cmdCode, int parameter1, int parameter2, int combineCode2) {
278   - try {
279   - String cmdStr= frontEndCmdString(cmdCode, parameter1, parameter2, combineCode2);
280   - logger.debug("控制字符串:" + cmdStr);
281   - StringBuffer ptzXml = new StringBuffer(200);
282   - String charset = device.getCharset();
283   - ptzXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
284   - ptzXml.append("<Control>\r\n");
285   - ptzXml.append("<CmdType>DeviceControl</CmdType>\r\n");
286   - ptzXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
287   - ptzXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
288   - ptzXml.append("<PTZCmd>" + cmdStr + "</PTZCmd>\r\n");
289   - ptzXml.append("<Info>\r\n");
290   - ptzXml.append("<ControlPriority>5</ControlPriority>\r\n");
291   - ptzXml.append("</Info>\r\n");
292   - ptzXml.append("</Control>\r\n");
293   -
294   -
295   - CallIdHeader callIdHeader = device.getTransport().equalsIgnoreCase("TCP") ? tcpSipProvider.getNewCallId()
296   - : udpSipProvider.getNewCallId();
297   -
298   - Request request = headerProvider.createMessageRequest(device, ptzXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null, callIdHeader);
299   - transmitRequest(device, request);
300   - return true;
301   - } catch (SipException | ParseException | InvalidArgumentException e) {
302   - e.printStackTrace();
303   - }
304   - return false;
305   - }
306   -
307   - /**
308   - * 前端控制指令(用于转发上级指令)
309   - * @param device 控制设备
310   - * @param channelId 预览通道
311   - * @param cmdString 前端控制指令串
312   - */
313   - @Override
314   - public boolean fronEndCmd(Device device, String channelId, String cmdString, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) {
315   - try {
316   - StringBuffer ptzXml = new StringBuffer(200);
317   - String charset = device.getCharset();
318   - ptzXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
319   - ptzXml.append("<Control>\r\n");
320   - ptzXml.append("<CmdType>DeviceControl</CmdType>\r\n");
321   - ptzXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
322   - ptzXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
323   - ptzXml.append("<PTZCmd>" + cmdString + "</PTZCmd>\r\n");
324   - ptzXml.append("<Info>\r\n");
325   - ptzXml.append("<ControlPriority>5</ControlPriority>\r\n");
326   - ptzXml.append("</Info>\r\n");
327   - ptzXml.append("</Control>\r\n");
328   -
329   -
330   - CallIdHeader callIdHeader = device.getTransport().equalsIgnoreCase("TCP") ? tcpSipProvider.getNewCallId()
331   - : udpSipProvider.getNewCallId();
332   -
333   - Request request = headerProvider.createMessageRequest(device, ptzXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null, callIdHeader);
334   - transmitRequest(device, request, errorEvent, okEvent);
335   - return true;
336   - } catch (SipException | ParseException | InvalidArgumentException e) {
337   - e.printStackTrace();
338   - }
339   - return false;
340   - }
341   -
342   - /**
343   - * 请求预览视频流
344   - * @param device 视频设备
345   - * @param channelId 预览通道
346   - * @param event hook订阅
347   - * @param errorEvent sip错误订阅
348   - */
349   - @Override
350   - public void playStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId,
351   - ZlmHttpHookSubscribe.Event event, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) {
352   - String stream = ssrcInfo.getStream();
353   - try {
354   - if (device == null) {
355   - return;
356   - }
357   -// String streamMode = device.getStreamMode().toUpperCase();
358   -
359   - logger.info("{} 分配的ZLM为: {} [{}:{}]", stream, mediaServerItem.getId(), mediaServerItem.getIp(), ssrcInfo.getPort());
360   - HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", stream, true, "rtsp", mediaServerItem.getId());
361   - subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, JSONObject json)->{
362   - if (event != null) {
363   - event.response(mediaServerItemInUse, json);
364   - subscribe.removeSubscribe(hookSubscribe);
365   - }
366   - });
367   - //
368   - StringBuffer content = new StringBuffer(200);
369   - content.append("v=0\r\n");
370   - content.append("o="+ channelId+" 0 0 IN IP4 "+ mediaServerItem.getSdpIp() +"\r\n");
371   - content.append("s=Play\r\n");
372   - content.append("c=IN IP4 "+ mediaServerItem.getSdpIp() +"\r\n");
373   - content.append("t=0 0\r\n");
374   -
375   - if (userSetting.isSeniorSdp()) {
376   - if("TCP-PASSIVE".equalsIgnoreCase(device.getStreamMode())) {
377   - content.append("m=video "+ ssrcInfo.getPort() +" TCP/RTP/AVP 96 126 125 99 34 98 97\r\n");
378   - }else if ("TCP-ACTIVE".equalsIgnoreCase(device.getStreamMode())) {
379   - content.append("m=video "+ ssrcInfo.getPort() +" TCP/RTP/AVP 96 126 125 99 34 98 97\r\n");
380   - }else if("UDP".equalsIgnoreCase(device.getStreamMode())) {
381   - content.append("m=video "+ ssrcInfo.getPort() +" RTP/AVP 96 126 125 99 34 98 97\r\n");
382   - }
383   - content.append("a=recvonly\r\n");
384   - content.append("a=rtpmap:96 PS/90000\r\n");
385   - content.append("a=fmtp:126 profile-level-id=42e01e\r\n");
386   - content.append("a=rtpmap:126 H264/90000\r\n");
387   - content.append("a=rtpmap:125 H264S/90000\r\n");
388   - content.append("a=fmtp:125 profile-level-id=42e01e\r\n");
389   - content.append("a=rtpmap:99 H265/90000\r\n");
390   - content.append("a=rtpmap:98 H264/90000\r\n");
391   - content.append("a=rtpmap:97 MPEG4/90000\r\n");
392   - if("TCP-PASSIVE".equalsIgnoreCase(device.getStreamMode())){ // tcp被动模式
393   - content.append("a=setup:passive\r\n");
394   - content.append("a=connection:new\r\n");
395   - }else if ("TCP-ACTIVE".equalsIgnoreCase(device.getStreamMode())) { // tcp主动模式
396   - content.append("a=setup:active\r\n");
397   - content.append("a=connection:new\r\n");
398   - }
399   - }else {
400   - if("TCP-PASSIVE".equalsIgnoreCase(device.getStreamMode())) {
401   - content.append("m=video "+ ssrcInfo.getPort() +" TCP/RTP/AVP 96 97 98 99\r\n");
402   - }else if ("TCP-ACTIVE".equalsIgnoreCase(device.getStreamMode())) {
403   - content.append("m=video "+ ssrcInfo.getPort() +" TCP/RTP/AVP 96 97 98 99\r\n");
404   - }else if("UDP".equalsIgnoreCase(device.getStreamMode())) {
405   - content.append("m=video "+ ssrcInfo.getPort() +" RTP/AVP 96 97 98 99\r\n");
406   - }
407   - content.append("a=recvonly\r\n");
408   - content.append("a=rtpmap:96 PS/90000\r\n");
409   - content.append("a=rtpmap:98 H264/90000\r\n");
410   - content.append("a=rtpmap:97 MPEG4/90000\r\n");
411   - content.append("a=rtpmap:99 H265/90000\r\n");
412   - if ("TCP-PASSIVE".equalsIgnoreCase(device.getStreamMode())) { // tcp被动模式
413   - content.append("a=setup:passive\r\n");
414   - content.append("a=connection:new\r\n");
415   - } else if ("TCP-ACTIVE".equalsIgnoreCase(device.getStreamMode())) { // tcp主动模式
416   - content.append("a=setup:active\r\n");
417   - content.append("a=connection:new\r\n");
418   - }
419   - }
420   -
421   - content.append("y="+ssrcInfo.getSsrc()+"\r\n");//ssrc
422   - // f字段:f= v/编码格式/分辨率/帧率/码率类型/码率大小a/编码格式/码率大小/采样率
  161 + StringBuilder builder = new StringBuilder("A50F01");
  162 + String strTmp;
  163 + strTmp = String.format("%02X", cmdCode);
  164 + builder.append(strTmp, 0, 2);
  165 + strTmp = String.format("%02X", parameter1);
  166 + builder.append(strTmp, 0, 2);
  167 + strTmp = String.format("%02X", parameter2);
  168 + builder.append(strTmp, 0, 2);
  169 + strTmp = String.format("%X", combineCode2);
  170 + builder.append(strTmp, 0, 1).append("0");
  171 + //计算校验码
  172 + int checkCode = (0XA5 + 0X0F + 0X01 + cmdCode + parameter1 + parameter2 + (combineCode2 & 0XF0)) % 0X100;
  173 + strTmp = String.format("%02X", checkCode);
  174 + builder.append(strTmp, 0, 2);
  175 + return builder.toString();
  176 + }
  177 +
  178 + /**
  179 + * 云台控制,支持方向与缩放控制
  180 + *
  181 + * @param device 控制设备
  182 + * @param channelId 预览通道
  183 + * @param leftRight 镜头左移右移 0:停止 1:左移 2:右移
  184 + * @param upDown 镜头上移下移 0:停止 1:上移 2:下移
  185 + * @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大
  186 + * @param moveSpeed 镜头移动速度
  187 + * @param zoomSpeed 镜头缩放速度
  188 + */
  189 + @Override
  190 + public void ptzCmd(Device device, String channelId, int leftRight, int upDown, int inOut, int moveSpeed,
  191 + int zoomSpeed) throws InvalidArgumentException, SipException, ParseException {
  192 + String cmdStr = SipUtils.cmdString(leftRight, upDown, inOut, moveSpeed, zoomSpeed);
  193 + StringBuffer ptzXml = new StringBuffer(200);
  194 + String charset = device.getCharset();
  195 + ptzXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
  196 + ptzXml.append("<Control>\r\n");
  197 + ptzXml.append("<CmdType>DeviceControl</CmdType>\r\n");
  198 + ptzXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");
  199 + ptzXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
  200 + ptzXml.append("<PTZCmd>" + cmdStr + "</PTZCmd>\r\n");
  201 + ptzXml.append("<Info>\r\n");
  202 + ptzXml.append("<ControlPriority>5</ControlPriority>\r\n");
  203 + ptzXml.append("</Info>\r\n");
  204 + ptzXml.append("</Control>\r\n");
  205 +
  206 + CallIdHeader callIdHeader = device.getTransport().equalsIgnoreCase("TCP") ? tcpSipProvider.getNewCallId()
  207 + : udpSipProvider.getNewCallId();
  208 +
  209 + Request request = headerProvider.createMessageRequest(device, ptzXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null, callIdHeader);
  210 +
  211 + transmitRequest(device.getTransport(), request);
  212 + }
  213 +
  214 + /**
  215 + * 前端控制,包括PTZ指令、FI指令、预置位指令、巡航指令、扫描指令和辅助开关指令
  216 + *
  217 + * @param device 控制设备
  218 + * @param channelId 预览通道
  219 + * @param cmdCode 指令码
  220 + * @param parameter1 数据1
  221 + * @param parameter2 数据2
  222 + * @param combineCode2 组合码2
  223 + */
  224 + @Override
  225 + public void frontEndCmd(Device device, String channelId, int cmdCode, int parameter1, int parameter2, int combineCode2) throws SipException, InvalidArgumentException, ParseException {
  226 +
  227 + String cmdStr = frontEndCmdString(cmdCode, parameter1, parameter2, combineCode2);
  228 + StringBuffer ptzXml = new StringBuffer(200);
  229 + String charset = device.getCharset();
  230 + ptzXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
  231 + ptzXml.append("<Control>\r\n");
  232 + ptzXml.append("<CmdType>DeviceControl</CmdType>\r\n");
  233 + ptzXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");
  234 + ptzXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
  235 + ptzXml.append("<PTZCmd>" + cmdStr + "</PTZCmd>\r\n");
  236 + ptzXml.append("<Info>\r\n");
  237 + ptzXml.append("<ControlPriority>5</ControlPriority>\r\n");
  238 + ptzXml.append("</Info>\r\n");
  239 + ptzXml.append("</Control>\r\n");
  240 +
  241 +
  242 + CallIdHeader callIdHeader = device.getTransport().equalsIgnoreCase("TCP") ? tcpSipProvider.getNewCallId()
  243 + : udpSipProvider.getNewCallId();
  244 +
  245 + SIPRequest request = (SIPRequest) headerProvider.createMessageRequest(device, ptzXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null, callIdHeader);
  246 + transmitRequest(device.getTransport(), request);
  247 +
  248 + }
  249 +
  250 + /**
  251 + * 前端控制指令(用于转发上级指令)
  252 + *
  253 + * @param device 控制设备
  254 + * @param channelId 预览通道
  255 + * @param cmdString 前端控制指令串
  256 + */
  257 + @Override
  258 + public void fronEndCmd(Device device, String channelId, String cmdString, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException {
  259 +
  260 + StringBuffer ptzXml = new StringBuffer(200);
  261 + String charset = device.getCharset();
  262 + ptzXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
  263 + ptzXml.append("<Control>\r\n");
  264 + ptzXml.append("<CmdType>DeviceControl</CmdType>\r\n");
  265 + ptzXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");
  266 + ptzXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
  267 + ptzXml.append("<PTZCmd>" + cmdString + "</PTZCmd>\r\n");
  268 + ptzXml.append("<Info>\r\n");
  269 + ptzXml.append("<ControlPriority>5</ControlPriority>\r\n");
  270 + ptzXml.append("</Info>\r\n");
  271 + ptzXml.append("</Control>\r\n");
  272 +
  273 +
  274 + CallIdHeader callIdHeader = device.getTransport().equalsIgnoreCase("TCP") ? tcpSipProvider.getNewCallId()
  275 + : udpSipProvider.getNewCallId();
  276 +
  277 + Request request = headerProvider.createMessageRequest(device, ptzXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null, callIdHeader);
  278 + transmitRequest(device.getTransport(), request, errorEvent, okEvent);
  279 +
  280 + }
  281 +
  282 + /**
  283 + * 请求预览视频流
  284 + *
  285 + * @param device 视频设备
  286 + * @param channelId 预览通道
  287 + * @param event hook订阅
  288 + * @param errorEvent sip错误订阅
  289 + */
  290 + @Override
  291 + public void playStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId,
  292 + ZlmHttpHookSubscribe.Event event, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException {
  293 + String stream = ssrcInfo.getStream();
  294 +
  295 + if (device == null) {
  296 + return;
  297 + }
  298 +
  299 + logger.info("{} 分配的ZLM为: {} [{}:{}]", stream, mediaServerItem.getId(), mediaServerItem.getIp(), ssrcInfo.getPort());
  300 + HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", stream, true, "rtsp", mediaServerItem.getId());
  301 + subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, JSONObject json) -> {
  302 + if (event != null) {
  303 + event.response(mediaServerItemInUse, json);
  304 + subscribe.removeSubscribe(hookSubscribe);
  305 + }
  306 + });
  307 + //
  308 + StringBuffer content = new StringBuffer(200);
  309 + content.append("v=0\r\n");
  310 + content.append("o=" + channelId + " 0 0 IN IP4 " + mediaServerItem.getSdpIp() + "\r\n");
  311 + content.append("s=Play\r\n");
  312 + content.append("c=IN IP4 " + mediaServerItem.getSdpIp() + "\r\n");
  313 + content.append("t=0 0\r\n");
  314 +
  315 + if (userSetting.isSeniorSdp()) {
  316 + if ("TCP-PASSIVE".equalsIgnoreCase(device.getStreamMode())) {
  317 + content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 126 125 99 34 98 97\r\n");
  318 + } else if ("TCP-ACTIVE".equalsIgnoreCase(device.getStreamMode())) {
  319 + content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 126 125 99 34 98 97\r\n");
  320 + } else if ("UDP".equalsIgnoreCase(device.getStreamMode())) {
  321 + content.append("m=video " + ssrcInfo.getPort() + " RTP/AVP 96 126 125 99 34 98 97\r\n");
  322 + }
  323 + content.append("a=recvonly\r\n");
  324 + content.append("a=rtpmap:96 PS/90000\r\n");
  325 + content.append("a=fmtp:126 profile-level-id=42e01e\r\n");
  326 + content.append("a=rtpmap:126 H264/90000\r\n");
  327 + content.append("a=rtpmap:125 H264S/90000\r\n");
  328 + content.append("a=fmtp:125 profile-level-id=42e01e\r\n");
  329 + content.append("a=rtpmap:99 H265/90000\r\n");
  330 + content.append("a=rtpmap:98 H264/90000\r\n");
  331 + content.append("a=rtpmap:97 MPEG4/90000\r\n");
  332 + if ("TCP-PASSIVE".equalsIgnoreCase(device.getStreamMode())) { // tcp被动模式
  333 + content.append("a=setup:passive\r\n");
  334 + content.append("a=connection:new\r\n");
  335 + } else if ("TCP-ACTIVE".equalsIgnoreCase(device.getStreamMode())) { // tcp主动模式
  336 + content.append("a=setup:active\r\n");
  337 + content.append("a=connection:new\r\n");
  338 + }
  339 + } else {
  340 + if ("TCP-PASSIVE".equalsIgnoreCase(device.getStreamMode())) {
  341 + content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 97 98 99\r\n");
  342 + } else if ("TCP-ACTIVE".equalsIgnoreCase(device.getStreamMode())) {
  343 + content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 97 98 99\r\n");
  344 + } else if ("UDP".equalsIgnoreCase(device.getStreamMode())) {
  345 + content.append("m=video " + ssrcInfo.getPort() + " RTP/AVP 96 97 98 99\r\n");
  346 + }
  347 + content.append("a=recvonly\r\n");
  348 + content.append("a=rtpmap:96 PS/90000\r\n");
  349 + content.append("a=rtpmap:98 H264/90000\r\n");
  350 + content.append("a=rtpmap:97 MPEG4/90000\r\n");
  351 + content.append("a=rtpmap:99 H265/90000\r\n");
  352 + if ("TCP-PASSIVE".equalsIgnoreCase(device.getStreamMode())) { // tcp被动模式
  353 + content.append("a=setup:passive\r\n");
  354 + content.append("a=connection:new\r\n");
  355 + } else if ("TCP-ACTIVE".equalsIgnoreCase(device.getStreamMode())) { // tcp主动模式
  356 + content.append("a=setup:active\r\n");
  357 + content.append("a=connection:new\r\n");
  358 + }
  359 + }
  360 +
  361 + content.append("y=" + ssrcInfo.getSsrc() + "\r\n");//ssrc
  362 + // f字段:f= v/编码格式/分辨率/帧率/码率类型/码率大小a/编码格式/码率大小/采样率
423 363 // content.append("f=v/2/5/25/1/4000a/1/8/1" + "\r\n"); // 未发现支持此特性的设备
424 364  
425   - CallIdHeader callIdHeader = device.getTransport().equalsIgnoreCase("TCP") ? tcpSipProvider.getNewCallId()
426   - : udpSipProvider.getNewCallId();
427   -
428   - Request request = headerProvider.createInviteRequest(device, channelId, content.toString(), null, SipUtils.getNewFromTag(), null, ssrcInfo.getSsrc(), callIdHeader);
429   -
430   - transmitRequest(device, request, (e -> {
431   - streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream());
432   - mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
433   - errorEvent.response(e);
434   - }), e ->{
435   - // 这里为例避免一个通道的点播只有一个callID这个参数使用一个固定值
436   - streamSession.put(device.getDeviceId(), channelId ,"play", stream, ssrcInfo.getSsrc(), mediaServerItem.getId(), ((ResponseEvent)e.event).getClientTransaction(), VideoStreamSessionManager.SessionType.play);
437   - Dialog sipDialog = null;
438   - if (e.dialog == null) {
439   - SIPClientTransaction clientTransaction = (SIPClientTransaction)((ResponseEvent)e.event).getClientTransaction();
440   - sipDialog = new SIPDialog(clientTransaction, clientTransaction.getLastResponse());
441   - }else {
442   - sipDialog = e.dialog;
443   - }
444   - streamSession.put(device.getDeviceId(), channelId ,"play", sipDialog);
445   - okEvent.response(e);
446   - });
447   -
448   -
449   - } catch ( SipException | ParseException | InvalidArgumentException e) {
450   - e.printStackTrace();
451   - }
452   - }
453   -
454   - /**
455   - * 请求回放视频流
456   - *
457   - * @param device 视频设备
458   - * @param channelId 预览通道
459   - * @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss
460   - * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss
461   - */
462   - @Override
463   - public void playbackStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId,
464   - String startTime, String endTime, InviteStreamCallback inviteStreamCallback, InviteStreamCallback hookEvent,
465   - SipSubscribe.Event okEvent,SipSubscribe.Event errorEvent) {
466   - try {
467   -
468   - logger.info("{} 分配的ZLM为: {} [{}:{}]", ssrcInfo.getStream(), mediaServerItem.getId(), mediaServerItem.getIp(), ssrcInfo.getPort());
469   -
470   - StringBuffer content = new StringBuffer(200);
471   - content.append("v=0\r\n");
472   - content.append("o="+channelId+" 0 0 IN IP4 " + mediaServerItem.getSdpIp() + "\r\n");
473   - content.append("s=Playback\r\n");
474   - content.append("u="+channelId+":0\r\n");
475   - content.append("c=IN IP4 "+mediaServerItem.getSdpIp()+"\r\n");
476   - content.append("t="+DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(startTime)+" "
477   - +DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(endTime) +"\r\n");
478   -
479   - String streamMode = device.getStreamMode();
480   -
481   - if (userSetting.isSeniorSdp()) {
482   - if("TCP-PASSIVE".equalsIgnoreCase(streamMode)) {
483   - content.append("m=video "+ ssrcInfo.getPort() +" TCP/RTP/AVP 96 126 125 99 34 98 97\r\n");
484   - }else if ("TCP-ACTIVE".equalsIgnoreCase(streamMode)) {
485   - content.append("m=video "+ ssrcInfo.getPort() +" TCP/RTP/AVP 96 126 125 99 34 98 97\r\n");
486   - }else if("UDP".equalsIgnoreCase(streamMode)) {
487   - content.append("m=video "+ ssrcInfo.getPort() +" RTP/AVP 96 126 125 99 34 98 97\r\n");
488   - }
489   - content.append("a=recvonly\r\n");
490   - content.append("a=rtpmap:96 PS/90000\r\n");
491   - content.append("a=fmtp:126 profile-level-id=42e01e\r\n");
492   - content.append("a=rtpmap:126 H264/90000\r\n");
493   - content.append("a=rtpmap:125 H264S/90000\r\n");
494   - content.append("a=fmtp:125 profile-level-id=42e01e\r\n");
495   - content.append("a=rtpmap:99 H265/90000\r\n");
496   - content.append("a=rtpmap:98 H264/90000\r\n");
497   - content.append("a=rtpmap:97 MPEG4/90000\r\n");
498   - if("TCP-PASSIVE".equalsIgnoreCase(streamMode)){ // tcp被动模式
499   - content.append("a=setup:passive\r\n");
500   - content.append("a=connection:new\r\n");
501   - }else if ("TCP-ACTIVE".equalsIgnoreCase(streamMode)) { // tcp主动模式
502   - content.append("a=setup:active\r\n");
503   - content.append("a=connection:new\r\n");
504   - }
505   - }else {
506   - if("TCP-PASSIVE".equalsIgnoreCase(streamMode)) {
507   - content.append("m=video "+ ssrcInfo.getPort() +" TCP/RTP/AVP 96 97 98 99\r\n");
508   - }else if ("TCP-ACTIVE".equalsIgnoreCase(streamMode)) {
509   - content.append("m=video "+ ssrcInfo.getPort() +" TCP/RTP/AVP 96 97 98 99\r\n");
510   - }else if("UDP".equalsIgnoreCase(streamMode)) {
511   - content.append("m=video "+ ssrcInfo.getPort() +" RTP/AVP 96 97 98 99\r\n");
512   - }
513   - content.append("a=recvonly\r\n");
514   - content.append("a=rtpmap:96 PS/90000\r\n");
515   - content.append("a=rtpmap:97 MPEG4/90000\r\n");
516   - content.append("a=rtpmap:98 H264/90000\r\n");
517   - content.append("a=rtpmap:99 H265/90000\r\n");
518   - if("TCP-PASSIVE".equalsIgnoreCase(streamMode)){ // tcp被动模式
519   - content.append("a=setup:passive\r\n");
520   - content.append("a=connection:new\r\n");
521   - }else if ("TCP-ACTIVE".equalsIgnoreCase(streamMode)) { // tcp主动模式
522   - content.append("a=setup:active\r\n");
523   - content.append("a=connection:new\r\n");
524   - }
525   - }
526   -
527   - content.append("y=" + ssrcInfo.getSsrc() + "\r\n");//ssrc
528   -
529   - CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
530   - : udpSipProvider.getNewCallId();
531   - HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", ssrcInfo.getStream(), true, "rtsp", mediaServerItem.getId());
532   - // 添加订阅
533   - subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, JSONObject json)->{
534   - if (hookEvent != null) {
535   - InviteStreamInfo inviteStreamInfo = new InviteStreamInfo(mediaServerItemInUse, json, callIdHeader.getCallId(), "rtp", ssrcInfo.getStream());
536   - hookEvent.call(inviteStreamInfo);
537   - }
538   - subscribe.removeSubscribe(hookSubscribe);
539   - });
540   - Request request = headerProvider.createPlaybackInviteRequest(device, channelId, content.toString(), null, SipUtils.getNewFromTag(), null, callIdHeader, ssrcInfo.getSsrc());
541   -
542   - transmitRequest(device, request, errorEvent, event -> {
543   - ResponseEvent responseEvent = (ResponseEvent) event.event;
544   - streamSession.put(device.getDeviceId(), channelId, callIdHeader.getCallId(), ssrcInfo.getStream(), ssrcInfo.getSsrc(), mediaServerItem.getId(), responseEvent.getClientTransaction(), VideoStreamSessionManager.SessionType.playback);
545   - streamSession.put(device.getDeviceId(), channelId, callIdHeader.getCallId(), event.dialog);
546   - okEvent.response(event);
547   - });
548   - if (inviteStreamCallback != null) {
549   - inviteStreamCallback.call(new InviteStreamInfo(mediaServerItem, null, callIdHeader.getCallId(), "rtp", ssrcInfo.getStream()));
550   - }
551   - } catch ( SipException | ParseException | InvalidArgumentException e) {
552   - e.printStackTrace();
553   - }
554   - }
555   -
556   - /**
557   - * 请求历史媒体下载
558   - *
559   - * @param device 视频设备
560   - * @param channelId 预览通道
561   - * @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss
562   - * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss
563   - * @param downloadSpeed 下载倍速参数
564   - */
565   - @Override
566   - public void downloadStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId,
567   - String startTime, String endTime, int downloadSpeed, InviteStreamCallback inviteStreamCallback, InviteStreamCallback hookEvent,
568   - SipSubscribe.Event errorEvent) {
569   - try {
570   - logger.info("{} 分配的ZLM为: {} [{}:{}]", ssrcInfo.getStream(), mediaServerItem.getId(), mediaServerItem.getIp(), ssrcInfo.getPort());
571   -
572   - StringBuffer content = new StringBuffer(200);
573   - content.append("v=0\r\n");
574   - content.append("o="+channelId+" 0 0 IN IP4 " + mediaServerItem.getSdpIp() + "\r\n");
575   - content.append("s=Download\r\n");
576   - content.append("u="+channelId+":0\r\n");
577   - content.append("c=IN IP4 "+mediaServerItem.getSdpIp()+"\r\n");
578   - content.append("t="+DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(startTime)+" "
579   - +DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(endTime) +"\r\n");
580   -
581   - String streamMode = device.getStreamMode().toUpperCase();
582   -
583   - if (userSetting.isSeniorSdp()) {
584   - if("TCP-PASSIVE".equals(streamMode)) {
585   - content.append("m=video "+ ssrcInfo.getPort() +" TCP/RTP/AVP 96 126 125 99 34 98 97\r\n");
586   - }else if ("TCP-ACTIVE".equals(streamMode)) {
587   - content.append("m=video "+ ssrcInfo.getPort() +" TCP/RTP/AVP 96 126 125 99 34 98 97\r\n");
588   - }else if("UDP".equals(streamMode)) {
589   - content.append("m=video "+ ssrcInfo.getPort() +" RTP/AVP 96 126 125 99 34 98 97\r\n");
590   - }
591   - content.append("a=recvonly\r\n");
592   - content.append("a=rtpmap:96 PS/90000\r\n");
593   - content.append("a=fmtp:126 profile-level-id=42e01e\r\n");
594   - content.append("a=rtpmap:126 H264/90000\r\n");
595   - content.append("a=rtpmap:125 H264S/90000\r\n");
596   - content.append("a=fmtp:125 profile-level-id=42e01e\r\n");
597   - content.append("a=rtpmap:99 MP4V-ES/90000\r\n");
598   - content.append("a=fmtp:99 profile-level-id=3\r\n");
599   - content.append("a=rtpmap:98 H264/90000\r\n");
600   - content.append("a=rtpmap:97 MPEG4/90000\r\n");
601   - if("TCP-PASSIVE".equals(streamMode)){ // tcp被动模式
602   - content.append("a=setup:passive\r\n");
603   - content.append("a=connection:new\r\n");
604   - }else if ("TCP-ACTIVE".equals(streamMode)) { // tcp主动模式
605   - content.append("a=setup:active\r\n");
606   - content.append("a=connection:new\r\n");
607   - }
608   - }else {
609   - if("TCP-PASSIVE".equals(streamMode)) {
610   - content.append("m=video "+ ssrcInfo.getPort() +" TCP/RTP/AVP 96 97 98 99\r\n");
611   - }else if ("TCP-ACTIVE".equals(streamMode)) {
612   - content.append("m=video "+ ssrcInfo.getPort() +" TCP/RTP/AVP 96 97 98 99\r\n");
613   - }else if("UDP".equals(streamMode)) {
614   - content.append("m=video "+ ssrcInfo.getPort() +" RTP/AVP 96 97 98 99\r\n");
615   - }
616   - content.append("a=recvonly\r\n");
617   - content.append("a=rtpmap:96 PS/90000\r\n");
618   - content.append("a=rtpmap:97 MPEG4/90000\r\n");
619   - content.append("a=rtpmap:98 H264/90000\r\n");
620   - content.append("a=rtpmap:99 H265/90000\r\n");
621   - if("TCP-PASSIVE".equals(streamMode)){ // tcp被动模式
622   - content.append("a=setup:passive\r\n");
623   - content.append("a=connection:new\r\n");
624   - }else if ("TCP-ACTIVE".equals(streamMode)) { // tcp主动模式
625   - content.append("a=setup:active\r\n");
626   - content.append("a=connection:new\r\n");
627   - }
628   - }
629   - content.append("a=downloadspeed:" + downloadSpeed + "\r\n");
630   -
631   - content.append("y=" + ssrcInfo.getSsrc() + "\r\n");//ssrc
632   -
633   - CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
634   - : udpSipProvider.getNewCallId();
635   -
636   - HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", ssrcInfo.getStream(), true, null, mediaServerItem.getId());
637   - // 添加订阅
638   - subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, JSONObject json)->{
639   - hookEvent.call(new InviteStreamInfo(mediaServerItem, json, callIdHeader.getCallId(), "rtp", ssrcInfo.getStream()));
640   - subscribe.removeSubscribe(hookSubscribe);
641   - hookSubscribe.getContent().put("regist", false);
642   - hookSubscribe.getContent().put("schema", "rtsp");
643   - // 添加流注销的订阅,注销了后向设备发送bye
644   - subscribe.addSubscribe(hookSubscribe,
645   - (MediaServerItem mediaServerItemForEnd, JSONObject jsonForEnd)->{
646   - ClientTransaction transaction = streamSession.getTransaction(device.getDeviceId(), channelId, ssrcInfo.getStream(), callIdHeader.getCallId());
647   - if (transaction != null) {
648   - logger.info("[录像]下载结束, 发送BYE");
649   - streamByeCmd(device.getDeviceId(), channelId, ssrcInfo.getStream(), callIdHeader.getCallId());
650   - }
651   - });
652   - });
653   -
654   - Request request = headerProvider.createPlaybackInviteRequest(device, channelId, content.toString(), null, SipUtils.getNewFromTag(), null, callIdHeader, ssrcInfo.getSsrc());
655   - if (inviteStreamCallback != null) {
656   - inviteStreamCallback.call(new InviteStreamInfo(mediaServerItem, null, callIdHeader.getCallId(), "rtp", ssrcInfo.getStream()));
657   - }
658   - transmitRequest(device, request, errorEvent, okEvent->{
659   - ResponseEvent responseEvent = (ResponseEvent) okEvent.event;
660   - streamSession.put(device.getDeviceId(), channelId, callIdHeader.getCallId(), ssrcInfo.getStream(), ssrcInfo.getSsrc(), mediaServerItem.getId(), responseEvent.getClientTransaction(), VideoStreamSessionManager.SessionType.download);
661   - streamSession.put(device.getDeviceId(), channelId, callIdHeader.getCallId(), okEvent.dialog);
662   - });
663   -
664   -
665   - } catch ( SipException | ParseException | InvalidArgumentException e) {
666   - e.printStackTrace();
667   - }
668   - }
669   -
670   - /**
671   - * 视频流停止, 不使用回调
672   - */
673   - @Override
674   - public void streamByeCmd(String deviceId, String channelId, String stream, String callId) {
675   - streamByeCmd(deviceId, channelId, stream, callId, null);
676   - }
677   -
678   - /**
679   - * 视频流停止
680   - */
681   - @Override
682   - public void streamByeCmd(String deviceId, String channelId, String stream, String callId, SipSubscribe.Event okEvent) {
683   - try {
684   - SsrcTransaction ssrcTransaction = streamSession.getSsrcTransaction(deviceId, channelId, callId, stream);
685   - ClientTransaction transaction = streamSession.getTransaction(deviceId, channelId, stream, callId);
686   -
687   - if (transaction == null ) {
688   - logger.warn("[ {} -> {}]停止视频流的时候发现事务已丢失", deviceId, channelId);
689   - SipSubscribe.EventResult<Object> eventResult = new SipSubscribe.EventResult<>();
690   - if (okEvent != null) {
691   - okEvent.response(eventResult);
692   - }
693   - return;
694   - }
695   - SIPDialog dialog;
696   - if (callId != null) {
697   - dialog = streamSession.getDialogByCallId(ssrcTransaction.getDeviceId(), ssrcTransaction.getChannelId(), callId);
698   - }else {
699   - if (stream == null && ssrcTransaction == null && ssrcTransaction.getStream() == null) {
700   - return;
701   - }
702   - dialog = streamSession.getDialogByStream(ssrcTransaction.getDeviceId(), ssrcTransaction.getChannelId(), ssrcTransaction.getStream());
703   - }
704   - mediaServerService.releaseSsrc(ssrcTransaction.getMediaServerId(), ssrcTransaction.getSsrc());
705   - mediaServerService.closeRTPServer(ssrcTransaction.getMediaServerId(), ssrcTransaction.getStream());
706   - streamSession.remove(ssrcTransaction.getDeviceId(), ssrcTransaction.getChannelId(), ssrcTransaction.getStream());
707   -
708   - if (dialog == null) {
709   - logger.warn("[ {} -> {}]停止视频流的时候发现对话已丢失", ssrcTransaction.getDeviceId(), ssrcTransaction.getChannelId());
710   - return;
711   - }
712   - SipStack sipStack = udpSipProvider.getSipStack();
713   - SIPDialog sipDialog = ((SipStackImpl) sipStack).putDialog(dialog);
714   - if (dialog != sipDialog) {
715   - dialog = sipDialog;
716   - }else {
717   - dialog.setSipProvider(udpSipProvider);
718   - try {
719   - Field sipStackField = SIPDialog.class.getDeclaredField("sipStack");
720   - sipStackField.setAccessible(true);
721   - sipStackField.set(dialog, sipStack);
722   - Field eventListenersField = SIPDialog.class.getDeclaredField("eventListeners");
723   - eventListenersField.setAccessible(true);
724   - eventListenersField.set(dialog, new HashSet<>());
725   - } catch (NoSuchFieldException | IllegalAccessException e) {
726   - e.printStackTrace();
727   - }
728   - }
729   -
730   - Request byeRequest = dialog.createRequest(Request.BYE);
731   - SipURI byeURI = (SipURI) byeRequest.getRequestURI();
732   - SIPRequest request = (SIPRequest)transaction.getRequest();
733   - byeURI.setHost(request.getRemoteAddress().getHostAddress());
734   - byeURI.setPort(request.getRemotePort());
735   - byeURI.setUser(channelId);
736   - ViaHeader viaHeader = (ViaHeader) byeRequest.getHeader(ViaHeader.NAME);
737   - String protocol = viaHeader.getTransport().toUpperCase();
738   - viaHeader.setRPort();
739   - // 增加Contact header
740   - Address concatAddress = sipFactory.createAddressFactory().createAddress(sipFactory.createAddressFactory().createSipURI(sipConfig.getId(), sipConfig.getIp()+":"+sipConfig.getPort()));
741   - byeRequest.addHeader(sipFactory.createHeaderFactory().createContactHeader(concatAddress));
742   - UserAgentHeader userAgentHeader = SipUtils.createUserAgentHeader(sipFactory, gitUtil);
743   - byeRequest.addHeader(userAgentHeader);
744   - ClientTransaction clientTransaction = null;
745   - if("TCP".equals(protocol)) {
746   - clientTransaction = tcpSipProvider.getNewClientTransaction(byeRequest);
747   - } else if("UDP".equals(protocol)) {
748   - clientTransaction = udpSipProvider.getNewClientTransaction(byeRequest);
749   - }
750   -
751   - CallIdHeader callIdHeader = (CallIdHeader) byeRequest.getHeader(CallIdHeader.NAME);
752   - if (okEvent != null) {
753   - sipSubscribe.addOkSubscribe(callIdHeader.getCallId(), okEvent);
754   - }
755   - CSeqHeader cSeqHeader = (CSeqHeader)byeRequest.getHeader(CSeqHeader.NAME);
756   - cSeqHeader.setSeqNumber(redisCatchStorage.getCSEQ());
757   - dialog.sendRequest(clientTransaction);
758   -
759   - } catch (SipException | ParseException e) {
760   - e.printStackTrace();
761   - } catch (InvalidArgumentException e) {
762   - throw new RuntimeException(e);
763   - }
764   - }
765   -
766   - /**
767   - * 语音广播
768   - *
769   - * @param device 视频设备
770   - * @param channelId 预览通道
771   - */
772   - @Override
773   - public boolean audioBroadcastCmd(Device device, String channelId) {
774   - // 改为新的实现
775   - return false;
776   - }
777   -
778   - /**
779   - * 语音广播
780   - *
781   - * @param device 视频设备
782   - */
783   - @Override
784   - public boolean audioBroadcastCmd(Device device) {
785   - try {
786   - StringBuffer broadcastXml = new StringBuffer(200);
787   - String charset = device.getCharset();
788   - broadcastXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
789   - broadcastXml.append("<Notify>\r\n");
790   - broadcastXml.append("<CmdType>Broadcast</CmdType>\r\n");
791   - broadcastXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
792   - broadcastXml.append("<SourceID>" + sipConfig.getId() + "</SourceID>\r\n");
793   - broadcastXml.append("<TargetID>" + device.getDeviceId() + "</TargetID>\r\n");
794   - broadcastXml.append("</Notify>\r\n");
795   -
796   - CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
797   - : udpSipProvider.getNewCallId();
798   -
799   - Request request = headerProvider.createMessageRequest(device, broadcastXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null, callIdHeader);
800   - transmitRequest(device, request);
801   - return true;
802   - } catch (SipException | ParseException | InvalidArgumentException e) {
803   - e.printStackTrace();
804   - }
805   - return false;
806   - }
807   - @Override
808   - public void audioBroadcastCmd(Device device, SipSubscribe.Event errorEvent) {
809   - try {
810   - StringBuffer broadcastXml = new StringBuffer(200);
811   - String charset = device.getCharset();
812   - broadcastXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
813   - broadcastXml.append("<Notify>\r\n");
814   - broadcastXml.append("<CmdType>Broadcast</CmdType>\r\n");
815   - broadcastXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
816   - broadcastXml.append("<SourceID>" + sipConfig.getId() + "</SourceID>\r\n");
817   - broadcastXml.append("<TargetID>" + device.getDeviceId() + "</TargetID>\r\n");
818   - broadcastXml.append("</Notify>\r\n");
819   -
820   - CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
821   - : udpSipProvider.getNewCallId();
822   -
823   - Request request = headerProvider.createMessageRequest(device, broadcastXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null, callIdHeader);
824   - transmitRequest(device, request, errorEvent);
825   - } catch (SipException | ParseException | InvalidArgumentException e) {
826   - e.printStackTrace();
827   - }
828   - }
829   -
830   -
831   - /**
832   - * 音视频录像控制
833   - *
834   - * @param device 视频设备
835   - * @param channelId 预览通道
836   - * @param recordCmdStr 录像命令:Record / StopRecord
837   - */
838   - @Override
839   - public boolean recordCmd(Device device, String channelId, String recordCmdStr, SipSubscribe.Event errorEvent) {
840   - try {
841   - StringBuffer cmdXml = new StringBuffer(200);
842   - String charset = device.getCharset();
843   - cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
844   - cmdXml.append("<Control>\r\n");
845   - cmdXml.append("<CmdType>DeviceControl</CmdType>\r\n");
846   - cmdXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
847   - if (ObjectUtils.isEmpty(channelId)) {
848   - cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
849   - } else {
850   - cmdXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
851   - }
852   - cmdXml.append("<RecordCmd>" + recordCmdStr + "</RecordCmd>\r\n");
853   - cmdXml.append("</Control>\r\n");
854   -
855   - CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
856   - : udpSipProvider.getNewCallId();
857   -
858   - Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null, callIdHeader);
859   - transmitRequest(device, request, errorEvent);
860   - return true;
861   - } catch (SipException | ParseException | InvalidArgumentException e) {
862   - e.printStackTrace();
863   - return false;
864   - }
865   - }
866   -
867   - /**
868   - * 远程启动控制命令
869   - *
870   - * @param device 视频设备
871   - */
872   - @Override
873   - public boolean teleBootCmd(Device device) {
874   - try {
875   - StringBuffer cmdXml = new StringBuffer(200);
876   - String charset = device.getCharset();
877   - cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
878   - cmdXml.append("<Control>\r\n");
879   - cmdXml.append("<CmdType>DeviceControl</CmdType>\r\n");
880   - cmdXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
881   - cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
882   - cmdXml.append("<TeleBoot>Boot</TeleBoot>\r\n");
883   - cmdXml.append("</Control>\r\n");
884   -
885   - CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
886   - : udpSipProvider.getNewCallId();
887   -
888   - Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null, callIdHeader);
889   - transmitRequest(device, request);
890   - return true;
891   - } catch (SipException | ParseException | InvalidArgumentException e) {
892   - e.printStackTrace();
893   - return false;
894   - }
895   - }
896   -
897   - /**
898   - * 报警布防/撤防命令
899   - *
900   - * @param device 视频设备
901   - * @param guardCmdStr "SetGuard"/"ResetGuard"
902   - */
903   - @Override
904   - public boolean guardCmd(Device device, String guardCmdStr, SipSubscribe.Event errorEvent) {
905   - try {
906   - StringBuffer cmdXml = new StringBuffer(200);
907   - String charset = device.getCharset();
908   - cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
909   - cmdXml.append("<Control>\r\n");
910   - cmdXml.append("<CmdType>DeviceControl</CmdType>\r\n");
911   - cmdXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
912   - cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
913   - cmdXml.append("<GuardCmd>" + guardCmdStr + "</GuardCmd>\r\n");
914   - cmdXml.append("</Control>\r\n");
915   -
916   - CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
917   - : udpSipProvider.getNewCallId();
918   -
919   - Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null, callIdHeader);
920   - transmitRequest(device, request, errorEvent);
921   - return true;
922   - } catch (SipException | ParseException | InvalidArgumentException e) {
923   - e.printStackTrace();
924   - return false;
925   - }
926   - }
927   -
928   - /**
929   - * 报警复位命令
930   - *
931   - * @param device 视频设备
932   - */
933   - @Override
934   - public boolean alarmCmd(Device device, String alarmMethod, String alarmType, SipSubscribe.Event errorEvent) {
935   - try {
936   - StringBuffer cmdXml = new StringBuffer(200);
937   - String charset = device.getCharset();
938   - cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
939   - cmdXml.append("<Control>\r\n");
940   - cmdXml.append("<CmdType>DeviceControl</CmdType>\r\n");
941   - cmdXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
942   - cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
943   - cmdXml.append("<AlarmCmd>ResetAlarm</AlarmCmd>\r\n");
944   - if (!ObjectUtils.isEmpty(alarmMethod) || !ObjectUtils.isEmpty(alarmType)) {
945   - cmdXml.append("<Info>\r\n");
946   - }
947   - if (!ObjectUtils.isEmpty(alarmMethod)) {
948   - cmdXml.append("<AlarmMethod>" + alarmMethod + "</AlarmMethod>\r\n");
949   - }
950   - if (!ObjectUtils.isEmpty(alarmType)) {
951   - cmdXml.append("<AlarmType>" + alarmType + "</AlarmType>\r\n");
952   - }
953   - if (!ObjectUtils.isEmpty(alarmMethod) || !ObjectUtils.isEmpty(alarmType)) {
954   - cmdXml.append("</Info>\r\n");
955   - }
956   - cmdXml.append("</Control>\r\n");
957   -
958   - CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
959   - : udpSipProvider.getNewCallId();
960   -
961   - Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null, callIdHeader);
962   - transmitRequest(device, request, errorEvent);
963   - return true;
964   - } catch (SipException | ParseException | InvalidArgumentException e) {
965   - e.printStackTrace();
966   - return false;
967   - }
968   - }
969   -
970   - /**
971   - * 强制关键帧命令,设备收到此命令应立刻发送一个IDR帧
972   - *
973   - * @param device 视频设备
974   - * @param channelId 预览通道
975   - */
976   - @Override
977   - public boolean iFrameCmd(Device device, String channelId) {
978   - try {
979   - StringBuffer cmdXml = new StringBuffer(200);
980   - String charset = device.getCharset();
981   - cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
982   - cmdXml.append("<Control>\r\n");
983   - cmdXml.append("<CmdType>DeviceControl</CmdType>\r\n");
984   - cmdXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
985   - if (ObjectUtils.isEmpty(channelId)) {
986   - cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
987   - } else {
988   - cmdXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
989   - }
990   - cmdXml.append("<IFameCmd>Send</IFameCmd>\r\n");
991   - cmdXml.append("</Control>\r\n");
992   -
993   - CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
994   - : udpSipProvider.getNewCallId();
995   -
996   - Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null, callIdHeader);
997   - transmitRequest(device, request);
998   - return true;
999   - } catch (SipException | ParseException | InvalidArgumentException e) {
1000   - e.printStackTrace();
1001   - return false;
1002   - }
1003   - }
1004   -
1005   - /**
1006   - * 看守位控制命令
1007   - *
1008   - * @param device 视频设备
1009   - * @param enabled 看守位使能:1 = 开启,0 = 关闭
1010   - * @param resetTime 自动归位时间间隔,开启看守位时使用,单位:秒(s)
1011   - * @param presetIndex 调用预置位编号,开启看守位时使用,取值范围0~255
1012   - */
1013   - @Override
1014   - public boolean homePositionCmd(Device device, String channelId, String enabled, String resetTime, String presetIndex, SipSubscribe.Event errorEvent) {
1015   - try {
1016   - StringBuffer cmdXml = new StringBuffer(200);
1017   - String charset = device.getCharset();
1018   - cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
1019   - cmdXml.append("<Control>\r\n");
1020   - cmdXml.append("<CmdType>DeviceControl</CmdType>\r\n");
1021   - cmdXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
1022   - if (ObjectUtils.isEmpty(channelId)) {
1023   - cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
1024   - } else {
1025   - cmdXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
1026   - }
1027   - cmdXml.append("<HomePosition>\r\n");
1028   - if (NumericUtil.isInteger(enabled) && (!enabled.equals("0"))) {
1029   - cmdXml.append("<Enabled>1</Enabled>\r\n");
1030   - if (NumericUtil.isInteger(resetTime)) {
1031   - cmdXml.append("<ResetTime>" + resetTime + "</ResetTime>\r\n");
1032   - } else {
1033   - cmdXml.append("<ResetTime>0</ResetTime>\r\n");
1034   - }
1035   - if (NumericUtil.isInteger(presetIndex)) {
1036   - cmdXml.append("<PresetIndex>" + presetIndex + "</PresetIndex>\r\n");
1037   - } else {
1038   - cmdXml.append("<PresetIndex>0</PresetIndex>\r\n");
1039   - }
1040   - } else {
1041   - cmdXml.append("<Enabled>0</Enabled>\r\n");
1042   - }
1043   - cmdXml.append("</HomePosition>\r\n");
1044   - cmdXml.append("</Control>\r\n");
1045   -
1046   - CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
1047   - : udpSipProvider.getNewCallId();
1048   -
1049   - Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null, callIdHeader);
1050   - transmitRequest(device, request, errorEvent);
1051   - return true;
1052   - } catch (SipException | ParseException | InvalidArgumentException e) {
1053   - e.printStackTrace();
1054   - return false;
1055   - }
1056   - }
1057   -
1058   - /**
1059   - * 设备配置命令
1060   - *
1061   - * @param device 视频设备
1062   - */
1063   - @Override
1064   - public boolean deviceConfigCmd(Device device) {
1065   - // TODO Auto-generated method stub
1066   - return false;
1067   - }
1068   -
1069   - /**
1070   - * 设备配置命令:basicParam
1071   - *
1072   - * @param device 视频设备
1073   - * @param channelId 通道编码(可选)
1074   - * @param name 设备/通道名称(可选)
1075   - * @param expiration 注册过期时间(可选)
1076   - * @param heartBeatInterval 心跳间隔时间(可选)
1077   - * @param heartBeatCount 心跳超时次数(可选)
1078   - */
1079   - @Override
1080   - public boolean deviceBasicConfigCmd(Device device, String channelId, String name, String expiration,
1081   - String heartBeatInterval, String heartBeatCount, SipSubscribe.Event errorEvent) {
1082   - try {
1083   - StringBuffer cmdXml = new StringBuffer(200);
1084   - String charset = device.getCharset();
1085   - cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
1086   - cmdXml.append("<Control>\r\n");
1087   - cmdXml.append("<CmdType>DeviceConfig</CmdType>\r\n");
1088   - cmdXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
1089   - if (ObjectUtils.isEmpty(channelId)) {
1090   - cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
1091   - } else {
1092   - cmdXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
1093   - }
1094   - cmdXml.append("<BasicParam>\r\n");
1095   - if (!ObjectUtils.isEmpty(name)) {
1096   - cmdXml.append("<Name>" + name + "</Name>\r\n");
1097   - }
1098   - if (NumericUtil.isInteger(expiration)) {
1099   - if (Integer.valueOf(expiration) > 0) {
1100   - cmdXml.append("<Expiration>" + expiration + "</Expiration>\r\n");
1101   - }
1102   - }
1103   - if (NumericUtil.isInteger(heartBeatInterval)) {
1104   - if (Integer.valueOf(heartBeatInterval) > 0) {
1105   - cmdXml.append("<HeartBeatInterval>" + heartBeatInterval + "</HeartBeatInterval>\r\n");
1106   - }
1107   - }
1108   - if (NumericUtil.isInteger(heartBeatCount)) {
1109   - if (Integer.valueOf(heartBeatCount) > 0) {
1110   - cmdXml.append("<HeartBeatCount>" + heartBeatCount + "</HeartBeatCount>\r\n");
1111   - }
1112   - }
1113   - cmdXml.append("</BasicParam>\r\n");
1114   - cmdXml.append("</Control>\r\n");
1115   -
1116   - CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
1117   - : udpSipProvider.getNewCallId();
1118   -
1119   - Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null, callIdHeader);
1120   - transmitRequest(device, request, errorEvent);
1121   - return true;
1122   - } catch (SipException | ParseException | InvalidArgumentException e) {
1123   - e.printStackTrace();
1124   - return false;
1125   - }
1126   - }
1127   -
1128   - /**
1129   - * 查询设备状态
1130   - *
1131   - * @param device 视频设备
1132   - */
1133   - @Override
1134   - public boolean deviceStatusQuery(Device device, SipSubscribe.Event errorEvent) {
1135   - try {
1136   - String charset = device.getCharset();
1137   - StringBuffer catalogXml = new StringBuffer(200);
1138   - catalogXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
1139   - catalogXml.append("<Query>\r\n");
1140   - catalogXml.append("<CmdType>DeviceStatus</CmdType>\r\n");
1141   - catalogXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
1142   - catalogXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
1143   - catalogXml.append("</Query>\r\n");
1144   -
1145   - CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
1146   - : udpSipProvider.getNewCallId();
1147   -
1148   - Request request = headerProvider.createMessageRequest(device, catalogXml.toString(), null, SipUtils.getNewFromTag(), null, callIdHeader);
1149   -
1150   - transmitRequest(device, request, errorEvent);
1151   - return true;
1152   -
1153   - } catch (SipException | ParseException | InvalidArgumentException e) {
1154   - e.printStackTrace();
1155   - return false;
1156   - }
1157   - }
1158   -
1159   - /**
1160   - * 查询设备信息
1161   - *
1162   - * @param device 视频设备
1163   - */
1164   - @Override
1165   - public boolean deviceInfoQuery(Device device) {
1166   - try {
1167   - StringBuffer catalogXml = new StringBuffer(200);
1168   - String charset = device.getCharset();
1169   - catalogXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
1170   - catalogXml.append("<Query>\r\n");
1171   - catalogXml.append("<CmdType>DeviceInfo</CmdType>\r\n");
1172   - catalogXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
1173   - catalogXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
1174   - catalogXml.append("</Query>\r\n");
1175   -
1176   - CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
1177   - : udpSipProvider.getNewCallId();
1178   -
1179   - Request request = headerProvider.createMessageRequest(device, catalogXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null, callIdHeader);
1180   -
1181   - transmitRequest(device, request);
1182   -
1183   - } catch (SipException | ParseException | InvalidArgumentException e) {
1184   - e.printStackTrace();
1185   - return false;
1186   - }
1187   - return true;
1188   - }
1189   -
1190   - /**
1191   - * 查询目录列表
1192   - *
1193   - * @param device 视频设备
1194   - */
1195   - @Override
1196   - public boolean catalogQuery(Device device, int sn, SipSubscribe.Event errorEvent) {
1197   - try {
1198   - StringBuffer catalogXml = new StringBuffer(200);
1199   - String charset = device.getCharset();
1200   - catalogXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
1201   - catalogXml.append("<Query>\r\n");
1202   - catalogXml.append(" <CmdType>Catalog</CmdType>\r\n");
1203   - catalogXml.append(" <SN>" + sn + "</SN>\r\n");
1204   - catalogXml.append(" <DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
1205   - catalogXml.append("</Query>\r\n");
1206   -
1207   - CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
1208   - : udpSipProvider.getNewCallId();
1209   -
1210   - Request request = headerProvider.createMessageRequest(device, catalogXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null, callIdHeader);
1211   -
1212   - transmitRequest(device, request, errorEvent);
1213   - } catch (SipException | ParseException | InvalidArgumentException e) {
1214   - e.printStackTrace();
1215   - return false;
1216   - }
1217   - return true;
1218   - }
1219   -
1220   - /**
1221   - * 查询录像信息
1222   - *
1223   - * @param device 视频设备
1224   - * @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss
1225   - * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss
1226   - */
1227   - @Override
1228   - public boolean recordInfoQuery(Device device, String channelId, String startTime, String endTime, int sn, Integer secrecy, String type, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) {
1229   - if (secrecy == null) {
1230   - secrecy = 0;
1231   - }
1232   - if (type == null) {
1233   - type = "all";
1234   - }
1235   - try {
1236   - StringBuffer recordInfoXml = new StringBuffer(200);
1237   - String charset = device.getCharset();
1238   - recordInfoXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
1239   - recordInfoXml.append("<Query>\r\n");
1240   - recordInfoXml.append("<CmdType>RecordInfo</CmdType>\r\n");
1241   - recordInfoXml.append("<SN>" + sn + "</SN>\r\n");
1242   - recordInfoXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
1243   - if (startTime != null) {
1244   - recordInfoXml.append("<StartTime>" + DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(startTime) + "</StartTime>\r\n");
1245   - }
1246   - if (endTime != null) {
1247   - recordInfoXml.append("<EndTime>" + DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(endTime) + "</EndTime>\r\n");
1248   - }
1249   - if (secrecy != null) {
1250   - recordInfoXml.append("<Secrecy> "+ secrecy + " </Secrecy>\r\n");
1251   - }
1252   - if (type != null) {
1253   - // 大华NVR要求必须增加一个值为all的文本元素节点Type
1254   - recordInfoXml.append("<Type>" + type+"</Type>\r\n");
1255   - }
1256   - recordInfoXml.append("</Query>\r\n");
1257   -
1258   - CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
1259   - : udpSipProvider.getNewCallId();
1260   -
1261   - Request request = headerProvider.createMessageRequest(device, recordInfoXml.toString(),
1262   - SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null, callIdHeader);
1263   -
1264   - transmitRequest(device, request, errorEvent, okEvent);
1265   - } catch (SipException | ParseException | InvalidArgumentException e) {
1266   - e.printStackTrace();
1267   - return false;
1268   - }
1269   - return true;
1270   - }
1271   -
1272   - /**
1273   - * 查询报警信息
1274   - *
1275   - * @param device 视频设备
1276   - * @param startPriority 报警起始级别(可选)
1277   - * @param endPriority 报警终止级别(可选)
1278   - * @param alarmMethod 报警方式条件(可选)
1279   - * @param alarmType 报警类型
1280   - * @param startTime 报警发生起始时间(可选)
1281   - * @param endTime 报警发生终止时间(可选)
1282   - * @return true = 命令发送成功
1283   - */
1284   - @Override
1285   - public boolean alarmInfoQuery(Device device, String startPriority, String endPriority, String alarmMethod, String alarmType,
1286   - String startTime, String endTime, SipSubscribe.Event errorEvent) {
1287   - try {
1288   - StringBuffer cmdXml = new StringBuffer(200);
1289   - String charset = device.getCharset();
1290   - cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
1291   - cmdXml.append("<Query>\r\n");
1292   - cmdXml.append("<CmdType>Alarm</CmdType>\r\n");
1293   - cmdXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
1294   - cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
1295   - if (!ObjectUtils.isEmpty(startPriority)) {
1296   - cmdXml.append("<StartAlarmPriority>" + startPriority + "</StartAlarmPriority>\r\n");
1297   - }
1298   - if (!ObjectUtils.isEmpty(endPriority)) {
1299   - cmdXml.append("<EndAlarmPriority>" + endPriority + "</EndAlarmPriority>\r\n");
1300   - }
1301   - if (!ObjectUtils.isEmpty(alarmMethod)) {
1302   - cmdXml.append("<AlarmMethod>" + alarmMethod + "</AlarmMethod>\r\n");
1303   - }
1304   - if (!ObjectUtils.isEmpty(alarmType)) {
1305   - cmdXml.append("<AlarmType>" + alarmType + "</AlarmType>\r\n");
1306   - }
1307   - if (!ObjectUtils.isEmpty(startTime)) {
1308   - cmdXml.append("<StartAlarmTime>" + startTime + "</StartAlarmTime>\r\n");
1309   - }
1310   - if (!ObjectUtils.isEmpty(endTime)) {
1311   - cmdXml.append("<EndAlarmTime>" + endTime + "</EndAlarmTime>\r\n");
1312   - }
1313   - cmdXml.append("</Query>\r\n");
1314   -
1315   - CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
1316   - : udpSipProvider.getNewCallId();
1317   -
1318   - Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null, callIdHeader);
1319   - transmitRequest(device, request, errorEvent);
1320   - return true;
1321   - } catch (SipException | ParseException | InvalidArgumentException e) {
1322   - e.printStackTrace();
1323   - return false;
1324   - }
1325   - }
1326   -
1327   - /**
1328   - * 查询设备配置
1329   - *
1330   - * @param device 视频设备
1331   - * @param channelId 通道编码(可选)
1332   - * @param configType 配置类型:
1333   - */
1334   - @Override
1335   - public boolean deviceConfigQuery(Device device, String channelId, String configType, SipSubscribe.Event errorEvent) {
1336   - try {
1337   - StringBuffer cmdXml = new StringBuffer(200);
1338   - String charset = device.getCharset();
1339   - cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
1340   - cmdXml.append("<Query>\r\n");
1341   - cmdXml.append("<CmdType>ConfigDownload</CmdType>\r\n");
1342   - cmdXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
1343   - if (ObjectUtils.isEmpty(channelId)) {
1344   - cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
1345   - } else {
1346   - cmdXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
1347   - }
1348   - cmdXml.append("<ConfigType>" + configType + "</ConfigType>\r\n");
1349   - cmdXml.append("</Query>\r\n");
1350   -
1351   - CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
1352   - : udpSipProvider.getNewCallId();
1353   -
1354   - Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null, callIdHeader);
1355   - transmitRequest(device, request, errorEvent);
1356   - return true;
1357   - } catch (SipException | ParseException | InvalidArgumentException e) {
1358   - e.printStackTrace();
1359   - return false;
1360   - }
1361   - }
1362   -
1363   - /**
1364   - * 查询设备预置位置
1365   - *
1366   - * @param device 视频设备
1367   - */
1368   - @Override
1369   - public boolean presetQuery(Device device, String channelId, SipSubscribe.Event errorEvent) {
1370   - try {
1371   - StringBuffer cmdXml = new StringBuffer(200);
1372   - String charset = device.getCharset();
1373   - cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
1374   - cmdXml.append("<Query>\r\n");
1375   - cmdXml.append("<CmdType>PresetQuery</CmdType>\r\n");
1376   - cmdXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
1377   - if (ObjectUtils.isEmpty(channelId)) {
1378   - cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
1379   - } else {
1380   - cmdXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
1381   - }
1382   - cmdXml.append("</Query>\r\n");
1383   -
1384   - CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
1385   - : udpSipProvider.getNewCallId();
1386   -
1387   - Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null, callIdHeader);
1388   - transmitRequest(device, request, errorEvent);
1389   - return true;
1390   - } catch (SipException | ParseException | InvalidArgumentException e) {
1391   - e.printStackTrace();
1392   - return false;
1393   - }
1394   - }
1395   -
1396   - /**
1397   - * 查询移动设备位置数据
1398   - *
1399   - * @param device 视频设备
1400   - */
1401   - @Override
1402   - public boolean mobilePostitionQuery(Device device, SipSubscribe.Event errorEvent) {
1403   - try {
1404   - StringBuffer mobilePostitionXml = new StringBuffer(200);
1405   - String charset = device.getCharset();
1406   - mobilePostitionXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
1407   - mobilePostitionXml.append("<Query>\r\n");
1408   - mobilePostitionXml.append("<CmdType>MobilePosition</CmdType>\r\n");
1409   - mobilePostitionXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
1410   - mobilePostitionXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
1411   - mobilePostitionXml.append("<Interval>60</Interval>\r\n");
1412   - mobilePostitionXml.append("</Query>\r\n");
1413   -
1414   - CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
1415   - : udpSipProvider.getNewCallId();
1416   -
1417   - Request request = headerProvider.createMessageRequest(device, mobilePostitionXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null, callIdHeader);
1418   -
1419   - transmitRequest(device, request, errorEvent);
1420   -
1421   - } catch (SipException | ParseException | InvalidArgumentException e) {
1422   - e.printStackTrace();
1423   - return false;
1424   - }
1425   - return true;
1426   - }
1427   -
1428   - /**
1429   - * 订阅、取消订阅移动位置
1430   - *
1431   - * @param device 视频设备
1432   - * @return true = 命令发送成功
1433   - */
1434   - @Override
1435   - public SIPRequest mobilePositionSubscribe(Device device, SIPRequest requestOld, SipSubscribe.Event okEvent ,SipSubscribe.Event errorEvent) {
1436   - try {
1437   - StringBuffer subscribePostitionXml = new StringBuffer(200);
1438   - String charset = device.getCharset();
1439   - subscribePostitionXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
1440   - subscribePostitionXml.append("<Query>\r\n");
1441   - subscribePostitionXml.append("<CmdType>MobilePosition</CmdType>\r\n");
1442   - subscribePostitionXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
1443   - subscribePostitionXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
1444   - if (device.getSubscribeCycleForMobilePosition() > 0) {
1445   - subscribePostitionXml.append("<Interval>" + device.getMobilePositionSubmissionInterval() + "</Interval>\r\n");
1446   - }
1447   - subscribePostitionXml.append("</Query>\r\n");
1448   -
1449   - CallIdHeader callIdHeader;
1450   -
1451   - if (requestOld != null) {
1452   - callIdHeader = sipFactory.createHeaderFactory().createCallIdHeader(requestOld.getCallIdHeader().getCallId());
1453   - }else {
1454   - callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
1455   - : udpSipProvider.getNewCallId();
1456   - }
1457   - SIPRequest request = (SIPRequest)headerProvider.createSubscribeRequest(device, subscribePostitionXml.toString(), requestOld, device.getSubscribeCycleForMobilePosition(), "presence" ,callIdHeader); //Position;id=" + tm.substring(tm.length() - 4));
1458   -
1459   - transmitRequest(device, request, errorEvent, okEvent);
1460   -
1461   - return request;
1462   -
1463   - } catch ( NumberFormatException | ParseException | InvalidArgumentException | SipException e) {
1464   - e.printStackTrace();
1465   - return null;
1466   - }
1467   - }
1468   -
1469   - /**
1470   - * 订阅、取消订阅报警信息
1471   - *
1472   - * @param device 视频设备
1473   - * @param expires 订阅过期时间(0 = 取消订阅)
1474   - * @param startPriority 报警起始级别(可选)
1475   - * @param endPriority 报警终止级别(可选)
1476   - * @param alarmMethod 报警方式条件(可选)
1477   - * @param alarmType 报警类型
1478   - * @param startTime 报警发生起始时间(可选)
1479   - * @param endTime 报警发生终止时间(可选)
1480   - * @return true = 命令发送成功
1481   - */
1482   - @Override
1483   - public boolean alarmSubscribe(Device device, int expires, String startPriority, String endPriority, String alarmMethod, String alarmType, String startTime, String endTime) {
1484   - try {
1485   - StringBuffer cmdXml = new StringBuffer(200);
1486   - String charset = device.getCharset();
1487   - cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
1488   - cmdXml.append("<Query>\r\n");
1489   - cmdXml.append("<CmdType>Alarm</CmdType>\r\n");
1490   - cmdXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
1491   - cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
1492   - if (!ObjectUtils.isEmpty(startPriority)) {
1493   - cmdXml.append("<StartAlarmPriority>" + startPriority + "</StartAlarmPriority>\r\n");
1494   - }
1495   - if (!ObjectUtils.isEmpty(endPriority)) {
1496   - cmdXml.append("<EndAlarmPriority>" + endPriority + "</EndAlarmPriority>\r\n");
1497   - }
1498   - if (!ObjectUtils.isEmpty(alarmMethod)) {
1499   - cmdXml.append("<AlarmMethod>" + alarmMethod + "</AlarmMethod>\r\n");
1500   - }
1501   - if (!ObjectUtils.isEmpty(alarmType)) {
1502   - cmdXml.append("<AlarmType>" + alarmType + "</AlarmType>\r\n");
1503   - }
1504   - if (!ObjectUtils.isEmpty(startTime)) {
1505   - cmdXml.append("<StartAlarmTime>" + startTime + "</StartAlarmTime>\r\n");
1506   - }
1507   - if (!ObjectUtils.isEmpty(endTime)) {
1508   - cmdXml.append("<EndAlarmTime>" + endTime + "</EndAlarmTime>\r\n");
1509   - }
1510   - cmdXml.append("</Query>\r\n");
1511   -
1512   - CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
1513   - : udpSipProvider.getNewCallId();
1514   -
1515   - Request request = headerProvider.createSubscribeRequest(device, cmdXml.toString(), null, expires, "presence" , callIdHeader);
1516   - transmitRequest(device, request);
1517   -
1518   - return true;
1519   -
1520   - } catch ( NumberFormatException | ParseException | InvalidArgumentException | SipException e) {
1521   - e.printStackTrace();
1522   - return false;
1523   - }
1524   - }
1525   -
1526   - @Override
1527   - public SIPRequest catalogSubscribe(Device device, SIPRequest requestOld, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) {
1528   - try {
1529   - StringBuffer cmdXml = new StringBuffer(200);
1530   - String charset = device.getCharset();
1531   - cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
1532   - cmdXml.append("<Query>\r\n");
1533   - cmdXml.append("<CmdType>Catalog</CmdType>\r\n");
1534   - cmdXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
1535   - cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
1536   - cmdXml.append("</Query>\r\n");
1537   -
1538   - CallIdHeader callIdHeader ;
1539   -
1540   - if (requestOld != null) {
1541   - callIdHeader = sipFactory.createHeaderFactory().createCallIdHeader(requestOld.getCallIdHeader().getCallId());
1542   - }else {
1543   - callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
1544   - : udpSipProvider.getNewCallId();
1545   - }
1546   -
1547   - // 有效时间默认为60秒以上
1548   - SIPRequest request = (SIPRequest)headerProvider.createSubscribeRequest(device, cmdXml.toString(), requestOld, device.getSubscribeCycleForCatalog(), "Catalog" ,
1549   - callIdHeader);
1550   - transmitRequest(device, request, errorEvent, okEvent);
1551   - return request;
1552   -
1553   - } catch ( NumberFormatException | ParseException | InvalidArgumentException | SipException e) {
1554   - e.printStackTrace();
1555   - return null;
1556   - }
1557   - }
1558   -
1559   - @Override
1560   - public boolean dragZoomCmd(Device device, String channelId, String cmdString) {
1561   - try {
1562   - StringBuffer dragXml = new StringBuffer(200);
1563   - String charset = device.getCharset();
1564   - dragXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
1565   - dragXml.append("<Control>\r\n");
1566   - dragXml.append("<CmdType>DeviceControl</CmdType>\r\n");
1567   - dragXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");
1568   - if (ObjectUtils.isEmpty(channelId)) {
1569   - dragXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
1570   - } else {
1571   - dragXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
1572   - }
1573   - dragXml.append(cmdString);
1574   - dragXml.append("</Control>\r\n");
1575   - CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
1576   - : udpSipProvider.getNewCallId();
1577   - Request request = headerProvider.createMessageRequest(device, dragXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null, callIdHeader);
1578   - logger.debug("拉框信令: " + request.toString());
1579   - transmitRequest(device, request);
1580   - return true;
1581   - } catch (SipException | ParseException | InvalidArgumentException e) {
1582   - e.printStackTrace();
1583   - }
1584   - return false;
1585   - }
1586   -
1587   -
1588   - private ClientTransaction transmitRequest(Device device, Request request) throws SipException {
1589   - return transmitRequest(device, request, null, null);
1590   - }
1591   -
1592   - private ClientTransaction transmitRequest(Device device, Request request, SipSubscribe.Event errorEvent) throws SipException {
1593   - return transmitRequest(device, request, errorEvent, null);
1594   - }
1595   -
1596   - private ClientTransaction transmitRequest(Device device, Request request, SipSubscribe.Event errorEvent , SipSubscribe.Event okEvent) throws SipException {
1597   - ClientTransaction clientTransaction = null;
1598   - if("TCP".equals(device.getTransport())) {
1599   - clientTransaction = tcpSipProvider.getNewClientTransaction(request);
1600   - } else if("UDP".equals(device.getTransport())) {
1601   - clientTransaction = udpSipProvider.getNewClientTransaction(request);
1602   - }
1603   - if (request.getHeader(UserAgentHeader.NAME) == null) {
1604   - try {
1605   - request.addHeader(SipUtils.createUserAgentHeader(sipFactory, gitUtil));
1606   - } catch (ParseException e) {
1607   - logger.error("添加UserAgentHeader失败", e);
1608   - }
1609   - }
1610   - CallIdHeader callIdHeader = (CallIdHeader)request.getHeader(CallIdHeader.NAME);
1611   - // 添加错误订阅
1612   - if (errorEvent != null) {
1613   - sipSubscribe.addErrorSubscribe(callIdHeader.getCallId(), (eventResult -> {
1614   - errorEvent.response(eventResult);
1615   - sipSubscribe.removeErrorSubscribe(eventResult.callId);
1616   - sipSubscribe.removeOkSubscribe(eventResult.callId);
1617   - }));
1618   - }
1619   - // 添加订阅
1620   - if (okEvent != null) {
1621   - sipSubscribe.addOkSubscribe(callIdHeader.getCallId(), eventResult ->{
1622   - okEvent.response(eventResult);
1623   - sipSubscribe.removeOkSubscribe(eventResult.callId);
1624   - sipSubscribe.removeErrorSubscribe(eventResult.callId);
1625   - });
1626   - }
1627   -
1628   - clientTransaction.sendRequest();
1629   - return clientTransaction;
1630   - }
1631   -
1632   - /**
1633   - * 回放暂停
1634   - */
1635   - @Override
1636   - public void playPauseCmd(Device device, StreamInfo streamInfo) {
1637   - try {
1638   - StringBuffer content = new StringBuffer(200);
1639   - content.append("PAUSE RTSP/1.0\r\n");
1640   - content.append("CSeq: " + getInfoCseq() + "\r\n");
1641   - content.append("PauseTime: now\r\n");
1642   - Request request = headerProvider.createInfoRequest(device, streamInfo, content.toString());
1643   - if (request == null) {
1644   - return;
1645   - }
1646   - logger.info(request.toString());
1647   - ClientTransaction clientTransaction = null;
1648   - if ("TCP".equals(device.getTransport())) {
1649   - clientTransaction = tcpSipProvider.getNewClientTransaction(request);
1650   - } else if ("UDP".equals(device.getTransport())) {
1651   - clientTransaction = udpSipProvider.getNewClientTransaction(request);
1652   - }
1653   - if (clientTransaction != null) {
1654   - clientTransaction.sendRequest();
1655   - }
1656   -
1657   - } catch (SipException | ParseException | InvalidArgumentException e) {
1658   - e.printStackTrace();
1659   - }
1660   - }
1661   -
1662   - /**
1663   - * 回放恢复
1664   - */
1665   - @Override
1666   - public void playResumeCmd(Device device, StreamInfo streamInfo) {
1667   - try {
1668   - StringBuffer content = new StringBuffer(200);
1669   - content.append("PLAY RTSP/1.0\r\n");
1670   - content.append("CSeq: " + getInfoCseq() + "\r\n");
1671   - content.append("Range: npt=now-\r\n");
1672   - Request request = headerProvider.createInfoRequest(device, streamInfo, content.toString());
1673   - if (request == null) {
1674   - return;
1675   - }
1676   - logger.info(request.toString());
1677   - ClientTransaction clientTransaction = null;
1678   - if ("TCP".equals(device.getTransport())) {
1679   - clientTransaction = tcpSipProvider.getNewClientTransaction(request);
1680   - } else if ("UDP".equals(device.getTransport())) {
1681   - clientTransaction = udpSipProvider.getNewClientTransaction(request);
1682   - }
1683   -
1684   - clientTransaction.sendRequest();
1685   -
1686   - } catch (SipException | ParseException | InvalidArgumentException e) {
1687   - e.printStackTrace();
1688   - }
1689   - }
1690   -
1691   - /**
1692   - * 回放拖动播放
1693   - */
1694   - @Override
1695   - public void playSeekCmd(Device device, StreamInfo streamInfo, long seekTime) {
1696   - try {
1697   - StringBuffer content = new StringBuffer(200);
1698   - content.append("PLAY RTSP/1.0\r\n");
1699   - content.append("CSeq: " + getInfoCseq() + "\r\n");
1700   - content.append("Range: npt=" + Math.abs(seekTime) + "-\r\n");
1701   -
1702   - Request request = headerProvider.createInfoRequest(device, streamInfo, content.toString());
1703   - if (request == null) {
1704   - return;
1705   - }
1706   - logger.info(request.toString());
1707   - ClientTransaction clientTransaction = null;
1708   - if ("TCP".equals(device.getTransport())) {
1709   - clientTransaction = tcpSipProvider.getNewClientTransaction(request);
1710   - } else if ("UDP".equals(device.getTransport())) {
1711   - clientTransaction = udpSipProvider.getNewClientTransaction(request);
1712   - }
1713   -
1714   - clientTransaction.sendRequest();
1715   -
1716   - } catch (SipException | ParseException | InvalidArgumentException e) {
1717   - e.printStackTrace();
1718   - }
1719   - }
1720   -
1721   - /**
1722   - * 回放倍速播放
1723   - */
1724   - @Override
1725   - public void playSpeedCmd(Device device, StreamInfo streamInfo, Double speed) {
1726   - try {
1727   -
1728   - StringBuffer content = new StringBuffer(200);
1729   - content.append("PLAY RTSP/1.0\r\n");
1730   - content.append("CSeq: " + getInfoCseq() + "\r\n");
1731   - content.append("Scale: " + String.format("%.6f",speed) + "\r\n");
1732   - Request request = headerProvider.createInfoRequest(device, streamInfo, content.toString());
1733   - if (request == null) {
1734   - return;
1735   - }
1736   - logger.info(request.toString());
1737   - ClientTransaction clientTransaction = null;
1738   - if ("TCP".equals(device.getTransport())) {
1739   - clientTransaction = tcpSipProvider.getNewClientTransaction(request);
1740   - } else if ("UDP".equals(device.getTransport())) {
1741   - clientTransaction = udpSipProvider.getNewClientTransaction(request);
1742   - }
1743   -
1744   - clientTransaction.sendRequest();
1745   -
1746   - } catch (SipException | ParseException | InvalidArgumentException e) {
1747   - e.printStackTrace();
1748   - }
1749   - }
1750   -
1751   - private int getInfoCseq() {
1752   - return (int) ((Math.random() * 9 + 1) * Math.pow(10, 8));
1753   - }
1754   -
1755   - @Override
1756   - public void playbackControlCmd(Device device, StreamInfo streamInfo, String content,SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) {
1757   - try {
1758   - Request request = headerProvider.createInfoRequest(device, streamInfo, content);
1759   - if (request == null) {
1760   - return;
1761   - }
1762   - ClientTransaction clientTransaction = null;
1763   - if ("TCP".equals(device.getTransport())) {
1764   - clientTransaction = tcpSipProvider.getNewClientTransaction(request);
1765   - } else if ("UDP".equals(device.getTransport())) {
1766   - clientTransaction = udpSipProvider.getNewClientTransaction(request);
1767   - }
1768   - CallIdHeader callIdHeader = (CallIdHeader)request.getHeader(CallIdHeader.NAME);
1769   - if(errorEvent != null) {
1770   - sipSubscribe.addErrorSubscribe(callIdHeader.getCallId(), (eventResult -> {
1771   - errorEvent.response(eventResult);
1772   - sipSubscribe.removeErrorSubscribe(eventResult.callId);
1773   - sipSubscribe.removeOkSubscribe(eventResult.callId);
1774   - }));
1775   - }
1776   -
1777   - if(okEvent != null) {
1778   - sipSubscribe.addOkSubscribe(callIdHeader.getCallId(), eventResult -> {
1779   - okEvent.response(eventResult);
1780   - sipSubscribe.removeOkSubscribe(eventResult.callId);
1781   - sipSubscribe.removeErrorSubscribe(eventResult.callId);
1782   - });
1783   - }
1784   - clientTransaction.sendRequest();
1785   -
1786   - } catch (SipException | ParseException | InvalidArgumentException e) {
1787   - e.printStackTrace();
1788   - }
1789   - }
1790   -
1791   - @Override
1792   - public boolean sendAlarmMessage(Device device, DeviceAlarm deviceAlarm) {
1793   - if (device == null) {
1794   - return false;
1795   - }
1796   - logger.info("[发送 报警通知] {}/{}->{},{}", device.getDeviceId(), deviceAlarm.getChannelId(),
1797   - deviceAlarm.getLongitude(), deviceAlarm.getLatitude());
1798   - try {
1799   - String characterSet = device.getCharset();
1800   - StringBuffer deviceStatusXml = new StringBuffer(600);
1801   - deviceStatusXml.append("<?xml version=\"1.0\" encoding=\"" + characterSet + "\"?>\r\n");
1802   - deviceStatusXml.append("<Notify>\r\n");
1803   - deviceStatusXml.append("<CmdType>Alarm</CmdType>\r\n");
1804   - deviceStatusXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
1805   - deviceStatusXml.append("<DeviceID>" + deviceAlarm.getChannelId() + "</DeviceID>\r\n");
1806   - deviceStatusXml.append("<AlarmPriority>" + deviceAlarm.getAlarmPriority() + "</AlarmPriority>\r\n");
1807   - deviceStatusXml.append("<AlarmMethod>" + deviceAlarm.getAlarmMethod() + "</AlarmMethod>\r\n");
1808   - deviceStatusXml.append("<AlarmTime>" + deviceAlarm.getAlarmTime() + "</AlarmTime>\r\n");
1809   - deviceStatusXml.append("<AlarmDescription>" + deviceAlarm.getAlarmDescription() + "</AlarmDescription>\r\n");
1810   - deviceStatusXml.append("<Longitude>" + deviceAlarm.getLongitude() + "</Longitude>\r\n");
1811   - deviceStatusXml.append("<Latitude>" + deviceAlarm.getLatitude() + "</Latitude>\r\n");
1812   - deviceStatusXml.append("<info>\r\n");
1813   - deviceStatusXml.append("<AlarmType>" + deviceAlarm.getAlarmType() + "</AlarmType>\r\n");
1814   - deviceStatusXml.append("</info>\r\n");
1815   - deviceStatusXml.append("</Notify>\r\n");
1816   -
1817   - CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
1818   - : udpSipProvider.getNewCallId();
1819   - Request request = headerProvider.createMessageRequest(device, deviceStatusXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null, callIdHeader);
1820   - transmitRequest(device, request);
1821   -
1822   -
1823   - } catch (SipException | ParseException e) {
1824   - e.printStackTrace();
1825   - return false;
1826   - } catch (InvalidArgumentException e) {
1827   - throw new RuntimeException(e);
1828   - }
1829   - return true;
1830   - }
  365 + CallIdHeader callIdHeader = device.getTransport().equalsIgnoreCase("TCP") ? tcpSipProvider.getNewCallId()
  366 + : udpSipProvider.getNewCallId();
  367 +
  368 + Request request = headerProvider.createInviteRequest(device, channelId, content.toString(), null, SipUtils.getNewFromTag(), null, ssrcInfo.getSsrc(), callIdHeader);
  369 + transmitRequest(device.getTransport(), request, (e -> {
  370 + streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream());
  371 + mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
  372 + errorEvent.response(e);
  373 + }), e -> {
  374 + // 这里为例避免一个通道的点播只有一个callID这个参数使用一个固定值
  375 + ResponseEvent responseEvent = (ResponseEvent) e.event;
  376 + SIPResponse response = (SIPResponse) responseEvent.getResponse();
  377 + streamSession.put(device.getDeviceId(), channelId, "play", stream, ssrcInfo.getSsrc(), mediaServerItem.getId(), response, VideoStreamSessionManager.SessionType.play);
  378 + okEvent.response(e);
  379 + });
  380 + }
  381 +
  382 + /**
  383 + * 请求回放视频流
  384 + *
  385 + * @param device 视频设备
  386 + * @param channelId 预览通道
  387 + * @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss
  388 + * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss
  389 + */
  390 + @Override
  391 + public void playbackStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId,
  392 + String startTime, String endTime, InviteStreamCallback inviteStreamCallback, InviteStreamCallback hookEvent,
  393 + SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException {
  394 +
  395 +
  396 + logger.info("{} 分配的ZLM为: {} [{}:{}]", ssrcInfo.getStream(), mediaServerItem.getId(), mediaServerItem.getIp(), ssrcInfo.getPort());
  397 +
  398 + StringBuffer content = new StringBuffer(200);
  399 + content.append("v=0\r\n");
  400 + content.append("o=" + channelId + " 0 0 IN IP4 " + mediaServerItem.getSdpIp() + "\r\n");
  401 + content.append("s=Playback\r\n");
  402 + content.append("u=" + channelId + ":0\r\n");
  403 + content.append("c=IN IP4 " + mediaServerItem.getSdpIp() + "\r\n");
  404 + content.append("t=" + DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(startTime) + " "
  405 + + DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(endTime) + "\r\n");
  406 +
  407 + String streamMode = device.getStreamMode();
  408 +
  409 + if (userSetting.isSeniorSdp()) {
  410 + if ("TCP-PASSIVE".equalsIgnoreCase(streamMode)) {
  411 + content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 126 125 99 34 98 97\r\n");
  412 + } else if ("TCP-ACTIVE".equalsIgnoreCase(streamMode)) {
  413 + content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 126 125 99 34 98 97\r\n");
  414 + } else if ("UDP".equalsIgnoreCase(streamMode)) {
  415 + content.append("m=video " + ssrcInfo.getPort() + " RTP/AVP 96 126 125 99 34 98 97\r\n");
  416 + }
  417 + content.append("a=recvonly\r\n");
  418 + content.append("a=rtpmap:96 PS/90000\r\n");
  419 + content.append("a=fmtp:126 profile-level-id=42e01e\r\n");
  420 + content.append("a=rtpmap:126 H264/90000\r\n");
  421 + content.append("a=rtpmap:125 H264S/90000\r\n");
  422 + content.append("a=fmtp:125 profile-level-id=42e01e\r\n");
  423 + content.append("a=rtpmap:99 H265/90000\r\n");
  424 + content.append("a=rtpmap:98 H264/90000\r\n");
  425 + content.append("a=rtpmap:97 MPEG4/90000\r\n");
  426 + if ("TCP-PASSIVE".equalsIgnoreCase(streamMode)) { // tcp被动模式
  427 + content.append("a=setup:passive\r\n");
  428 + content.append("a=connection:new\r\n");
  429 + } else if ("TCP-ACTIVE".equalsIgnoreCase(streamMode)) { // tcp主动模式
  430 + content.append("a=setup:active\r\n");
  431 + content.append("a=connection:new\r\n");
  432 + }
  433 + } else {
  434 + if ("TCP-PASSIVE".equalsIgnoreCase(streamMode)) {
  435 + content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 97 98 99\r\n");
  436 + } else if ("TCP-ACTIVE".equalsIgnoreCase(streamMode)) {
  437 + content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 97 98 99\r\n");
  438 + } else if ("UDP".equalsIgnoreCase(streamMode)) {
  439 + content.append("m=video " + ssrcInfo.getPort() + " RTP/AVP 96 97 98 99\r\n");
  440 + }
  441 + content.append("a=recvonly\r\n");
  442 + content.append("a=rtpmap:96 PS/90000\r\n");
  443 + content.append("a=rtpmap:97 MPEG4/90000\r\n");
  444 + content.append("a=rtpmap:98 H264/90000\r\n");
  445 + content.append("a=rtpmap:99 H265/90000\r\n");
  446 + if ("TCP-PASSIVE".equalsIgnoreCase(streamMode)) { // tcp被动模式
  447 + content.append("a=setup:passive\r\n");
  448 + content.append("a=connection:new\r\n");
  449 + } else if ("TCP-ACTIVE".equalsIgnoreCase(streamMode)) { // tcp主动模式
  450 + content.append("a=setup:active\r\n");
  451 + content.append("a=connection:new\r\n");
  452 + }
  453 + }
  454 +
  455 + content.append("y=" + ssrcInfo.getSsrc() + "\r\n");//ssrc
  456 +
  457 + CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
  458 + : udpSipProvider.getNewCallId();
  459 + HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", ssrcInfo.getStream(), true, "rtsp", mediaServerItem.getId());
  460 + // 添加订阅
  461 + subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, JSONObject json) -> {
  462 + if (hookEvent != null) {
  463 + InviteStreamInfo inviteStreamInfo = new InviteStreamInfo(mediaServerItemInUse, json, callIdHeader.getCallId(), "rtp", ssrcInfo.getStream());
  464 + hookEvent.call(inviteStreamInfo);
  465 + }
  466 + subscribe.removeSubscribe(hookSubscribe);
  467 + });
  468 + Request request = headerProvider.createPlaybackInviteRequest(device, channelId, content.toString(), null, SipUtils.getNewFromTag(), null, callIdHeader, ssrcInfo.getSsrc());
  469 +
  470 + transmitRequest(device.getTransport(), request, errorEvent, event -> {
  471 + ResponseEvent responseEvent = (ResponseEvent) event.event;
  472 + SIPResponse response = (SIPResponse) responseEvent.getResponse();
  473 + streamSession.put(device.getDeviceId(), channelId, callIdHeader.getCallId(), ssrcInfo.getStream(), ssrcInfo.getSsrc(), mediaServerItem.getId(), response, VideoStreamSessionManager.SessionType.playback);
  474 + okEvent.response(event);
  475 + });
  476 + if (inviteStreamCallback != null) {
  477 + inviteStreamCallback.call(new InviteStreamInfo(mediaServerItem, null, callIdHeader.getCallId(), "rtp", ssrcInfo.getStream()));
  478 + }
  479 + }
  480 +
  481 + /**
  482 + * 请求历史媒体下载
  483 + *
  484 + * @param device 视频设备
  485 + * @param channelId 预览通道
  486 + * @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss
  487 + * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss
  488 + * @param downloadSpeed 下载倍速参数
  489 + */
  490 + @Override
  491 + public void downloadStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId,
  492 + String startTime, String endTime, int downloadSpeed, InviteStreamCallback inviteStreamCallback, InviteStreamCallback hookEvent,
  493 + SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException {
  494 +
  495 + logger.info("{} 分配的ZLM为: {} [{}:{}]", ssrcInfo.getStream(), mediaServerItem.getId(), mediaServerItem.getIp(), ssrcInfo.getPort());
  496 +
  497 + StringBuffer content = new StringBuffer(200);
  498 + content.append("v=0\r\n");
  499 + content.append("o=" + channelId + " 0 0 IN IP4 " + mediaServerItem.getSdpIp() + "\r\n");
  500 + content.append("s=Download\r\n");
  501 + content.append("u=" + channelId + ":0\r\n");
  502 + content.append("c=IN IP4 " + mediaServerItem.getSdpIp() + "\r\n");
  503 + content.append("t=" + DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(startTime) + " "
  504 + + DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(endTime) + "\r\n");
  505 +
  506 + String streamMode = device.getStreamMode().toUpperCase();
  507 +
  508 + if (userSetting.isSeniorSdp()) {
  509 + if ("TCP-PASSIVE".equals(streamMode)) {
  510 + content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 126 125 99 34 98 97\r\n");
  511 + } else if ("TCP-ACTIVE".equals(streamMode)) {
  512 + content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 126 125 99 34 98 97\r\n");
  513 + } else if ("UDP".equals(streamMode)) {
  514 + content.append("m=video " + ssrcInfo.getPort() + " RTP/AVP 96 126 125 99 34 98 97\r\n");
  515 + }
  516 + content.append("a=recvonly\r\n");
  517 + content.append("a=rtpmap:96 PS/90000\r\n");
  518 + content.append("a=fmtp:126 profile-level-id=42e01e\r\n");
  519 + content.append("a=rtpmap:126 H264/90000\r\n");
  520 + content.append("a=rtpmap:125 H264S/90000\r\n");
  521 + content.append("a=fmtp:125 profile-level-id=42e01e\r\n");
  522 + content.append("a=rtpmap:99 MP4V-ES/90000\r\n");
  523 + content.append("a=fmtp:99 profile-level-id=3\r\n");
  524 + content.append("a=rtpmap:98 H264/90000\r\n");
  525 + content.append("a=rtpmap:97 MPEG4/90000\r\n");
  526 + if ("TCP-PASSIVE".equals(streamMode)) { // tcp被动模式
  527 + content.append("a=setup:passive\r\n");
  528 + content.append("a=connection:new\r\n");
  529 + } else if ("TCP-ACTIVE".equals(streamMode)) { // tcp主动模式
  530 + content.append("a=setup:active\r\n");
  531 + content.append("a=connection:new\r\n");
  532 + }
  533 + } else {
  534 + if ("TCP-PASSIVE".equals(streamMode)) {
  535 + content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 97 98 99\r\n");
  536 + } else if ("TCP-ACTIVE".equals(streamMode)) {
  537 + content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 97 98 99\r\n");
  538 + } else if ("UDP".equals(streamMode)) {
  539 + content.append("m=video " + ssrcInfo.getPort() + " RTP/AVP 96 97 98 99\r\n");
  540 + }
  541 + content.append("a=recvonly\r\n");
  542 + content.append("a=rtpmap:96 PS/90000\r\n");
  543 + content.append("a=rtpmap:97 MPEG4/90000\r\n");
  544 + content.append("a=rtpmap:98 H264/90000\r\n");
  545 + content.append("a=rtpmap:99 H265/90000\r\n");
  546 + if ("TCP-PASSIVE".equals(streamMode)) { // tcp被动模式
  547 + content.append("a=setup:passive\r\n");
  548 + content.append("a=connection:new\r\n");
  549 + } else if ("TCP-ACTIVE".equals(streamMode)) { // tcp主动模式
  550 + content.append("a=setup:active\r\n");
  551 + content.append("a=connection:new\r\n");
  552 + }
  553 + }
  554 + content.append("a=downloadspeed:" + downloadSpeed + "\r\n");
  555 +
  556 + content.append("y=" + ssrcInfo.getSsrc() + "\r\n");//ssrc
  557 +
  558 + CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
  559 + : udpSipProvider.getNewCallId();
  560 +
  561 + HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", ssrcInfo.getStream(), true, null, mediaServerItem.getId());
  562 + // 添加订阅
  563 + subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, JSONObject json) -> {
  564 + hookEvent.call(new InviteStreamInfo(mediaServerItem, json, callIdHeader.getCallId(), "rtp", ssrcInfo.getStream()));
  565 + subscribe.removeSubscribe(hookSubscribe);
  566 + hookSubscribe.getContent().put("regist", false);
  567 + hookSubscribe.getContent().put("schema", "rtsp");
  568 + // 添加流注销的订阅,注销了后向设备发送bye
  569 + subscribe.addSubscribe(hookSubscribe,
  570 + (MediaServerItem mediaServerItemForEnd, JSONObject jsonForEnd) -> {
  571 + logger.info("[录像]下载结束, 发送BYE");
  572 + try {
  573 + streamByeCmd(device, channelId, ssrcInfo.getStream(), callIdHeader.getCallId());
  574 + } catch (InvalidArgumentException | ParseException | SipException |
  575 + SsrcTransactionNotFoundException e) {
  576 + logger.error("[录像]下载结束, 发送BYE失败 {}", e.getMessage());
  577 + }
  578 + });
  579 + });
  580 +
  581 + Request request = headerProvider.createPlaybackInviteRequest(device, channelId, content.toString(), null, SipUtils.getNewFromTag(), null, callIdHeader, ssrcInfo.getSsrc());
  582 + if (inviteStreamCallback != null) {
  583 + inviteStreamCallback.call(new InviteStreamInfo(mediaServerItem, null, callIdHeader.getCallId(), "rtp", ssrcInfo.getStream()));
  584 + }
  585 + transmitRequest(device.getTransport(), request, errorEvent, okEvent -> {
  586 + ResponseEvent responseEvent = (ResponseEvent) okEvent.event;
  587 + SIPResponse response = (SIPResponse) responseEvent.getResponse();
  588 + streamSession.put(device.getDeviceId(), channelId, callIdHeader.getCallId(), ssrcInfo.getStream(), ssrcInfo.getSsrc(), mediaServerItem.getId(), response, VideoStreamSessionManager.SessionType.download);
  589 + });
  590 + }
  591 +
  592 + /**
  593 + * 视频流停止, 不使用回调
  594 + */
  595 + @Override
  596 + public void streamByeCmd(Device device, String channelId, String stream, String callId) throws InvalidArgumentException, ParseException, SipException, SsrcTransactionNotFoundException {
  597 + streamByeCmd(device, channelId, stream, callId, null);
  598 + }
  599 +
  600 + /**
  601 + * 视频流停止
  602 + */
  603 + @Override
  604 + public void streamByeCmd(Device device, String channelId, String stream, String callId, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException, SsrcTransactionNotFoundException {
  605 + SsrcTransaction ssrcTransaction = streamSession.getSsrcTransaction(device.getDeviceId(), channelId, callId, stream);
  606 + if (ssrcTransaction == null) {
  607 + throw new SsrcTransactionNotFoundException(device.getDeviceId(), channelId, callId, stream);
  608 + }
  609 +
  610 + mediaServerService.releaseSsrc(ssrcTransaction.getMediaServerId(), ssrcTransaction.getSsrc());
  611 + mediaServerService.closeRTPServer(ssrcTransaction.getMediaServerId(), ssrcTransaction.getStream());
  612 + streamSession.remove(ssrcTransaction.getDeviceId(), ssrcTransaction.getChannelId(), ssrcTransaction.getStream());
  613 +
  614 + Request byteRequest = headerProvider.createByteRequest(device, channelId, ssrcTransaction.getSipTransactionInfo());
  615 + transmitRequest(device.getTransport(), byteRequest, null, okEvent);
  616 + }
  617 +
  618 + /**
  619 + * 语音广播
  620 + *
  621 + * @param device 视频设备
  622 + * @param channelId 预览通道
  623 + */
  624 + @Override
  625 + public void audioBroadcastCmd(Device device, String channelId) {
  626 + }
  627 +
  628 + /**
  629 + * 语音广播
  630 + *
  631 + * @param device 视频设备
  632 + */
  633 + @Override
  634 + public void audioBroadcastCmd(Device device) throws InvalidArgumentException, SipException, ParseException {
  635 +
  636 + StringBuffer broadcastXml = new StringBuffer(200);
  637 + String charset = device.getCharset();
  638 + broadcastXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
  639 + broadcastXml.append("<Notify>\r\n");
  640 + broadcastXml.append("<CmdType>Broadcast</CmdType>\r\n");
  641 + broadcastXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");
  642 + broadcastXml.append("<SourceID>" + sipConfig.getId() + "</SourceID>\r\n");
  643 + broadcastXml.append("<TargetID>" + device.getDeviceId() + "</TargetID>\r\n");
  644 + broadcastXml.append("</Notify>\r\n");
  645 +
  646 + CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
  647 + : udpSipProvider.getNewCallId();
  648 +
  649 + Request request = headerProvider.createMessageRequest(device, broadcastXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null, callIdHeader);
  650 + transmitRequest(device.getTransport(), request);
  651 +
  652 + }
  653 +
  654 + @Override
  655 + public void audioBroadcastCmd(Device device, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException {
  656 +
  657 + StringBuffer broadcastXml = new StringBuffer(200);
  658 + String charset = device.getCharset();
  659 + broadcastXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
  660 + broadcastXml.append("<Notify>\r\n");
  661 + broadcastXml.append("<CmdType>Broadcast</CmdType>\r\n");
  662 + broadcastXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");
  663 + broadcastXml.append("<SourceID>" + sipConfig.getId() + "</SourceID>\r\n");
  664 + broadcastXml.append("<TargetID>" + device.getDeviceId() + "</TargetID>\r\n");
  665 + broadcastXml.append("</Notify>\r\n");
  666 +
  667 + CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
  668 + : udpSipProvider.getNewCallId();
  669 +
  670 + Request request = headerProvider.createMessageRequest(device, broadcastXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null, callIdHeader);
  671 + transmitRequest(device.getTransport(), request, errorEvent);
  672 +
  673 + }
  674 +
  675 +
  676 + /**
  677 + * 音视频录像控制
  678 + *
  679 + * @param device 视频设备
  680 + * @param channelId 预览通道
  681 + * @param recordCmdStr 录像命令:Record / StopRecord
  682 + */
  683 + @Override
  684 + public void recordCmd(Device device, String channelId, String recordCmdStr, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException {
  685 + StringBuffer cmdXml = new StringBuffer(200);
  686 + String charset = device.getCharset();
  687 + cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
  688 + cmdXml.append("<Control>\r\n");
  689 + cmdXml.append("<CmdType>DeviceControl</CmdType>\r\n");
  690 + cmdXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");
  691 + if (ObjectUtils.isEmpty(channelId)) {
  692 + cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
  693 + } else {
  694 + cmdXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
  695 + }
  696 + cmdXml.append("<RecordCmd>" + recordCmdStr + "</RecordCmd>\r\n");
  697 + cmdXml.append("</Control>\r\n");
  698 +
  699 + CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
  700 + : udpSipProvider.getNewCallId();
  701 +
  702 + Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null, callIdHeader);
  703 + transmitRequest(device.getTransport(), request, errorEvent);
  704 + }
  705 +
  706 + /**
  707 + * 远程启动控制命令
  708 + *
  709 + * @param device 视频设备
  710 + */
  711 + @Override
  712 + public void teleBootCmd(Device device) throws InvalidArgumentException, SipException, ParseException {
  713 +
  714 + StringBuffer cmdXml = new StringBuffer(200);
  715 + String charset = device.getCharset();
  716 + cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
  717 + cmdXml.append("<Control>\r\n");
  718 + cmdXml.append("<CmdType>DeviceControl</CmdType>\r\n");
  719 + cmdXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");
  720 + cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
  721 + cmdXml.append("<TeleBoot>Boot</TeleBoot>\r\n");
  722 + cmdXml.append("</Control>\r\n");
  723 +
  724 + CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
  725 + : udpSipProvider.getNewCallId();
  726 +
  727 + Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null, callIdHeader);
  728 + transmitRequest(device.getTransport(), request);
  729 + }
  730 +
  731 + /**
  732 + * 报警布防/撤防命令
  733 + *
  734 + * @param device 视频设备
  735 + * @param guardCmdStr "SetGuard"/"ResetGuard"
  736 + */
  737 + @Override
  738 + public void guardCmd(Device device, String guardCmdStr, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException {
  739 +
  740 + StringBuffer cmdXml = new StringBuffer(200);
  741 + String charset = device.getCharset();
  742 + cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
  743 + cmdXml.append("<Control>\r\n");
  744 + cmdXml.append("<CmdType>DeviceControl</CmdType>\r\n");
  745 + cmdXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");
  746 + cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
  747 + cmdXml.append("<GuardCmd>" + guardCmdStr + "</GuardCmd>\r\n");
  748 + cmdXml.append("</Control>\r\n");
  749 +
  750 + CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
  751 + : udpSipProvider.getNewCallId();
  752 +
  753 + Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null, callIdHeader);
  754 + transmitRequest(device.getTransport(), request, errorEvent);
  755 + }
  756 +
  757 + /**
  758 + * 报警复位命令
  759 + *
  760 + * @param device 视频设备
  761 + */
  762 + @Override
  763 + public void alarmCmd(Device device, String alarmMethod, String alarmType, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException {
  764 +
  765 + StringBuffer cmdXml = new StringBuffer(200);
  766 + String charset = device.getCharset();
  767 + cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
  768 + cmdXml.append("<Control>\r\n");
  769 + cmdXml.append("<CmdType>DeviceControl</CmdType>\r\n");
  770 + cmdXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");
  771 + cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
  772 + cmdXml.append("<AlarmCmd>ResetAlarm</AlarmCmd>\r\n");
  773 + if (!ObjectUtils.isEmpty(alarmMethod) || !ObjectUtils.isEmpty(alarmType)) {
  774 + cmdXml.append("<Info>\r\n");
  775 + }
  776 + if (!ObjectUtils.isEmpty(alarmMethod)) {
  777 + cmdXml.append("<AlarmMethod>" + alarmMethod + "</AlarmMethod>\r\n");
  778 + }
  779 + if (!ObjectUtils.isEmpty(alarmType)) {
  780 + cmdXml.append("<AlarmType>" + alarmType + "</AlarmType>\r\n");
  781 + }
  782 + if (!ObjectUtils.isEmpty(alarmMethod) || !ObjectUtils.isEmpty(alarmType)) {
  783 + cmdXml.append("</Info>\r\n");
  784 + }
  785 + cmdXml.append("</Control>\r\n");
  786 +
  787 + CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
  788 + : udpSipProvider.getNewCallId();
  789 +
  790 + Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null, callIdHeader);
  791 + transmitRequest(device.getTransport(), request, errorEvent);
  792 + }
  793 +
  794 + /**
  795 + * 强制关键帧命令,设备收到此命令应立刻发送一个IDR帧
  796 + *
  797 + * @param device 视频设备
  798 + * @param channelId 预览通道
  799 + */
  800 + @Override
  801 + public void iFrameCmd(Device device, String channelId) throws InvalidArgumentException, SipException, ParseException {
  802 +
  803 + StringBuffer cmdXml = new StringBuffer(200);
  804 + String charset = device.getCharset();
  805 + cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
  806 + cmdXml.append("<Control>\r\n");
  807 + cmdXml.append("<CmdType>DeviceControl</CmdType>\r\n");
  808 + cmdXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");
  809 + if (ObjectUtils.isEmpty(channelId)) {
  810 + cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
  811 + } else {
  812 + cmdXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
  813 + }
  814 + cmdXml.append("<IFameCmd>Send</IFameCmd>\r\n");
  815 + cmdXml.append("</Control>\r\n");
  816 +
  817 + CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
  818 + : udpSipProvider.getNewCallId();
  819 +
  820 + Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null, callIdHeader);
  821 + transmitRequest(device.getTransport(), request);
  822 + }
  823 +
  824 + /**
  825 + * 看守位控制命令
  826 + *
  827 + * @param device 视频设备
  828 + * @param enabled 看守位使能:1 = 开启,0 = 关闭
  829 + * @param resetTime 自动归位时间间隔,开启看守位时使用,单位:秒(s)
  830 + * @param presetIndex 调用预置位编号,开启看守位时使用,取值范围0~255
  831 + */
  832 + @Override
  833 + public void homePositionCmd(Device device, String channelId, String enabled, String resetTime, String presetIndex, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException {
  834 +
  835 + StringBuffer cmdXml = new StringBuffer(200);
  836 + String charset = device.getCharset();
  837 + cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
  838 + cmdXml.append("<Control>\r\n");
  839 + cmdXml.append("<CmdType>DeviceControl</CmdType>\r\n");
  840 + cmdXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");
  841 + if (ObjectUtils.isEmpty(channelId)) {
  842 + cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
  843 + } else {
  844 + cmdXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
  845 + }
  846 + cmdXml.append("<HomePosition>\r\n");
  847 + if (NumericUtil.isInteger(enabled) && (!enabled.equals("0"))) {
  848 + cmdXml.append("<Enabled>1</Enabled>\r\n");
  849 + if (NumericUtil.isInteger(resetTime)) {
  850 + cmdXml.append("<ResetTime>" + resetTime + "</ResetTime>\r\n");
  851 + } else {
  852 + cmdXml.append("<ResetTime>0</ResetTime>\r\n");
  853 + }
  854 + if (NumericUtil.isInteger(presetIndex)) {
  855 + cmdXml.append("<PresetIndex>" + presetIndex + "</PresetIndex>\r\n");
  856 + } else {
  857 + cmdXml.append("<PresetIndex>0</PresetIndex>\r\n");
  858 + }
  859 + } else {
  860 + cmdXml.append("<Enabled>0</Enabled>\r\n");
  861 + }
  862 + cmdXml.append("</HomePosition>\r\n");
  863 + cmdXml.append("</Control>\r\n");
  864 +
  865 + CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
  866 + : udpSipProvider.getNewCallId();
  867 +
  868 + Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null, callIdHeader);
  869 + transmitRequest(device.getTransport(), request, errorEvent);
  870 + }
  871 +
  872 + /**
  873 + * 设备配置命令
  874 + *
  875 + * @param device 视频设备
  876 + */
  877 + @Override
  878 + public void deviceConfigCmd(Device device) {
  879 + // TODO Auto-generated method stub
  880 + }
  881 +
  882 + /**
  883 + * 设备配置命令:basicParam
  884 + *
  885 + * @param device 视频设备
  886 + * @param channelId 通道编码(可选)
  887 + * @param name 设备/通道名称(可选)
  888 + * @param expiration 注册过期时间(可选)
  889 + * @param heartBeatInterval 心跳间隔时间(可选)
  890 + * @param heartBeatCount 心跳超时次数(可选)
  891 + */
  892 + @Override
  893 + public void deviceBasicConfigCmd(Device device, String channelId, String name, String expiration,
  894 + String heartBeatInterval, String heartBeatCount, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException {
  895 +
  896 + StringBuffer cmdXml = new StringBuffer(200);
  897 + String charset = device.getCharset();
  898 + cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
  899 + cmdXml.append("<Control>\r\n");
  900 + cmdXml.append("<CmdType>DeviceConfig</CmdType>\r\n");
  901 + cmdXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");
  902 + if (ObjectUtils.isEmpty(channelId)) {
  903 + cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
  904 + } else {
  905 + cmdXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
  906 + }
  907 + cmdXml.append("<BasicParam>\r\n");
  908 + if (!ObjectUtils.isEmpty(name)) {
  909 + cmdXml.append("<Name>" + name + "</Name>\r\n");
  910 + }
  911 + if (NumericUtil.isInteger(expiration)) {
  912 + if (Integer.valueOf(expiration) > 0) {
  913 + cmdXml.append("<Expiration>" + expiration + "</Expiration>\r\n");
  914 + }
  915 + }
  916 + if (NumericUtil.isInteger(heartBeatInterval)) {
  917 + if (Integer.valueOf(heartBeatInterval) > 0) {
  918 + cmdXml.append("<HeartBeatInterval>" + heartBeatInterval + "</HeartBeatInterval>\r\n");
  919 + }
  920 + }
  921 + if (NumericUtil.isInteger(heartBeatCount)) {
  922 + if (Integer.valueOf(heartBeatCount) > 0) {
  923 + cmdXml.append("<HeartBeatCount>" + heartBeatCount + "</HeartBeatCount>\r\n");
  924 + }
  925 + }
  926 + cmdXml.append("</BasicParam>\r\n");
  927 + cmdXml.append("</Control>\r\n");
  928 +
  929 + CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
  930 + : udpSipProvider.getNewCallId();
  931 +
  932 + Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null, callIdHeader);
  933 + transmitRequest(device.getTransport(), request, errorEvent);
  934 + }
  935 +
  936 + /**
  937 + * 查询设备状态
  938 + *
  939 + * @param device 视频设备
  940 + */
  941 + @Override
  942 + public void deviceStatusQuery(Device device, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException {
  943 +
  944 + String charset = device.getCharset();
  945 + StringBuffer catalogXml = new StringBuffer(200);
  946 + catalogXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
  947 + catalogXml.append("<Query>\r\n");
  948 + catalogXml.append("<CmdType>DeviceStatus</CmdType>\r\n");
  949 + catalogXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");
  950 + catalogXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
  951 + catalogXml.append("</Query>\r\n");
  952 +
  953 + CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
  954 + : udpSipProvider.getNewCallId();
  955 +
  956 + Request request = headerProvider.createMessageRequest(device, catalogXml.toString(), null, SipUtils.getNewFromTag(), null, callIdHeader);
  957 +
  958 + transmitRequest(device.getTransport(), request, errorEvent);
  959 + }
  960 +
  961 + /**
  962 + * 查询设备信息
  963 + *
  964 + * @param device 视频设备
  965 + */
  966 + @Override
  967 + public void deviceInfoQuery(Device device) throws InvalidArgumentException, SipException, ParseException {
  968 +
  969 + StringBuffer catalogXml = new StringBuffer(200);
  970 + String charset = device.getCharset();
  971 + catalogXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
  972 + catalogXml.append("<Query>\r\n");
  973 + catalogXml.append("<CmdType>DeviceInfo</CmdType>\r\n");
  974 + catalogXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");
  975 + catalogXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
  976 + catalogXml.append("</Query>\r\n");
  977 +
  978 + CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
  979 + : udpSipProvider.getNewCallId();
  980 +
  981 + Request request = headerProvider.createMessageRequest(device, catalogXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null, callIdHeader);
  982 +
  983 + transmitRequest(device.getTransport(), request);
  984 +
  985 + }
  986 +
  987 + /**
  988 + * 查询目录列表
  989 + *
  990 + * @param device 视频设备
  991 + */
  992 + @Override
  993 + public void catalogQuery(Device device, int sn, SipSubscribe.Event errorEvent) throws SipException, InvalidArgumentException, ParseException {
  994 +
  995 + StringBuffer catalogXml = new StringBuffer(200);
  996 + String charset = device.getCharset();
  997 + catalogXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
  998 + catalogXml.append("<Query>\r\n");
  999 + catalogXml.append(" <CmdType>Catalog</CmdType>\r\n");
  1000 + catalogXml.append(" <SN>" + sn + "</SN>\r\n");
  1001 + catalogXml.append(" <DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
  1002 + catalogXml.append("</Query>\r\n");
  1003 +
  1004 + CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
  1005 + : udpSipProvider.getNewCallId();
  1006 +
  1007 + Request request = headerProvider.createMessageRequest(device, catalogXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null, callIdHeader);
  1008 +
  1009 + transmitRequest(device.getTransport(), request, errorEvent);
  1010 + }
  1011 +
  1012 + /**
  1013 + * 查询录像信息
  1014 + *
  1015 + * @param device 视频设备
  1016 + * @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss
  1017 + * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss
  1018 + */
  1019 + @Override
  1020 + 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 {
  1021 + if (secrecy == null) {
  1022 + secrecy = 0;
  1023 + }
  1024 + if (type == null) {
  1025 + type = "all";
  1026 + }
  1027 +
  1028 + StringBuffer recordInfoXml = new StringBuffer(200);
  1029 + String charset = device.getCharset();
  1030 + recordInfoXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
  1031 + recordInfoXml.append("<Query>\r\n");
  1032 + recordInfoXml.append("<CmdType>RecordInfo</CmdType>\r\n");
  1033 + recordInfoXml.append("<SN>" + sn + "</SN>\r\n");
  1034 + recordInfoXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
  1035 + if (startTime != null) {
  1036 + recordInfoXml.append("<StartTime>" + DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(startTime) + "</StartTime>\r\n");
  1037 + }
  1038 + if (endTime != null) {
  1039 + recordInfoXml.append("<EndTime>" + DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(endTime) + "</EndTime>\r\n");
  1040 + }
  1041 + if (secrecy != null) {
  1042 + recordInfoXml.append("<Secrecy> " + secrecy + " </Secrecy>\r\n");
  1043 + }
  1044 + if (type != null) {
  1045 + // 大华NVR要求必须增加一个值为all的文本元素节点Type
  1046 + recordInfoXml.append("<Type>" + type + "</Type>\r\n");
  1047 + }
  1048 + recordInfoXml.append("</Query>\r\n");
  1049 +
  1050 + CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
  1051 + : udpSipProvider.getNewCallId();
  1052 +
  1053 + Request request = headerProvider.createMessageRequest(device, recordInfoXml.toString(),
  1054 + SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null, callIdHeader);
  1055 +
  1056 + transmitRequest(device.getTransport(), request, errorEvent, okEvent);
  1057 + }
  1058 +
  1059 + /**
  1060 + * 查询报警信息
  1061 + *
  1062 + * @param device 视频设备
  1063 + * @param startPriority 报警起始级别(可选)
  1064 + * @param endPriority 报警终止级别(可选)
  1065 + * @param alarmMethod 报警方式条件(可选)
  1066 + * @param alarmType 报警类型
  1067 + * @param startTime 报警发生起始时间(可选)
  1068 + * @param endTime 报警发生终止时间(可选)
  1069 + * @return true = 命令发送成功
  1070 + */
  1071 + @Override
  1072 + public void alarmInfoQuery(Device device, String startPriority, String endPriority, String alarmMethod, String alarmType,
  1073 + String startTime, String endTime, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException {
  1074 +
  1075 + StringBuffer cmdXml = new StringBuffer(200);
  1076 + String charset = device.getCharset();
  1077 + cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
  1078 + cmdXml.append("<Query>\r\n");
  1079 + cmdXml.append("<CmdType>Alarm</CmdType>\r\n");
  1080 + cmdXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");
  1081 + cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
  1082 + if (!ObjectUtils.isEmpty(startPriority)) {
  1083 + cmdXml.append("<StartAlarmPriority>" + startPriority + "</StartAlarmPriority>\r\n");
  1084 + }
  1085 + if (!ObjectUtils.isEmpty(endPriority)) {
  1086 + cmdXml.append("<EndAlarmPriority>" + endPriority + "</EndAlarmPriority>\r\n");
  1087 + }
  1088 + if (!ObjectUtils.isEmpty(alarmMethod)) {
  1089 + cmdXml.append("<AlarmMethod>" + alarmMethod + "</AlarmMethod>\r\n");
  1090 + }
  1091 + if (!ObjectUtils.isEmpty(alarmType)) {
  1092 + cmdXml.append("<AlarmType>" + alarmType + "</AlarmType>\r\n");
  1093 + }
  1094 + if (!ObjectUtils.isEmpty(startTime)) {
  1095 + cmdXml.append("<StartAlarmTime>" + startTime + "</StartAlarmTime>\r\n");
  1096 + }
  1097 + if (!ObjectUtils.isEmpty(endTime)) {
  1098 + cmdXml.append("<EndAlarmTime>" + endTime + "</EndAlarmTime>\r\n");
  1099 + }
  1100 + cmdXml.append("</Query>\r\n");
  1101 +
  1102 + CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
  1103 + : udpSipProvider.getNewCallId();
  1104 +
  1105 + Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null, callIdHeader);
  1106 + transmitRequest(device.getTransport(), request, errorEvent);
  1107 + }
  1108 +
  1109 + /**
  1110 + * 查询设备配置
  1111 + *
  1112 + * @param device 视频设备
  1113 + * @param channelId 通道编码(可选)
  1114 + * @param configType 配置类型:
  1115 + */
  1116 + @Override
  1117 + public void deviceConfigQuery(Device device, String channelId, String configType, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException {
  1118 +
  1119 + StringBuffer cmdXml = new StringBuffer(200);
  1120 + String charset = device.getCharset();
  1121 + cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
  1122 + cmdXml.append("<Query>\r\n");
  1123 + cmdXml.append("<CmdType>ConfigDownload</CmdType>\r\n");
  1124 + cmdXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");
  1125 + if (ObjectUtils.isEmpty(channelId)) {
  1126 + cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
  1127 + } else {
  1128 + cmdXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
  1129 + }
  1130 + cmdXml.append("<ConfigType>" + configType + "</ConfigType>\r\n");
  1131 + cmdXml.append("</Query>\r\n");
  1132 +
  1133 + CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
  1134 + : udpSipProvider.getNewCallId();
  1135 +
  1136 + Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null, callIdHeader);
  1137 + transmitRequest(device.getTransport(), request, errorEvent);
  1138 + }
  1139 +
  1140 + /**
  1141 + * 查询设备预置位置
  1142 + *
  1143 + * @param device 视频设备
  1144 + */
  1145 + @Override
  1146 + public void presetQuery(Device device, String channelId, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException {
  1147 +
  1148 + StringBuffer cmdXml = new StringBuffer(200);
  1149 + String charset = device.getCharset();
  1150 + cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
  1151 + cmdXml.append("<Query>\r\n");
  1152 + cmdXml.append("<CmdType>PresetQuery</CmdType>\r\n");
  1153 + cmdXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");
  1154 + if (ObjectUtils.isEmpty(channelId)) {
  1155 + cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
  1156 + } else {
  1157 + cmdXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
  1158 + }
  1159 + cmdXml.append("</Query>\r\n");
  1160 +
  1161 + CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
  1162 + : udpSipProvider.getNewCallId();
  1163 +
  1164 + Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null, callIdHeader);
  1165 + transmitRequest(device.getTransport(), request, errorEvent);
  1166 + }
  1167 +
  1168 + /**
  1169 + * 查询移动设备位置数据
  1170 + *
  1171 + * @param device 视频设备
  1172 + */
  1173 + @Override
  1174 + public void mobilePostitionQuery(Device device, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException {
  1175 +
  1176 + StringBuffer mobilePostitionXml = new StringBuffer(200);
  1177 + String charset = device.getCharset();
  1178 + mobilePostitionXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
  1179 + mobilePostitionXml.append("<Query>\r\n");
  1180 + mobilePostitionXml.append("<CmdType>MobilePosition</CmdType>\r\n");
  1181 + mobilePostitionXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");
  1182 + mobilePostitionXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
  1183 + mobilePostitionXml.append("<Interval>60</Interval>\r\n");
  1184 + mobilePostitionXml.append("</Query>\r\n");
  1185 +
  1186 + CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
  1187 + : udpSipProvider.getNewCallId();
  1188 +
  1189 + Request request = headerProvider.createMessageRequest(device, mobilePostitionXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null, callIdHeader);
  1190 +
  1191 + transmitRequest(device.getTransport(), request, errorEvent);
  1192 +
  1193 + }
  1194 +
  1195 + /**
  1196 + * 订阅、取消订阅移动位置
  1197 + *
  1198 + * @param device 视频设备
  1199 + * @return true = 命令发送成功
  1200 + */
  1201 + @Override
  1202 + public SIPRequest mobilePositionSubscribe(Device device, SIPRequest requestOld, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException {
  1203 +
  1204 + StringBuffer subscribePostitionXml = new StringBuffer(200);
  1205 + String charset = device.getCharset();
  1206 + subscribePostitionXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
  1207 + subscribePostitionXml.append("<Query>\r\n");
  1208 + subscribePostitionXml.append("<CmdType>MobilePosition</CmdType>\r\n");
  1209 + subscribePostitionXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");
  1210 + subscribePostitionXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
  1211 + if (device.getSubscribeCycleForMobilePosition() > 0) {
  1212 + subscribePostitionXml.append("<Interval>" + device.getMobilePositionSubmissionInterval() + "</Interval>\r\n");
  1213 + }
  1214 + subscribePostitionXml.append("</Query>\r\n");
  1215 +
  1216 + CallIdHeader callIdHeader;
  1217 +
  1218 + if (requestOld != null) {
  1219 + callIdHeader = sipFactory.createHeaderFactory().createCallIdHeader(requestOld.getCallIdHeader().getCallId());
  1220 + } else {
  1221 + callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
  1222 + : udpSipProvider.getNewCallId();
  1223 + }
  1224 + SIPRequest request = (SIPRequest) headerProvider.createSubscribeRequest(device, subscribePostitionXml.toString(), requestOld, device.getSubscribeCycleForMobilePosition(), "presence", callIdHeader); //Position;id=" + tm.substring(tm.length() - 4));
  1225 +
  1226 + transmitRequest(device.getTransport(), request, errorEvent, okEvent);
  1227 + return request;
  1228 + }
  1229 +
  1230 + /**
  1231 + * 订阅、取消订阅报警信息
  1232 + *
  1233 + * @param device 视频设备
  1234 + * @param expires 订阅过期时间(0 = 取消订阅)
  1235 + * @param startPriority 报警起始级别(可选)
  1236 + * @param endPriority 报警终止级别(可选)
  1237 + * @param alarmMethod 报警方式条件(可选)
  1238 + * @param alarmType 报警类型
  1239 + * @param startTime 报警发生起始时间(可选)
  1240 + * @param endTime 报警发生终止时间(可选)
  1241 + * @return true = 命令发送成功
  1242 + */
  1243 + @Override
  1244 + public void alarmSubscribe(Device device, int expires, String startPriority, String endPriority, String alarmMethod, String alarmType, String startTime, String endTime) throws InvalidArgumentException, SipException, ParseException {
  1245 +
  1246 + StringBuffer cmdXml = new StringBuffer(200);
  1247 + String charset = device.getCharset();
  1248 + cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
  1249 + cmdXml.append("<Query>\r\n");
  1250 + cmdXml.append("<CmdType>Alarm</CmdType>\r\n");
  1251 + cmdXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");
  1252 + cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
  1253 + if (!ObjectUtils.isEmpty(startPriority)) {
  1254 + cmdXml.append("<StartAlarmPriority>" + startPriority + "</StartAlarmPriority>\r\n");
  1255 + }
  1256 + if (!ObjectUtils.isEmpty(endPriority)) {
  1257 + cmdXml.append("<EndAlarmPriority>" + endPriority + "</EndAlarmPriority>\r\n");
  1258 + }
  1259 + if (!ObjectUtils.isEmpty(alarmMethod)) {
  1260 + cmdXml.append("<AlarmMethod>" + alarmMethod + "</AlarmMethod>\r\n");
  1261 + }
  1262 + if (!ObjectUtils.isEmpty(alarmType)) {
  1263 + cmdXml.append("<AlarmType>" + alarmType + "</AlarmType>\r\n");
  1264 + }
  1265 + if (!ObjectUtils.isEmpty(startTime)) {
  1266 + cmdXml.append("<StartAlarmTime>" + startTime + "</StartAlarmTime>\r\n");
  1267 + }
  1268 + if (!ObjectUtils.isEmpty(endTime)) {
  1269 + cmdXml.append("<EndAlarmTime>" + endTime + "</EndAlarmTime>\r\n");
  1270 + }
  1271 + cmdXml.append("</Query>\r\n");
  1272 +
  1273 + CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
  1274 + : udpSipProvider.getNewCallId();
  1275 +
  1276 + Request request = headerProvider.createSubscribeRequest(device, cmdXml.toString(), null, expires, "presence", callIdHeader);
  1277 + transmitRequest(device.getTransport(), request);
  1278 +
  1279 + }
  1280 +
  1281 + @Override
  1282 + public SIPRequest catalogSubscribe(Device device, SIPRequest requestOld, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException {
  1283 +
  1284 + StringBuffer cmdXml = new StringBuffer(200);
  1285 + String charset = device.getCharset();
  1286 + cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
  1287 + cmdXml.append("<Query>\r\n");
  1288 + cmdXml.append("<CmdType>Catalog</CmdType>\r\n");
  1289 + cmdXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");
  1290 + cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
  1291 + cmdXml.append("</Query>\r\n");
  1292 +
  1293 + CallIdHeader callIdHeader;
  1294 +
  1295 + if (requestOld != null) {
  1296 + callIdHeader = sipFactory.createHeaderFactory().createCallIdHeader(requestOld.getCallIdHeader().getCallId());
  1297 + } else {
  1298 + callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
  1299 + : udpSipProvider.getNewCallId();
  1300 + }
  1301 +
  1302 + // 有效时间默认为60秒以上
  1303 + SIPRequest request = (SIPRequest) headerProvider.createSubscribeRequest(device, cmdXml.toString(), requestOld, device.getSubscribeCycleForCatalog(), "Catalog",
  1304 + callIdHeader);
  1305 + transmitRequest(device.getTransport(), request, errorEvent, okEvent);
  1306 + return request;
  1307 + }
  1308 +
  1309 + @Override
  1310 + public void dragZoomCmd(Device device, String channelId, String cmdString) throws InvalidArgumentException, SipException, ParseException {
  1311 +
  1312 + StringBuffer dragXml = new StringBuffer(200);
  1313 + String charset = device.getCharset();
  1314 + dragXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
  1315 + dragXml.append("<Control>\r\n");
  1316 + dragXml.append("<CmdType>DeviceControl</CmdType>\r\n");
  1317 + dragXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");
  1318 + if (ObjectUtils.isEmpty(channelId)) {
  1319 + dragXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
  1320 + } else {
  1321 + dragXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
  1322 + }
  1323 + dragXml.append(cmdString);
  1324 + dragXml.append("</Control>\r\n");
  1325 + CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
  1326 + : udpSipProvider.getNewCallId();
  1327 + Request request = headerProvider.createMessageRequest(device, dragXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null, callIdHeader);
  1328 + logger.debug("拉框信令: " + request.toString());
  1329 + transmitRequest(device.getTransport(), request);
  1330 + }
  1331 +
  1332 +
  1333 + @Override
  1334 + public void transmitRequest(String transport, Request request) throws SipException, ParseException {
  1335 + transmitRequest(transport, request, null, null);
  1336 + }
  1337 +
  1338 + @Override
  1339 + public void transmitRequest(String transport, Request request, SipSubscribe.Event errorEvent) throws SipException, ParseException {
  1340 + transmitRequest(transport, request, errorEvent, null);
  1341 + }
  1342 +
  1343 + @Override
  1344 + public void transmitRequest(String transport, Request request, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws SipException, ParseException {
  1345 +
  1346 + if (request.getHeader(UserAgentHeader.NAME) == null) {
  1347 + try {
  1348 + request.addHeader(SipUtils.createUserAgentHeader(sipFactory, gitUtil));
  1349 + } catch (ParseException e) {
  1350 + logger.error("添加UserAgentHeader失败", e);
  1351 + }
  1352 + }
  1353 +
  1354 + CallIdHeader callIdHeader = (CallIdHeader) request.getHeader(CallIdHeader.NAME);
  1355 + // 添加错误订阅
  1356 + if (errorEvent != null) {
  1357 + sipSubscribe.addErrorSubscribe(callIdHeader.getCallId(), (eventResult -> {
  1358 + errorEvent.response(eventResult);
  1359 + sipSubscribe.removeErrorSubscribe(eventResult.callId);
  1360 + sipSubscribe.removeOkSubscribe(eventResult.callId);
  1361 + }));
  1362 + }
  1363 + // 添加订阅
  1364 + if (okEvent != null) {
  1365 + sipSubscribe.addOkSubscribe(callIdHeader.getCallId(), eventResult -> {
  1366 + okEvent.response(eventResult);
  1367 + sipSubscribe.removeOkSubscribe(eventResult.callId);
  1368 + sipSubscribe.removeErrorSubscribe(eventResult.callId);
  1369 + });
  1370 + }
  1371 + if ("TCP".equals(transport)) {
  1372 + tcpSipProvider.sendRequest(request);
  1373 + } else if ("UDP".equals(transport)) {
  1374 + udpSipProvider.sendRequest(request);
  1375 + }
  1376 +
  1377 + }
  1378 +
  1379 +
  1380 + /**
  1381 + * 回放暂停
  1382 + */
  1383 + @Override
  1384 + public void playPauseCmd(Device device, StreamInfo streamInfo) throws InvalidArgumentException, ParseException, SipException {
  1385 + StringBuffer content = new StringBuffer(200);
  1386 + content.append("PAUSE RTSP/1.0\r\n");
  1387 + content.append("CSeq: " + getInfoCseq() + "\r\n");
  1388 + content.append("PauseTime: now\r\n");
  1389 +
  1390 + playbackControlCmd(device, streamInfo, content.toString(), null, null);
  1391 + }
  1392 +
  1393 +
  1394 + /**
  1395 + * 回放恢复
  1396 + */
  1397 + @Override
  1398 + public void playResumeCmd(Device device, StreamInfo streamInfo) throws InvalidArgumentException, ParseException, SipException {
  1399 + StringBuffer content = new StringBuffer(200);
  1400 + content.append("PLAY RTSP/1.0\r\n");
  1401 + content.append("CSeq: " + getInfoCseq() + "\r\n");
  1402 + content.append("Range: npt=now-\r\n");
  1403 +
  1404 + playbackControlCmd(device, streamInfo, content.toString(), null, null);
  1405 + }
  1406 +
  1407 + /**
  1408 + * 回放拖动播放
  1409 + */
  1410 + @Override
  1411 + public void playSeekCmd(Device device, StreamInfo streamInfo, long seekTime) throws InvalidArgumentException, ParseException, SipException {
  1412 + StringBuffer content = new StringBuffer(200);
  1413 + content.append("PLAY RTSP/1.0\r\n");
  1414 + content.append("CSeq: " + getInfoCseq() + "\r\n");
  1415 + content.append("Range: npt=" + Math.abs(seekTime) + "-\r\n");
  1416 +
  1417 + playbackControlCmd(device, streamInfo, content.toString(), null, null);
  1418 + }
  1419 +
  1420 + /**
  1421 + * 回放倍速播放
  1422 + */
  1423 + @Override
  1424 + public void playSpeedCmd(Device device, StreamInfo streamInfo, Double speed) throws InvalidArgumentException, ParseException, SipException {
  1425 + StringBuffer content = new StringBuffer(200);
  1426 + content.append("PLAY RTSP/1.0\r\n");
  1427 + content.append("CSeq: " + getInfoCseq() + "\r\n");
  1428 + content.append("Scale: " + String.format("%.6f", speed) + "\r\n");
  1429 +
  1430 + playbackControlCmd(device, streamInfo, content.toString(), null, null);
  1431 + }
  1432 +
  1433 + private int getInfoCseq() {
  1434 + return (int) ((Math.random() * 9 + 1) * Math.pow(10, 8));
  1435 + }
  1436 +
  1437 + @Override
  1438 + public void playbackControlCmd(Device device, StreamInfo streamInfo, String content, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws SipException, InvalidArgumentException, ParseException {
  1439 +
  1440 + SsrcTransaction ssrcTransaction = streamSession.getSsrcTransaction(device.getDeviceId(), streamInfo.getChannelId(), null, streamInfo.getStream());
  1441 + if (ssrcTransaction == null) {
  1442 + logger.info("[回放控制]未找到视频流信息,设备:{}, 流ID: {}", device.getDeviceId(), streamInfo.getStream());
  1443 + return;
  1444 + }
  1445 +
  1446 + SIPRequest request = headerProvider.createInfoRequest(device, streamInfo.getChannelId(), content.toString(), ssrcTransaction.getSipTransactionInfo());
  1447 + if (request == null) {
  1448 + logger.info("[回放控制]构建Request信息失败,设备:{}, 流ID: {}", device.getDeviceId(), streamInfo.getStream());
  1449 + return;
  1450 + }
  1451 +
  1452 + transmitRequest(device.getTransport(), request, errorEvent, okEvent);
  1453 + }
  1454 +
  1455 + @Override
  1456 + public void sendAlarmMessage(Device device, DeviceAlarm deviceAlarm) throws InvalidArgumentException, SipException, ParseException {
  1457 + if (device == null) {
  1458 + return;
  1459 + }
  1460 + logger.info("[发送 报警通知] {}/{}->{},{}", device.getDeviceId(), deviceAlarm.getChannelId(),
  1461 + deviceAlarm.getLongitude(), deviceAlarm.getLatitude());
  1462 +
  1463 + String characterSet = device.getCharset();
  1464 + StringBuffer deviceStatusXml = new StringBuffer(600);
  1465 + deviceStatusXml.append("<?xml version=\"1.0\" encoding=\"" + characterSet + "\"?>\r\n");
  1466 + deviceStatusXml.append("<Notify>\r\n");
  1467 + deviceStatusXml.append("<CmdType>Alarm</CmdType>\r\n");
  1468 + deviceStatusXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");
  1469 + deviceStatusXml.append("<DeviceID>" + deviceAlarm.getChannelId() + "</DeviceID>\r\n");
  1470 + deviceStatusXml.append("<AlarmPriority>" + deviceAlarm.getAlarmPriority() + "</AlarmPriority>\r\n");
  1471 + deviceStatusXml.append("<AlarmMethod>" + deviceAlarm.getAlarmMethod() + "</AlarmMethod>\r\n");
  1472 + deviceStatusXml.append("<AlarmTime>" + deviceAlarm.getAlarmTime() + "</AlarmTime>\r\n");
  1473 + deviceStatusXml.append("<AlarmDescription>" + deviceAlarm.getAlarmDescription() + "</AlarmDescription>\r\n");
  1474 + deviceStatusXml.append("<Longitude>" + deviceAlarm.getLongitude() + "</Longitude>\r\n");
  1475 + deviceStatusXml.append("<Latitude>" + deviceAlarm.getLatitude() + "</Latitude>\r\n");
  1476 + deviceStatusXml.append("<info>\r\n");
  1477 + deviceStatusXml.append("<AlarmType>" + deviceAlarm.getAlarmType() + "</AlarmType>\r\n");
  1478 + deviceStatusXml.append("</info>\r\n");
  1479 + deviceStatusXml.append("</Notify>\r\n");
  1480 +
  1481 + CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
  1482 + : udpSipProvider.getNewCallId();
  1483 + Request request = headerProvider.createMessageRequest(device, deviceStatusXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null, callIdHeader);
  1484 + transmitRequest(device.getTransport(), request);
  1485 +
  1486 +
  1487 + }
1831 1488 }
... ...