Commit 2ff3cdb6a1550941dbd36585749499064db4f8d5

Authored by 648540858
2 parents d7a1b94f 30979eb6

Merge branch 'wvp-28181-2.0'

# Conflicts:
#	src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java
#	src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java
#	src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/SIPRequestProcessorParent.java
#	src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/AckRequestProcessor.java
#	src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java
#	src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/play/PlayController.java
Showing 22 changed files with 1810 additions and 2103 deletions

Too many changes to show.

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