Commit cd117ed22825b8f442e0f2281678f4549be3e109

Authored by 648540858
1 parent a574ff09

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

Too many changes to show.

To preserve performance only 18 of 53 files are displayed.

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