Commit b86f0aaae2f0212bc01ddfd3e5d646c22eb1d8c0

Authored by panll
Committed by Gitee
2 parents d8b24fc7 1fcdf5a8

!28 语音对讲合并

语音对讲合并
Showing 31 changed files with 2591 additions and 1814 deletions

Too many changes to show.

To preserve performance only 31 of 81 files are displayed.

README.md
@@ -134,3 +134,11 @@ https://gitee.com/pan648540858/wvp-GB28181-pro.git @@ -134,3 +134,11 @@ https://gitee.com/pan648540858/wvp-GB28181-pro.git
134 [mk1990](https://github.com/mk1990) [SaltFish001](https://github.com/SaltFish001) 134 [mk1990](https://github.com/mk1990) [SaltFish001](https://github.com/SaltFish001)
135 135
136 136
  137 +ffmpeg -re -i 123.mp3 -acodec pcm_alaw -ar 8000 -ac 1 -f rtsp rtsp://192.168.1.3:30554/broadcast/34020000001320000101_34020000001310000001
  138 +
  139 +ffmpeg -re -i 123.mp3 -acodec pcm_alaw -ar 8000 -ac 1 -f rtsp rtsp://192.168.1.3:30554/talk/34020000001320000011_34020000001370000001
  140 +
  141 +
  142 +
  143 +ffmpeg -re -i 123.mp3 -acodec pcm_alaw -ar 8000 -ac 1 -f rtsp rtsp://192.168.1.3:30554/talk/34020000001320000101_34020000001310000001
  144 +
doc/README.md
@@ -56,7 +56,7 @@ @@ -56,7 +56,7 @@
56 - [X] 报警订阅 56 - [X] 报警订阅
57 - [X] 目录订阅 57 - [X] 目录订阅
58 - [ ] 语音广播 58 - [ ] 语音广播
59 -- [ ] 语音对讲 59 +- [ ] 语音喊话
60 60
61 **作为下级平台** 61 **作为下级平台**
62 - [X] 注册 62 - [X] 注册
@@ -95,7 +95,7 @@ @@ -95,7 +95,7 @@
95 - [ ] 报警订阅 95 - [ ] 报警订阅
96 - [X] 目录订阅 96 - [X] 目录订阅
97 - [ ] 语音广播 97 - [ ] 语音广播
98 -- [ ] 语音对讲 98 +- [ ] 语音喊话
99 99
100 100
101 101
doc/_content/broadcast.md 0 → 100644
  1 +# 原理图
  2 +
  3 +## 使用ffmpeg测试语音对讲原理
  4 +```plantuml
  5 +@startuml
  6 +"FFMPEG" -> "ZLMediaKit": 推流到zlm
  7 +"WVP-PRO" <- "ZLMediaKit": 通知收到语音对讲推流,携带设备和通道信息
  8 +"WVP-PRO" -> "设备": 开始语音对讲
  9 +"WVP-PRO" <-- "设备": 语音对讲建立成功,携带收流端口
  10 +"WVP-PRO" -> "ZLMediaKit": 通知zlm将流推送到设备收流端口
  11 +"ZLMediaKit" -> "设备": 向设备推流
  12 +@enduml
  13 +```
  14 +
  15 +## 使用网页测试语音对讲原理
  16 +```plantuml
  17 +@startuml
  18 +"前端页面" -> "WVP-PRO": 请求推流地址
  19 +"前端页面" <-- "WVP-PRO": 返回推流地址
  20 +"前端页面" -> "ZLMediaKit": 使用webrtc推流到zlm,以下过程相同
  21 +"WVP-PRO" <- "ZLMediaKit": 通知收到语音对讲推流,携带设备和通道信息
  22 +"WVP-PRO" -> "设备": 开始语音对讲
  23 +"WVP-PRO" <-- "设备": 语音对讲建立成功,携带收流端口
  24 +"WVP-PRO" -> "ZLMediaKit": 通知zlm将流推送到设备收流端口
  25 +"ZLMediaKit" -> "设备": 向设备推流
  26 +@enduml
  27 +```
0 \ No newline at end of file 28 \ No newline at end of file
doc/_content/introduction/deployment.md
@@ -21,9 +21,9 @@ @@ -21,9 +21,9 @@
21 4. WVP-PRO与ZLM支持分开部署,但是wvp-pro-assist必须与zlm部署在同一台主机; 21 4. WVP-PRO与ZLM支持分开部署,但是wvp-pro-assist必须与zlm部署在同一台主机;
22 5. 生产环境按需开放端口,但是建议修改默认端口,尤其是5060端口,易受到攻击; 22 5. 生产环境按需开放端口,但是建议修改默认端口,尤其是5060端口,易受到攻击;
23 6. zlm使用docker部署的情况,要求端口映射一致,比如映射5060,应将外部端口也映射为5060端口; 23 6. zlm使用docker部署的情况,要求端口映射一致,比如映射5060,应将外部端口也映射为5060端口;
24 -7. 启动服务,以linux为例  
25 -### 启动WVP-PRO  
26 -**jar包:** 24 +7. zlm与wvp会保持高频率的通信,所以不要去将wvp与zlm分属在两个网络,比如wvp在内网,zlm却在公网的情况。
  25 +8. 启动服务,以linux为例
  26 +**启动WVP-PRO**
27 ```shell 27 ```shell
28 nohup java -jar wvp-pro-*.jar & 28 nohup java -jar wvp-pro-*.jar &
29 ``` 29 ```
doc/_content/theory/broadcast_cascade.md 0 → 100644
  1 +<!-- 点播流程 -->
  2 +
  3 +# 点播流程
  4 +> 以下为WVP-PRO级联语音喊话流程。
  5 +
  6 +```plantuml
  7 +@startuml
  8 +"上级平台" -> "下级平台": 1. 发起语音喊话请求
  9 +"上级平台" <-- "下级平台": 2. 200OK
  10 +"上级平台" <- "下级平台": 3. 回复Result OK
  11 +"上级平台" --> "下级平台": 4. 200OK
  12 +
  13 +"下级平台" -> "设备": 5. 发起语音喊话请求
  14 +"下级平台" <-- "设备": 6. 200OK
  15 +"下级平台" <- "设备": 7. 回复Result OK
  16 +"下级平台" --> "设备": 8. 200OK
  17 +
  18 +"下级平台" <- "设备": 9. invite(broadcast)
  19 +"下级平台" --> "设备": 10. 100 trying
  20 +"下级平台" --> "设备": 11. 200OK SDP
  21 +"下级平台" <-- "设备": 12. ack
  22 +
  23 +"上级平台" <- "下级平台": 13. invite(broadcast)
  24 +"上级平台" --> "下级平台": 14. 100 trying
  25 +"上级平台" --> "下级平台": 15. 200OK SDP
  26 +"上级平台" <-- "下级平台": 16. ack
  27 +
  28 +"上级平台" -> "下级平台": 17. 推送RTP
  29 +"下级平台" -> "设备": 18. 推送RTP
  30 +
  31 +@enduml
  32 +```
  33 +
  34 +
  35 +## 注册流程描述如下:
  36 +1. 用户从网页或调用接口发起点播请求;
  37 +2. WVP-PRO向摄像机发送Invite消息,消息头域中携带 Subject字段,表明点播的视频源ID、发送方媒体流序列号、ZLMediaKit接收流使用的IP、端口号、
  38 + 接收端媒体流序列号等参数,SDP消息体中 s字段为“Play”代表实时点播,y字段描述SSRC值,f字段描述媒体参数。
  39 +3. 摄像机向WVP-PRO回复200OK,消息体中描述了媒体流发送者发送媒体流的IP、端口、媒体格式、SSRC字段等内容。
  40 +4. WVP-PRO向设备回复Ack, 会话建立成功。
  41 +5. 设备向ZLMediaKit发送实时流。
  42 +6. ZLMediaKit向WVP-PRO发送流改变事件。
  43 +7. WVP-PRO向WEB用户回复播放地址。
  44 +8. ZLMediaKit向WVP发送流无人观看事件。
  45 +9. WVP-PRO向设备回复Bye, 结束会话。
  46 +10. 设备回复200OK,会话结束成功。
doc/_sidebar.md
@@ -20,6 +20,7 @@ @@ -20,6 +20,7 @@
20 * [树形结构](_content/theory/channel_tree.md) 20 * [树形结构](_content/theory/channel_tree.md)
21 * [注册流程](_content/theory/register.md) 21 * [注册流程](_content/theory/register.md)
22 * [点播流程](_content/theory/play.md) 22 * [点播流程](_content/theory/play.md)
  23 + * [级联语音喊话流程](_content/theory/broadcast_cascade.md)
23 * **必备技巧** 24 * **必备技巧**
24 * [抓包](_content/skill/tcpdump.md) 25 * [抓包](_content/skill/tcpdump.md)
25 26
src/main/java/com/genersoft/iot/vmp/common/InviteSessionType.java
@@ -3,5 +3,7 @@ package com.genersoft.iot.vmp.common; @@ -3,5 +3,7 @@ package com.genersoft.iot.vmp.common;
3 public enum InviteSessionType { 3 public enum InviteSessionType {
4 PLAY, 4 PLAY,
5 PLAYBACK, 5 PLAYBACK,
6 - DOWNLOAD 6 + DOWNLOAD,
  7 + BROADCAST,
  8 + TALK
7 } 9 }
src/main/java/com/genersoft/iot/vmp/common/StreamInfo.java
@@ -240,11 +240,11 @@ public class StreamInfo implements Serializable, Cloneable{ @@ -240,11 +240,11 @@ public class StreamInfo implements Serializable, Cloneable{
240 } 240 }
241 } 241 }
242 242
243 - public void setRtc(String host, int port, int sslPort, String app, String stream, String callIdParam) { 243 + public void setRtc(String host, int port, int sslPort, String app, String stream, String callIdParam, boolean isPlay) {
244 if (callIdParam != null) { 244 if (callIdParam != null) {
245 callIdParam = Objects.equals(callIdParam, "") ? callIdParam : callIdParam.replace("?", "&"); 245 callIdParam = Objects.equals(callIdParam, "") ? callIdParam : callIdParam.replace("?", "&");
246 } 246 }
247 - String file = String.format("index/api/webrtc?app=%s&stream=%s&type=play%s", app, stream, callIdParam); 247 + String file = String.format("index/api/webrtc?app=%s&stream=%s&type=%s%s", app, stream, isPlay?"play":"push", callIdParam);
248 if (port > 0) { 248 if (port > 0) {
249 this.rtc = new StreamURL("http", host, port, file); 249 this.rtc = new StreamURL("http", host, port, file);
250 } 250 }
src/main/java/com/genersoft/iot/vmp/common/VideoManagerConstants.java
@@ -68,6 +68,7 @@ public class VideoManagerConstants { @@ -68,6 +68,7 @@ public class VideoManagerConstants {
68 public static final String SYSTEM_INFO_NET_PREFIX = "VMP_SYSTEM_INFO_NET_"; 68 public static final String SYSTEM_INFO_NET_PREFIX = "VMP_SYSTEM_INFO_NET_";
69 69
70 public static final String SYSTEM_INFO_DISK_PREFIX = "VMP_SYSTEM_INFO_DISK_"; 70 public static final String SYSTEM_INFO_DISK_PREFIX = "VMP_SYSTEM_INFO_DISK_";
  71 + public static final String BROADCAST_WAITE_INVITE = "task_broadcast_waite_invite_";
71 72
72 public static final String REGISTER_EXPIRE_TASK_KEY_PREFIX = "VMP_device_register_expire_"; 73 public static final String REGISTER_EXPIRE_TASK_KEY_PREFIX = "VMP_device_register_expire_";
73 public static final String PUSH_STREAM_LIST = "VMP_PUSH_STREAM_LIST_"; 74 public static final String PUSH_STREAM_LIST = "VMP_PUSH_STREAM_LIST_";
src/main/java/com/genersoft/iot/vmp/conf/GlobalResponseAdvice.java
@@ -32,7 +32,7 @@ public class GlobalResponseAdvice implements ResponseBodyAdvice&lt;Object&gt; { @@ -32,7 +32,7 @@ public class GlobalResponseAdvice implements ResponseBodyAdvice&lt;Object&gt; {
32 @Override 32 @Override
33 public Object beforeBodyWrite(Object body, @NotNull MethodParameter returnType, @NotNull MediaType selectedContentType, @NotNull Class<? extends HttpMessageConverter<?>> selectedConverterType, @NotNull ServerHttpRequest request, @NotNull ServerHttpResponse response) { 33 public Object beforeBodyWrite(Object body, @NotNull MethodParameter returnType, @NotNull MediaType selectedContentType, @NotNull Class<? extends HttpMessageConverter<?>> selectedConverterType, @NotNull ServerHttpRequest request, @NotNull ServerHttpResponse response) {
34 // 排除api文档的接口,这个接口不需要统一 34 // 排除api文档的接口,这个接口不需要统一
35 - String[] excludePath = {"/v3/api-docs","/api/v1","/index/hook"}; 35 + String[] excludePath = {"/v3/api-docs","/api/v1","/index/hook","/api/video-"};
36 for (String path : excludePath) { 36 for (String path : excludePath) {
37 if (request.getURI().getPath().startsWith(path)) { 37 if (request.getURI().getPath().startsWith(path)) {
38 return body; 38 return body;
@@ -59,8 +59,8 @@ public class GlobalResponseAdvice implements ResponseBodyAdvice&lt;Object&gt; { @@ -59,8 +59,8 @@ public class GlobalResponseAdvice implements ResponseBodyAdvice&lt;Object&gt; {
59 * 防止返回string时出错 59 * 防止返回string时出错
60 * @return 60 * @return
61 */ 61 */
62 - @Bean  
63 - public HttpMessageConverters fast() { 62 + /*@Bean
  63 + public HttpMessageConverters custHttpMessageConverter() {
64 return new HttpMessageConverters(new FastJsonHttpMessageConverter()); 64 return new HttpMessageConverters(new FastJsonHttpMessageConverter());
65 - } 65 + }*/
66 } 66 }
src/main/java/com/genersoft/iot/vmp/conf/MediaConfig.java
@@ -97,7 +97,7 @@ public class MediaConfig{ @@ -97,7 +97,7 @@ public class MediaConfig{
97 97
98 public String getHookIp() { 98 public String getHookIp() {
99 if (ObjectUtils.isEmpty(hookIp)){ 99 if (ObjectUtils.isEmpty(hookIp)){
100 - return sipIp.split(",")[0]; 100 + return sipIp;
101 }else { 101 }else {
102 return hookIp; 102 return hookIp;
103 } 103 }
src/main/java/com/genersoft/iot/vmp/conf/UserSetting.java
@@ -33,7 +33,7 @@ public class UserSetting { @@ -33,7 +33,7 @@ public class UserSetting {
33 33
34 private Boolean logInDatabase = Boolean.TRUE; 34 private Boolean logInDatabase = Boolean.TRUE;
35 35
36 - private Boolean usePushingAsStatus = Boolean.TRUE; 36 + private Boolean usePushingAsStatus = Boolean.FALSE;
37 37
38 private Boolean useSourceIpAsStreamIp = Boolean.FALSE; 38 private Boolean useSourceIpAsStreamIp = Boolean.FALSE;
39 39
@@ -58,6 +58,8 @@ public class UserSetting { @@ -58,6 +58,8 @@ public class UserSetting {
58 58
59 private String thirdPartyGBIdReg = "[\\s\\S]*"; 59 private String thirdPartyGBIdReg = "[\\s\\S]*";
60 60
  61 + private String broadcastForPlatform = "UDP";
  62 +
61 private String civilCodeFile = "classpath:civilCode.csv"; 63 private String civilCodeFile = "classpath:civilCode.csv";
62 64
63 private List<String> interfaceAuthenticationExcludes = new ArrayList<>(); 65 private List<String> interfaceAuthenticationExcludes = new ArrayList<>();
@@ -210,6 +212,14 @@ public class UserSetting { @@ -210,6 +212,14 @@ public class UserSetting {
210 this.syncChannelOnDeviceOnline = syncChannelOnDeviceOnline; 212 this.syncChannelOnDeviceOnline = syncChannelOnDeviceOnline;
211 } 213 }
212 214
  215 + public String getBroadcastForPlatform() {
  216 + return broadcastForPlatform;
  217 + }
  218 +
  219 + public void setBroadcastForPlatform(String broadcastForPlatform) {
  220 + this.broadcastForPlatform = broadcastForPlatform;
  221 + }
  222 +
213 public Boolean getSipUseSourceIpAsRemoteAddress() { 223 public Boolean getSipUseSourceIpAsRemoteAddress() {
214 return sipUseSourceIpAsRemoteAddress; 224 return sipUseSourceIpAsRemoteAddress;
215 } 225 }
src/main/java/com/genersoft/iot/vmp/conf/redis/RedisConfig.java 0 → 100644
src/main/java/com/genersoft/iot/vmp/conf/security/dto/LoginUser.java
@@ -100,6 +100,9 @@ public class LoginUser implements UserDetails, CredentialsContainer { @@ -100,6 +100,9 @@ public class LoginUser implements UserDetails, CredentialsContainer {
100 return user.getRole(); 100 return user.getRole();
101 } 101 }
102 102
  103 + public String getPushKey() {
  104 + return user.getPushKey();
  105 + }
103 106
104 public String getAccessToken() { 107 public String getAccessToken() {
105 return accessToken; 108 return accessToken;
src/main/java/com/genersoft/iot/vmp/gb28181/bean/AudioBroadcastCatch.java 0 → 100644
  1 +package com.genersoft.iot.vmp.gb28181.bean;
  2 +
  3 +
  4 +import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
  5 +import com.genersoft.iot.vmp.vmanager.gb28181.play.bean.AudioBroadcastEvent;
  6 +import gov.nist.javax.sip.message.SIPResponse;
  7 +
  8 +/**
  9 + * 缓存语音广播的状态
  10 + * @author lin
  11 + */
  12 +public class AudioBroadcastCatch {
  13 +
  14 +
  15 + public AudioBroadcastCatch(
  16 + String deviceId,
  17 + String channelId,
  18 + MediaServerItem mediaServerItem,
  19 + String app,
  20 + String stream,
  21 + AudioBroadcastEvent event,
  22 + AudioBroadcastCatchStatus status,
  23 + boolean isFromPlatform
  24 + ) {
  25 + this.deviceId = deviceId;
  26 + this.channelId = channelId;
  27 + this.status = status;
  28 + this.event = event;
  29 + this.isFromPlatform = isFromPlatform;
  30 + this.app = app;
  31 + this.stream = stream;
  32 + this.mediaServerItem = mediaServerItem;
  33 + }
  34 +
  35 + public AudioBroadcastCatch() {
  36 + }
  37 +
  38 + /**
  39 + * 设备编号
  40 + */
  41 + private String deviceId;
  42 +
  43 + /**
  44 + * 通道编号
  45 + */
  46 + private String channelId;
  47 +
  48 + /**
  49 + * 流媒体信息
  50 + */
  51 + private MediaServerItem mediaServerItem;
  52 +
  53 + /**
  54 + * 关联的流APP
  55 + */
  56 + private String app;
  57 +
  58 + /**
  59 + * 关联的流STREAM
  60 + */
  61 + private String stream;
  62 +
  63 + /**
  64 + * 是否是级联语音喊话
  65 + */
  66 + private boolean isFromPlatform;
  67 +
  68 + /**
  69 + * 语音广播状态
  70 + */
  71 + private AudioBroadcastCatchStatus status;
  72 +
  73 + /**
  74 + * 请求信息
  75 + */
  76 + private SipTransactionInfo sipTransactionInfo;
  77 +
  78 + /**
  79 + * 请求结果回调
  80 + */
  81 + private AudioBroadcastEvent event;
  82 +
  83 +
  84 + public String getDeviceId() {
  85 + return deviceId;
  86 + }
  87 +
  88 + public void setDeviceId(String deviceId) {
  89 + this.deviceId = deviceId;
  90 + }
  91 +
  92 + public String getChannelId() {
  93 + return channelId;
  94 + }
  95 +
  96 + public void setChannelId(String channelId) {
  97 + this.channelId = channelId;
  98 + }
  99 +
  100 + public AudioBroadcastCatchStatus getStatus() {
  101 + return status;
  102 + }
  103 +
  104 + public void setStatus(AudioBroadcastCatchStatus status) {
  105 + this.status = status;
  106 + }
  107 +
  108 + public SipTransactionInfo getSipTransactionInfo() {
  109 + return sipTransactionInfo;
  110 + }
  111 +
  112 + public MediaServerItem getMediaServerItem() {
  113 + return mediaServerItem;
  114 + }
  115 +
  116 + public void setMediaServerItem(MediaServerItem mediaServerItem) {
  117 + this.mediaServerItem = mediaServerItem;
  118 + }
  119 +
  120 + public String getApp() {
  121 + return app;
  122 + }
  123 +
  124 + public void setApp(String app) {
  125 + this.app = app;
  126 + }
  127 +
  128 + public String getStream() {
  129 + return stream;
  130 + }
  131 +
  132 + public void setStream(String stream) {
  133 + this.stream = stream;
  134 + }
  135 +
  136 + public boolean isFromPlatform() {
  137 + return isFromPlatform;
  138 + }
  139 +
  140 + public void setFromPlatform(boolean fromPlatform) {
  141 + isFromPlatform = fromPlatform;
  142 + }
  143 +
  144 + public void setSipTransactionInfo(SipTransactionInfo sipTransactionInfo) {
  145 + this.sipTransactionInfo = sipTransactionInfo;
  146 + }
  147 +
  148 + public AudioBroadcastEvent getEvent() {
  149 + return event;
  150 + }
  151 +
  152 + public void setEvent(AudioBroadcastEvent event) {
  153 + this.event = event;
  154 + }
  155 +
  156 + public void setSipTransactionInfoByRequset(SIPResponse sipResponse) {
  157 + this.sipTransactionInfo = new SipTransactionInfo(sipResponse);
  158 + }
  159 +}
src/main/java/com/genersoft/iot/vmp/gb28181/bean/AudioBroadcastCatchStatus.java 0 → 100644
  1 +package com.genersoft.iot.vmp.gb28181.bean;
  2 +
  3 +/**
  4 + * 语音广播状态
  5 + * @author lin
  6 + */
  7 +public enum AudioBroadcastCatchStatus {
  8 +
  9 + // 发送语音广播消息等待对方回复语音广播
  10 + Ready,
  11 + // 收到回复等待invite消息
  12 + WaiteInvite,
  13 + // 收到invite消息
  14 + Ok,
  15 +}
src/main/java/com/genersoft/iot/vmp/gb28181/bean/Device.java
@@ -188,8 +188,8 @@ public class Device { @@ -188,8 +188,8 @@ public class Device {
188 @Schema(description = "设备注册的事务信息") 188 @Schema(description = "设备注册的事务信息")
189 private SipTransactionInfo sipTransactionInfo; 189 private SipTransactionInfo sipTransactionInfo;
190 190
191 -  
192 - 191 + @Schema(description = "控制语音对讲流程,释放收到ACK后发流")
  192 + private boolean broadcastPushAfterAck;
193 193
194 public String getDeviceId() { 194 public String getDeviceId() {
195 return deviceId; 195 return deviceId;
@@ -452,5 +452,11 @@ public class Device { @@ -452,5 +452,11 @@ public class Device {
452 public void setSipTransactionInfo(SipTransactionInfo sipTransactionInfo) { 452 public void setSipTransactionInfo(SipTransactionInfo sipTransactionInfo) {
453 this.sipTransactionInfo = sipTransactionInfo; 453 this.sipTransactionInfo = sipTransactionInfo;
454 } 454 }
  455 + public boolean isBroadcastPushAfterAck() {
  456 + return broadcastPushAfterAck;
  457 + }
455 458
  459 + public void setBroadcastPushAfterAck(boolean broadcastPushAfterAck) {
  460 + this.broadcastPushAfterAck = broadcastPushAfterAck;
  461 + }
456 } 462 }
src/main/java/com/genersoft/iot/vmp/gb28181/bean/InviteStreamType.java
@@ -2,7 +2,7 @@ package com.genersoft.iot.vmp.gb28181.bean; @@ -2,7 +2,7 @@ package com.genersoft.iot.vmp.gb28181.bean;
2 2
3 public enum InviteStreamType { 3 public enum InviteStreamType {
4 4
5 - PLAY,PLAYBACK,DOWNLOAD,PUSH,PROXY,CLOUD_RECORD_PUSH,CLOUD_RECORD_PROXY 5 + PLAY,PLAYBACK,DOWNLOAD,PUSH,PROXY,CLOUD_RECORD_PUSH,CLOUD_RECORD_PROXY,BROADCAST,TALK
6 6
7 7
8 } 8 }
src/main/java/com/genersoft/iot/vmp/gb28181/bean/ParentPlatform.java
@@ -66,7 +66,7 @@ public class ParentPlatform { @@ -66,7 +66,7 @@ public class ParentPlatform {
66 * 设备端口 66 * 设备端口
67 */ 67 */
68 @Schema(description = "设备端口") 68 @Schema(description = "设备端口")
69 - private String devicePort; 69 + private int devicePort;
70 70
71 /** 71 /**
72 * SIP认证用户名(默认使用设备国标编号) 72 * SIP认证用户名(默认使用设备国标编号)
@@ -261,11 +261,11 @@ public class ParentPlatform { @@ -261,11 +261,11 @@ public class ParentPlatform {
261 this.deviceIp = deviceIp; 261 this.deviceIp = deviceIp;
262 } 262 }
263 263
264 - public String getDevicePort() { 264 + public int getDevicePort() {
265 return devicePort; 265 return devicePort;
266 } 266 }
267 267
268 - public void setDevicePort(String devicePort) { 268 + public void setDevicePort(int devicePort) {
269 this.devicePort = devicePort; 269 this.devicePort = devicePort;
270 } 270 }
271 271
src/main/java/com/genersoft/iot/vmp/gb28181/bean/SendRtpItem.java
@@ -49,7 +49,7 @@ public class SendRtpItem { @@ -49,7 +49,7 @@ public class SendRtpItem {
49 /** 49 /**
50 * 设备推流的streamId 50 * 设备推流的streamId
51 */ 51 */
52 - private String streamId; 52 + private String stream;
53 53
54 /** 54 /**
55 * 是否为tcp 55 * 是否为tcp
@@ -117,6 +117,11 @@ public class SendRtpItem { @@ -117,6 +117,11 @@ public class SendRtpItem {
117 */ 117 */
118 private InviteStreamType playType; 118 private InviteStreamType playType;
119 119
  120 + /**
  121 + * 发流的同时收流
  122 + */
  123 + private String receiveStream;
  124 +
120 public String getIp() { 125 public String getIp() {
121 return ip; 126 return ip;
122 } 127 }
@@ -181,12 +186,12 @@ public class SendRtpItem { @@ -181,12 +186,12 @@ public class SendRtpItem {
181 this.app = app; 186 this.app = app;
182 } 187 }
183 188
184 - public String getStreamId() {  
185 - return streamId; 189 + public String getStream() {
  190 + return stream;
186 } 191 }
187 192
188 - public void setStreamId(String streamId) {  
189 - this.streamId = streamId; 193 + public void setStream(String stream) {
  194 + this.stream = stream;
190 } 195 }
191 196
192 public boolean isTcp() { 197 public boolean isTcp() {
@@ -292,4 +297,12 @@ public class SendRtpItem { @@ -292,4 +297,12 @@ public class SendRtpItem {
292 public void setRtcp(boolean rtcp) { 297 public void setRtcp(boolean rtcp) {
293 this.rtcp = rtcp; 298 this.rtcp = rtcp;
294 } 299 }
  300 +
  301 + public String getReceiveStream() {
  302 + return receiveStream;
  303 + }
  304 +
  305 + public void setReceiveStream(String receiveStream) {
  306 + this.receiveStream = receiveStream;
  307 + }
295 } 308 }
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;  
4 import gov.nist.javax.sip.message.SIPResponse; 3 import gov.nist.javax.sip.message.SIPResponse;
5 4
6 public class SipTransactionInfo { 5 public class SipTransactionInfo {
@@ -10,11 +9,23 @@ public class SipTransactionInfo { @@ -10,11 +9,23 @@ public class SipTransactionInfo {
10 private String toTag; 9 private String toTag;
11 private String viaBranch; 10 private String viaBranch;
12 11
  12 + // 自己是否媒体流发送者
  13 + private boolean asSender;
  14 +
  15 + public SipTransactionInfo(SIPResponse response, boolean asSender) {
  16 + this.callId = response.getCallIdHeader().getCallId();
  17 + this.fromTag = response.getFromTag();
  18 + this.toTag = response.getToTag();
  19 + this.viaBranch = response.getTopmostViaHeader().getBranch();
  20 + this.asSender = asSender;
  21 + }
  22 +
13 public SipTransactionInfo(SIPResponse response) { 23 public SipTransactionInfo(SIPResponse response) {
14 this.callId = response.getCallIdHeader().getCallId(); 24 this.callId = response.getCallIdHeader().getCallId();
15 this.fromTag = response.getFromTag(); 25 this.fromTag = response.getFromTag();
16 this.toTag = response.getToTag(); 26 this.toTag = response.getToTag();
17 this.viaBranch = response.getTopmostViaHeader().getBranch(); 27 this.viaBranch = response.getTopmostViaHeader().getBranch();
  28 + this.asSender = false;
18 } 29 }
19 30
20 public SipTransactionInfo() { 31 public SipTransactionInfo() {
@@ -51,4 +62,12 @@ public class SipTransactionInfo { @@ -51,4 +62,12 @@ public class SipTransactionInfo {
51 public void setViaBranch(String viaBranch) { 62 public void setViaBranch(String viaBranch) {
52 this.viaBranch = viaBranch; 63 this.viaBranch = viaBranch;
53 } 64 }
  65 +
  66 + public boolean isAsSender() {
  67 + return asSender;
  68 + }
  69 +
  70 + public void setAsSender(boolean asSender) {
  71 + this.asSender = asSender;
  72 + }
54 } 73 }
src/main/java/com/genersoft/iot/vmp/gb28181/event/SipSubscribe.java
@@ -61,7 +61,7 @@ public class SipSubscribe { @@ -61,7 +61,7 @@ public class SipSubscribe {
61 logger.debug("errorSubscribes.size:{}",errorSubscribes.size()); 61 logger.debug("errorSubscribes.size:{}",errorSubscribes.size());
62 } 62 }
63 63
64 - public interface Event { void response(EventResult eventResult) ; 64 + public interface Event { void response(EventResult eventResult);
65 } 65 }
66 66
67 /** 67 /**
@@ -78,8 +78,10 @@ public class SipSubscribe { @@ -78,8 +78,10 @@ public class SipSubscribe {
78 dialogTerminated, 78 dialogTerminated,
79 // 设备未找到 79 // 设备未找到
80 deviceNotFoundEvent, 80 deviceNotFoundEvent,
81 - // 设备未找到  
82 - cmdSendFailEvent 81 + // 消息发送失败
  82 + cmdSendFailEvent,
  83 + // 消息发送失败
  84 + failedToGetPort
83 } 85 }
84 86
85 public static class EventResult<EventObject>{ 87 public static class EventResult<EventObject>{
src/main/java/com/genersoft/iot/vmp/gb28181/session/AudioBroadcastManager.java 0 → 100644
  1 +package com.genersoft.iot.vmp.gb28181.session;
  2 +
  3 +import com.genersoft.iot.vmp.conf.SipConfig;
  4 +import com.genersoft.iot.vmp.gb28181.bean.AudioBroadcastCatch;
  5 +import com.genersoft.iot.vmp.gb28181.utils.SipUtils;
  6 +import org.springframework.beans.factory.annotation.Autowired;
  7 +import org.springframework.stereotype.Component;
  8 +
  9 +import java.util.*;
  10 +import java.util.concurrent.ConcurrentHashMap;
  11 +import java.util.stream.Collectors;
  12 +import java.util.stream.Stream;
  13 +
  14 +/**
  15 + * 语音广播消息管理类
  16 + * @author lin
  17 + */
  18 +@Component
  19 +public class AudioBroadcastManager {
  20 +
  21 + @Autowired
  22 + private SipConfig config;
  23 +
  24 + public static Map<String, AudioBroadcastCatch> data = new ConcurrentHashMap<>();
  25 +
  26 + public void update(AudioBroadcastCatch audioBroadcastCatch) {
  27 + if (SipUtils.isFrontEnd(audioBroadcastCatch.getDeviceId())) {
  28 + data.put(audioBroadcastCatch.getDeviceId(), audioBroadcastCatch);
  29 + }else {
  30 + data.put(audioBroadcastCatch.getDeviceId() + audioBroadcastCatch.getChannelId(), audioBroadcastCatch);
  31 + }
  32 + }
  33 +
  34 + public void del(String deviceId, String channelId) {
  35 + if (SipUtils.isFrontEnd(deviceId)) {
  36 + data.remove(deviceId);
  37 + }else {
  38 + data.remove(deviceId + channelId);
  39 + }
  40 +
  41 + }
  42 +
  43 + public void delByDeviceId(String deviceId) {
  44 + for (String key : data.keySet()) {
  45 + if (key.startsWith(deviceId)) {
  46 + data.remove(key);
  47 + }
  48 + }
  49 + }
  50 +
  51 + public List<AudioBroadcastCatch> getAll(){
  52 + Collection<AudioBroadcastCatch> values = data.values();
  53 + return new ArrayList<>(values);
  54 + }
  55 +
  56 +
  57 + public boolean exit(String deviceId, String channelId) {
  58 + for (String key : data.keySet()) {
  59 + if (SipUtils.isFrontEnd(deviceId)) {
  60 + return key.equals(deviceId);
  61 + }else {
  62 + return key.equals(deviceId + channelId);
  63 + }
  64 + }
  65 + return false;
  66 + }
  67 +
  68 + public AudioBroadcastCatch get(String deviceId, String channelId) {
  69 + AudioBroadcastCatch audioBroadcastCatch;
  70 + if (SipUtils.isFrontEnd(deviceId)) {
  71 + audioBroadcastCatch = data.get(deviceId);
  72 + }else {
  73 + audioBroadcastCatch = data.get(deviceId + channelId);
  74 + }
  75 + if (audioBroadcastCatch == null) {
  76 + Stream<AudioBroadcastCatch> allAudioBroadcastCatchStreamForDevice = data.values().stream().filter(
  77 + audioBroadcastCatchItem -> Objects.equals(audioBroadcastCatchItem.getDeviceId(), deviceId));
  78 + List<AudioBroadcastCatch> audioBroadcastCatchList = allAudioBroadcastCatchStreamForDevice.collect(Collectors.toList());
  79 + if (audioBroadcastCatchList.size() == 1 && Objects.equals(config.getId(), channelId)) {
  80 + audioBroadcastCatch = audioBroadcastCatchList.get(0);
  81 + }
  82 + }
  83 +
  84 + return audioBroadcastCatch;
  85 + }
  86 +
  87 + public List<AudioBroadcastCatch> get(String deviceId) {
  88 + List<AudioBroadcastCatch> audioBroadcastCatchList= new ArrayList<>();
  89 + if (SipUtils.isFrontEnd(deviceId)) {
  90 + if (data.get(deviceId) != null) {
  91 + audioBroadcastCatchList.add(data.get(deviceId));
  92 + }
  93 + }else {
  94 + for (String key : data.keySet()) {
  95 + if (key.startsWith(deviceId)) {
  96 + audioBroadcastCatchList.add(data.get(key));
  97 + }
  98 + }
  99 + }
  100 +
  101 + return audioBroadcastCatchList;
  102 + }
  103 +}
src/main/java/com/genersoft/iot/vmp/gb28181/task/SipRunner.java
@@ -106,13 +106,13 @@ public class SipRunner implements CommandLineRunner { @@ -106,13 +106,13 @@ public class SipRunner implements CommandLineRunner {
106 if (sendRtpItems.size() > 0) { 106 if (sendRtpItems.size() > 0) {
107 for (SendRtpItem sendRtpItem : sendRtpItems) { 107 for (SendRtpItem sendRtpItem : sendRtpItems) {
108 MediaServerItem mediaServerItem = mediaServerService.getOne(sendRtpItem.getMediaServerId()); 108 MediaServerItem mediaServerItem = mediaServerService.getOne(sendRtpItem.getMediaServerId());
109 - redisCatchStorage.deleteSendRTPServer(sendRtpItem.getPlatformId(),sendRtpItem.getChannelId(), sendRtpItem.getCallId(),sendRtpItem.getStreamId()); 109 + redisCatchStorage.deleteSendRTPServer(sendRtpItem.getPlatformId(),sendRtpItem.getChannelId(), sendRtpItem.getCallId(),sendRtpItem.getStream());
110 if (mediaServerItem != null) { 110 if (mediaServerItem != null) {
111 ssrcFactory.releaseSsrc(sendRtpItem.getMediaServerId(), sendRtpItem.getSsrc()); 111 ssrcFactory.releaseSsrc(sendRtpItem.getMediaServerId(), sendRtpItem.getSsrc());
112 Map<String, Object> param = new HashMap<>(); 112 Map<String, Object> param = new HashMap<>();
113 param.put("vhost","__defaultVhost__"); 113 param.put("vhost","__defaultVhost__");
114 param.put("app",sendRtpItem.getApp()); 114 param.put("app",sendRtpItem.getApp());
115 - param.put("stream",sendRtpItem.getStreamId()); 115 + param.put("stream",sendRtpItem.getStream());
116 param.put("ssrc",sendRtpItem.getSsrc()); 116 param.put("ssrc",sendRtpItem.getSsrc());
117 JSONObject jsonObject = zlmresTfulUtils.stopSendRtp(mediaServerItem, param); 117 JSONObject jsonObject = zlmresTfulUtils.stopSendRtp(mediaServerItem, param);
118 if (jsonObject != null && jsonObject.getInteger("code") == 0) { 118 if (jsonObject != null && jsonObject.getInteger("code") == 0) {
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java
@@ -2,6 +2,7 @@ package com.genersoft.iot.vmp.gb28181.transmit.cmd; @@ -2,6 +2,7 @@ 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.conf.exception.SsrcTransactionNotFoundException;
  5 +import com.genersoft.iot.vmp.gb28181.bean.*;
5 import com.genersoft.iot.vmp.gb28181.bean.Device; 6 import com.genersoft.iot.vmp.gb28181.bean.Device;
6 import com.genersoft.iot.vmp.gb28181.bean.DeviceAlarm; 7 import com.genersoft.iot.vmp.gb28181.bean.DeviceAlarm;
7 import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; 8 import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
@@ -124,13 +125,19 @@ public interface ISIPCommander { @@ -124,13 +125,19 @@ public interface ISIPCommander {
124 String startTime, String endTime, int downloadSpeed, ZlmHttpHookSubscribe.Event hookEvent, 125 String startTime, String endTime, int downloadSpeed, ZlmHttpHookSubscribe.Event hookEvent,
125 SipSubscribe.Event errorEvent,SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException; 126 SipSubscribe.Event errorEvent,SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException;
126 127
  128 +
127 /** 129 /**
128 * 视频流停止 130 * 视频流停止
129 */ 131 */
130 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, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException, SsrcTransactionNotFoundException;
131 133
  134 + void talkStreamCmd(MediaServerItem mediaServerItem, SendRtpItem sendRtpItem, Device device, String channelId, String callId, ZlmHttpHookSubscribe.Event event, ZlmHttpHookSubscribe.Event eventForPush, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException;
  135 +
  136 +
132 void streamByeCmd(Device device, String channelId, String stream, String callId) throws InvalidArgumentException, ParseException, SipException, SsrcTransactionNotFoundException; 137 void streamByeCmd(Device device, String channelId, String stream, String callId) throws InvalidArgumentException, ParseException, SipException, SsrcTransactionNotFoundException;
133 138
  139 + void streamByeCmd(Device device, String channelId, SipTransactionInfo sipTransactionInfo, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException, SsrcTransactionNotFoundException;
  140 +
134 /** 141 /**
135 * 回放暂停 142 * 回放暂停
136 */ 143 */
@@ -160,22 +167,16 @@ public interface ISIPCommander { @@ -160,22 +167,16 @@ public interface ISIPCommander {
160 void playbackControlCmd(Device device, StreamInfo streamInfo, String content,SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws SipException, InvalidArgumentException, ParseException; 167 void playbackControlCmd(Device device, StreamInfo streamInfo, String content,SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws SipException, InvalidArgumentException, ParseException;
161 168
162 169
  170 + void streamByeCmdForDeviceInvite(Device device, String channelId, SipTransactionInfo sipTransactionInfo, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException, SsrcTransactionNotFoundException;
  171 +
163 /** 172 /**
  173 + * /**
164 * 语音广播 174 * 语音广播
165 - *  
166 - * @param device 视频设备  
167 - * @param channelId 预览通道  
168 - */  
169 - void audioBroadcastCmd(Device device,String channelId);  
170 -  
171 - /**  
172 - * 语音广播  
173 - *  
174 - * @param device 视频设备 175 + *
  176 + * @param device 视频设备
175 */ 177 */
176 - void audioBroadcastCmd(Device device, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException;  
177 - void audioBroadcastCmd(Device device) throws InvalidArgumentException, SipException, ParseException;  
178 - 178 + void audioBroadcastCmd(Device device, String channelId, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException;
  179 +
179 /** 180 /**
180 * 音视频录像控制 181 * 音视频录像控制
181 * 182 *
@@ -362,4 +363,5 @@ public interface ISIPCommander { @@ -362,4 +363,5 @@ public interface ISIPCommander {
362 */ 363 */
363 void sendAlarmMessage(Device device, DeviceAlarm deviceAlarm) throws InvalidArgumentException, SipException, ParseException; 364 void sendAlarmMessage(Device device, DeviceAlarm deviceAlarm) throws InvalidArgumentException, SipException, ParseException;
364 365
  366 +
365 } 367 }
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommanderForPlatform.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.conf.exception.SsrcTransactionNotFoundException;
3 import com.genersoft.iot.vmp.gb28181.bean.*; 4 import com.genersoft.iot.vmp.gb28181.bean.*;
4 import com.genersoft.iot.vmp.gb28181.event.SipSubscribe; 5 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.dto.MediaServerItem;
5 import com.genersoft.iot.vmp.service.bean.GPSMsgInfo; 8 import com.genersoft.iot.vmp.service.bean.GPSMsgInfo;
  9 +import com.genersoft.iot.vmp.service.bean.SSRCInfo;
6 10
7 import javax.sip.InvalidArgumentException; 11 import javax.sip.InvalidArgumentException;
8 import javax.sip.SipException; 12 import javax.sip.SipException;
@@ -14,6 +18,7 @@ public interface ISIPCommanderForPlatform { @@ -14,6 +18,7 @@ public interface ISIPCommanderForPlatform {
14 18
15 /** 19 /**
16 * 向上级平台注册 20 * 向上级平台注册
  21 + *
17 * @param parentPlatform 22 * @param parentPlatform
18 * @return 23 * @return
19 */ 24 */
@@ -26,6 +31,7 @@ public interface ISIPCommanderForPlatform { @@ -26,6 +31,7 @@ public interface ISIPCommanderForPlatform {
26 31
27 /** 32 /**
28 * 向上级平台注销 33 * 向上级平台注销
  34 + *
29 * @param parentPlatform 35 * @param parentPlatform
30 * @return 36 * @return
31 */ 37 */
@@ -34,26 +40,33 @@ public interface ISIPCommanderForPlatform { @@ -34,26 +40,33 @@ public interface ISIPCommanderForPlatform {
34 40
35 /** 41 /**
36 * 向上级平发送心跳信息 42 * 向上级平发送心跳信息
  43 + *
37 * @param parentPlatform 44 * @param parentPlatform
38 * @return callId(作为接受回复的判定) 45 * @return callId(作为接受回复的判定)
39 */ 46 */
40 - String keepalive(ParentPlatform parentPlatform,SipSubscribe.Event errorEvent , SipSubscribe.Event okEvent) throws SipException, InvalidArgumentException, ParseException; 47 + String keepalive(ParentPlatform parentPlatform, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent)
  48 + throws SipException, InvalidArgumentException, ParseException;
41 49
42 50
43 /** 51 /**
44 * 向上级回复通道信息 52 * 向上级回复通道信息
45 - * @param channel 通道信息 53 + *
  54 + * @param channel 通道信息
46 * @param parentPlatform 平台信息 55 * @param parentPlatform 平台信息
47 * @param sn 56 * @param sn
48 * @param fromTag 57 * @param fromTag
49 * @param size 58 * @param size
50 * @return 59 * @return
51 */ 60 */
52 - void catalogQuery(DeviceChannel channel, ParentPlatform parentPlatform, String sn, String fromTag, int size) throws SipException, InvalidArgumentException, ParseException;  
53 - void catalogQuery(List<DeviceChannel> channels, ParentPlatform parentPlatform, String sn, String fromTag) throws InvalidArgumentException, ParseException, SipException; 61 + void catalogQuery(DeviceChannel channel, ParentPlatform parentPlatform, String sn, String fromTag, int size)
  62 + throws SipException, InvalidArgumentException, ParseException;
  63 +
  64 + void catalogQuery(List<DeviceChannel> channels, ParentPlatform parentPlatform, String sn, String fromTag)
  65 + throws InvalidArgumentException, ParseException, SipException;
54 66
55 /** 67 /**
56 * 向上级回复DeviceInfo查询信息 68 * 向上级回复DeviceInfo查询信息
  69 + *
57 * @param parentPlatform 平台信息 70 * @param parentPlatform 平台信息
58 * @param sn SN 71 * @param sn SN
59 * @param fromTag FROM头的tag信息 72 * @param fromTag FROM头的tag信息
@@ -63,6 +76,7 @@ public interface ISIPCommanderForPlatform { @@ -63,6 +76,7 @@ public interface ISIPCommanderForPlatform {
63 76
64 /** 77 /**
65 * 向上级回复DeviceStatus查询信息 78 * 向上级回复DeviceStatus查询信息
  79 + *
66 * @param parentPlatform 平台信息 80 * @param parentPlatform 平台信息
67 * @param sn 81 * @param sn
68 * @param fromTag 82 * @param fromTag
@@ -72,23 +86,27 @@ public interface ISIPCommanderForPlatform { @@ -72,23 +86,27 @@ public interface ISIPCommanderForPlatform {
72 86
73 /** 87 /**
74 * 向上级回复移动位置订阅消息 88 * 向上级回复移动位置订阅消息
  89 + *
75 * @param parentPlatform 平台信息 90 * @param parentPlatform 平台信息
76 - * @param gpsMsgInfo GPS信息  
77 - * @param subscribeInfo 订阅相关的信息 91 + * @param gpsMsgInfo GPS信息
  92 + * @param subscribeInfo 订阅相关的信息
78 * @return 93 * @return
79 */ 94 */
80 - void sendNotifyMobilePosition(ParentPlatform parentPlatform, GPSMsgInfo gpsMsgInfo, SubscribeInfo subscribeInfo) throws InvalidArgumentException, ParseException, NoSuchFieldException, SipException, IllegalAccessException; 95 + void sendNotifyMobilePosition(ParentPlatform parentPlatform, GPSMsgInfo gpsMsgInfo, SubscribeInfo subscribeInfo)
  96 + throws InvalidArgumentException, ParseException, NoSuchFieldException, SipException, IllegalAccessException;
81 97
82 /** 98 /**
83 * 向上级回复报警消息 99 * 向上级回复报警消息
  100 + *
84 * @param parentPlatform 平台信息 101 * @param parentPlatform 平台信息
85 - * @param deviceAlarm 报警信息信息 102 + * @param deviceAlarm 报警信息信息
86 * @return 103 * @return
87 */ 104 */
88 void sendAlarmMessage(ParentPlatform parentPlatform, DeviceAlarm deviceAlarm) throws SipException, InvalidArgumentException, ParseException; 105 void sendAlarmMessage(ParentPlatform parentPlatform, DeviceAlarm deviceAlarm) throws SipException, InvalidArgumentException, ParseException;
89 106
90 /** 107 /**
91 * 回复catalog事件-增加/更新 108 * 回复catalog事件-增加/更新
  109 + *
92 * @param parentPlatform 110 * @param parentPlatform
93 * @param deviceChannels 111 * @param deviceChannels
94 */ 112 */
@@ -96,22 +114,28 @@ public interface ISIPCommanderForPlatform { @@ -96,22 +114,28 @@ public interface ISIPCommanderForPlatform {
96 114
97 /** 115 /**
98 * 回复catalog事件-删除 116 * 回复catalog事件-删除
  117 + *
99 * @param parentPlatform 118 * @param parentPlatform
100 * @param deviceChannels 119 * @param deviceChannels
101 */ 120 */
102 - void sendNotifyForCatalogOther(String type, ParentPlatform parentPlatform, List<DeviceChannel> deviceChannels, SubscribeInfo subscribeInfo, Integer index) throws InvalidArgumentException, ParseException, NoSuchFieldException, SipException, IllegalAccessException; 121 + void sendNotifyForCatalogOther(String type, ParentPlatform parentPlatform, List<DeviceChannel> deviceChannels,
  122 + SubscribeInfo subscribeInfo, Integer index) throws InvalidArgumentException,
  123 + ParseException, NoSuchFieldException, SipException, IllegalAccessException;
103 124
104 /** 125 /**
105 * 回复recordInfo 126 * 回复recordInfo
106 - * @param deviceChannel 通道信息 127 + *
  128 + * @param deviceChannel 通道信息
107 * @param parentPlatform 平台信息 129 * @param parentPlatform 平台信息
108 - * @param fromTag fromTag  
109 - * @param recordInfo 录像信息 130 + * @param fromTag fromTag
  131 + * @param recordInfo 录像信息
110 */ 132 */
111 - void recordInfo(DeviceChannel deviceChannel, ParentPlatform parentPlatform, String fromTag, RecordInfo recordInfo) throws SipException, InvalidArgumentException, ParseException; 133 + void recordInfo(DeviceChannel deviceChannel, ParentPlatform parentPlatform, String fromTag, RecordInfo recordInfo)
  134 + throws SipException, InvalidArgumentException, ParseException;
112 135
113 /** 136 /**
114 * 录像播放推送完成时发送MediaStatus消息 137 * 录像播放推送完成时发送MediaStatus消息
  138 + *
115 * @param platform 139 * @param platform
116 * @param sendRtpItem 140 * @param sendRtpItem
117 * @return 141 * @return
@@ -120,9 +144,19 @@ public interface ISIPCommanderForPlatform { @@ -120,9 +144,19 @@ public interface ISIPCommanderForPlatform {
120 144
121 /** 145 /**
122 * 向发起点播的上级回复bye 146 * 向发起点播的上级回复bye
  147 + *
123 * @param platform 平台信息 148 * @param platform 平台信息
124 - * @param callId callId 149 + * @param callId callId
125 */ 150 */
126 void streamByeCmd(ParentPlatform platform, String callId) throws SipException, InvalidArgumentException, ParseException; 151 void streamByeCmd(ParentPlatform platform, String callId) throws SipException, InvalidArgumentException, ParseException;
  152 +
127 void streamByeCmd(ParentPlatform platform, SendRtpItem sendRtpItem) throws SipException, InvalidArgumentException, ParseException; 153 void streamByeCmd(ParentPlatform platform, SendRtpItem sendRtpItem) throws SipException, InvalidArgumentException, ParseException;
  154 +
  155 + void streamByeCmd(ParentPlatform platform, String channelId, String stream, String callId, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException, SsrcTransactionNotFoundException;
  156 +
  157 + void broadcastInviteCmd(ParentPlatform platform, String channelId, MediaServerItem mediaServerItem,
  158 + SSRCInfo ssrcInfo, ZlmHttpHookSubscribe.Event event, SipSubscribe.Event okEvent,
  159 + SipSubscribe.Event errorEvent) throws ParseException, SipException, InvalidArgumentException;
  160 +
  161 + void broadcastResultCmd(ParentPlatform platform, DeviceChannel deviceChannel, String sn, boolean result, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException;
128 } 162 }
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderPlarformProvider.java
@@ -4,6 +4,7 @@ import com.genersoft.iot.vmp.conf.SipConfig; @@ -4,6 +4,7 @@ import com.genersoft.iot.vmp.conf.SipConfig;
4 import com.genersoft.iot.vmp.gb28181.SipLayer; 4 import com.genersoft.iot.vmp.gb28181.SipLayer;
5 import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; 5 import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
6 import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem; 6 import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
  7 +import com.genersoft.iot.vmp.gb28181.bean.SipTransactionInfo;
7 import com.genersoft.iot.vmp.gb28181.bean.SubscribeInfo; 8 import com.genersoft.iot.vmp.gb28181.bean.SubscribeInfo;
8 import com.genersoft.iot.vmp.gb28181.utils.SipUtils; 9 import com.genersoft.iot.vmp.gb28181.utils.SipUtils;
9 import com.genersoft.iot.vmp.storager.IRedisCatchStorage; 10 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
@@ -55,7 +56,7 @@ public class SIPRequestHeaderPlarformProvider { @@ -55,7 +56,7 @@ public class SIPRequestHeaderPlarformProvider {
55 //via 56 //via
56 ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>(); 57 ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();
57 ViaHeader viaHeader = SipFactory.getInstance().createHeaderFactory().createViaHeader(parentPlatform.getDeviceIp(), 58 ViaHeader viaHeader = SipFactory.getInstance().createHeaderFactory().createViaHeader(parentPlatform.getDeviceIp(),
58 - Integer.parseInt(parentPlatform.getDevicePort()), parentPlatform.getTransport(), SipUtils.getNewViaTag()); 59 + parentPlatform.getDevicePort(), parentPlatform.getTransport(), SipUtils.getNewViaTag());
59 viaHeader.setRPort(); 60 viaHeader.setRPort();
60 viaHeaders.add(viaHeader); 61 viaHeaders.add(viaHeader);
61 //from 62 //from
@@ -182,7 +183,7 @@ public class SIPRequestHeaderPlarformProvider { @@ -182,7 +183,7 @@ public class SIPRequestHeaderPlarformProvider {
182 SipURI requestURI = SipFactory.getInstance().createAddressFactory().createSipURI(parentPlatform.getServerGBId(), serverAddress); 183 SipURI requestURI = SipFactory.getInstance().createAddressFactory().createSipURI(parentPlatform.getServerGBId(), serverAddress);
183 // via 184 // via
184 ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>(); 185 ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();
185 - ViaHeader viaHeader = SipFactory.getInstance().createHeaderFactory().createViaHeader(parentPlatform.getDeviceIp(), Integer.parseInt(parentPlatform.getDevicePort()), 186 + ViaHeader viaHeader = SipFactory.getInstance().createHeaderFactory().createViaHeader(parentPlatform.getDeviceIp(), parentPlatform.getDevicePort(),
186 parentPlatform.getTransport(), viaTag); 187 parentPlatform.getTransport(), viaTag);
187 viaHeader.setRPort(); 188 viaHeader.setRPort();
188 viaHeaders.add(viaHeader); 189 viaHeaders.add(viaHeader);
@@ -219,7 +220,7 @@ public class SIPRequestHeaderPlarformProvider { @@ -219,7 +220,7 @@ public class SIPRequestHeaderPlarformProvider {
219 SipURI requestURI = SipFactory.getInstance().createAddressFactory().createSipURI(parentPlatform.getServerGBId(), parentPlatform.getServerIP()+ ":" + parentPlatform.getServerPort()); 220 SipURI requestURI = SipFactory.getInstance().createAddressFactory().createSipURI(parentPlatform.getServerGBId(), parentPlatform.getServerIP()+ ":" + parentPlatform.getServerPort());
220 // via 221 // via
221 ArrayList<ViaHeader> viaHeaders = new ArrayList<>(); 222 ArrayList<ViaHeader> viaHeaders = new ArrayList<>();
222 - ViaHeader viaHeader = SipFactory.getInstance().createHeaderFactory().createViaHeader(parentPlatform.getDeviceIp(), Integer.parseInt(parentPlatform.getDevicePort()), 223 + ViaHeader viaHeader = SipFactory.getInstance().createHeaderFactory().createViaHeader(parentPlatform.getDeviceIp(), parentPlatform.getDevicePort(),
223 parentPlatform.getTransport(), SipUtils.getNewViaTag()); 224 parentPlatform.getTransport(), SipUtils.getNewViaTag());
224 viaHeader.setRPort(); 225 viaHeader.setRPort();
225 viaHeaders.add(viaHeader); 226 viaHeaders.add(viaHeader);
@@ -279,7 +280,7 @@ public class SIPRequestHeaderPlarformProvider { @@ -279,7 +280,7 @@ public class SIPRequestHeaderPlarformProvider {
279 SipURI requestURI = SipFactory.getInstance().createAddressFactory().createSipURI(platform.getServerGBId(), platform.getServerIP()+ ":" + platform.getServerPort()); 280 SipURI requestURI = SipFactory.getInstance().createAddressFactory().createSipURI(platform.getServerGBId(), platform.getServerIP()+ ":" + platform.getServerPort());
280 // via 281 // via
281 ArrayList<ViaHeader> viaHeaders = new ArrayList<>(); 282 ArrayList<ViaHeader> viaHeaders = new ArrayList<>();
282 - ViaHeader viaHeader = SipFactory.getInstance().createHeaderFactory().createViaHeader(platform.getDeviceIp(), Integer.parseInt(platform.getDevicePort()), 283 + ViaHeader viaHeader = SipFactory.getInstance().createHeaderFactory().createViaHeader(platform.getDeviceIp(), platform.getDevicePort(),
283 platform.getTransport(), SipUtils.getNewViaTag()); 284 platform.getTransport(), SipUtils.getNewViaTag());
284 viaHeader.setRPort(); 285 viaHeader.setRPort();
285 viaHeaders.add(viaHeader); 286 viaHeaders.add(viaHeader);
@@ -313,4 +314,80 @@ public class SIPRequestHeaderPlarformProvider { @@ -313,4 +314,80 @@ public class SIPRequestHeaderPlarformProvider {
313 314
314 return request; 315 return request;
315 } 316 }
  317 +
  318 + public Request createInviteRequest(ParentPlatform platform, String channelId, String content, String viaTag, String fromTag, String ssrc, CallIdHeader callIdHeader) throws PeerUnavailableException, ParseException, InvalidArgumentException {
  319 + Request request = null;
  320 + //请求行
  321 + String platformHostAddress = platform.getServerIP() + ":" + platform.getServerPort();
  322 + String localHostAddress = sipLayer.getLocalIp(platform.getDeviceIp())+":"+ platform.getDevicePort();
  323 + SipURI requestLine = SipFactory.getInstance().createAddressFactory().createSipURI(channelId, platformHostAddress);
  324 + //via
  325 + ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();
  326 + ViaHeader viaHeader = SipFactory.getInstance().createHeaderFactory().createViaHeader(sipLayer.getLocalIp(platform.getDeviceIp()), platform.getDevicePort(), platform.getTransport(), viaTag);
  327 + viaHeader.setRPort();
  328 + viaHeaders.add(viaHeader);
  329 +
  330 + //from
  331 + SipURI fromSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(platform.getDeviceGBId(), sipConfig.getDomain());
  332 + Address fromAddress = SipFactory.getInstance().createAddressFactory().createAddress(fromSipURI);
  333 + FromHeader fromHeader = SipFactory.getInstance().createHeaderFactory().createFromHeader(fromAddress, fromTag); //必须要有标记,否则无法创建会话,无法回应ack
  334 + //to
  335 + SipURI toSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(channelId, platformHostAddress);
  336 + Address toAddress = SipFactory.getInstance().createAddressFactory().createAddress(toSipURI);
  337 + ToHeader toHeader = SipFactory.getInstance().createHeaderFactory().createToHeader(toAddress,null);
  338 +
  339 + //Forwards
  340 + MaxForwardsHeader maxForwards = SipFactory.getInstance().createHeaderFactory().createMaxForwardsHeader(70);
  341 +
  342 + //ceq
  343 + CSeqHeader cSeqHeader = SipFactory.getInstance().createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(), Request.INVITE);
  344 + request = SipFactory.getInstance().createMessageFactory().createRequest(requestLine, Request.INVITE, callIdHeader, cSeqHeader,fromHeader, toHeader, viaHeaders, maxForwards);
  345 +
  346 + request.addHeader(SipUtils.createUserAgentHeader(gitUtil));
  347 +
  348 + Address concatAddress = SipFactory.getInstance().createAddressFactory().createAddress(SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(),localHostAddress));
  349 + request.addHeader(SipFactory.getInstance().createHeaderFactory().createContactHeader(concatAddress));
  350 + // Subject
  351 + SubjectHeader subjectHeader = SipFactory.getInstance().createHeaderFactory().createSubjectHeader(String.format("%s:%s,%s:%s", channelId, ssrc, sipConfig.getId(), 0));
  352 + request.addHeader(subjectHeader);
  353 + ContentTypeHeader contentTypeHeader = SipFactory.getInstance().createHeaderFactory().createContentTypeHeader("APPLICATION", "SDP");
  354 + request.setContent(content, contentTypeHeader);
  355 + return request;
  356 + }
  357 +
  358 + public Request createByteRequest(ParentPlatform platform, String channelId, SipTransactionInfo transactionInfo) throws PeerUnavailableException, ParseException, InvalidArgumentException {
  359 + String deviceHostAddress = platform.getDeviceIp() + ":" + platform.getDevicePort();
  360 + Request request = null;
  361 + SipURI requestLine = SipFactory.getInstance().createAddressFactory().createSipURI(channelId, deviceHostAddress);
  362 +
  363 + // via
  364 + ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();
  365 + ViaHeader viaHeader = SipFactory.getInstance().createHeaderFactory().createViaHeader(sipLayer.getLocalIp(platform.getDeviceIp()), platform.getDevicePort(), platform.getTransport(), SipUtils.getNewViaTag());
  366 + viaHeaders.add(viaHeader);
  367 + //from
  368 + SipURI fromSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(),sipConfig.getDomain());
  369 + Address fromAddress = SipFactory.getInstance().createAddressFactory().createAddress(fromSipURI);
  370 + FromHeader fromHeader = SipFactory.getInstance().createHeaderFactory().createFromHeader(fromAddress, transactionInfo.isAsSender()?transactionInfo.getFromTag():transactionInfo.getToTag());
  371 + //to
  372 + SipURI toSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(channelId, deviceHostAddress);
  373 + Address toAddress = SipFactory.getInstance().createAddressFactory().createAddress(toSipURI);
  374 + ToHeader toHeader = SipFactory.getInstance().createHeaderFactory().createToHeader(toAddress,transactionInfo.isAsSender()?transactionInfo.getToTag():transactionInfo.getFromTag());
  375 +
  376 + //Forwards
  377 + MaxForwardsHeader maxForwards = SipFactory.getInstance().createHeaderFactory().createMaxForwardsHeader(70);
  378 +
  379 + //ceq
  380 + CSeqHeader cSeqHeader = SipFactory.getInstance().createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(), Request.BYE);
  381 + CallIdHeader callIdHeader = SipFactory.getInstance().createHeaderFactory().createCallIdHeader(transactionInfo.getCallId());
  382 + request = SipFactory.getInstance().createMessageFactory().createRequest(requestLine, Request.BYE, callIdHeader, cSeqHeader,fromHeader, toHeader, viaHeaders, maxForwards);
  383 +
  384 + request.addHeader(SipUtils.createUserAgentHeader(gitUtil));
  385 +
  386 + Address concatAddress = SipFactory.getInstance().createAddressFactory().createAddress(SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), sipLayer.getLocalIp(platform.getDeviceIp())+":"+ platform.getDevicePort()));
  387 + request.addHeader(SipFactory.getInstance().createHeaderFactory().createContactHeader(concatAddress));
  388 +
  389 + request.addHeader(SipUtils.createUserAgentHeader(gitUtil));
  390 +
  391 + return request;
  392 + }
316 } 393 }
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderProvider.java
1 -package com.genersoft.iot.vmp.gb28181.transmit.cmd;  
2 -  
3 -import com.genersoft.iot.vmp.conf.SipConfig;  
4 -import com.genersoft.iot.vmp.gb28181.SipLayer;  
5 -import com.genersoft.iot.vmp.gb28181.bean.Device;  
6 -import com.genersoft.iot.vmp.gb28181.bean.SipTransactionInfo;  
7 -import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;  
8 -import com.genersoft.iot.vmp.gb28181.utils.SipUtils;  
9 -import com.genersoft.iot.vmp.storager.IRedisCatchStorage;  
10 -import com.genersoft.iot.vmp.utils.GitUtil;  
11 -import gov.nist.javax.sip.message.SIPRequest;  
12 -import gov.nist.javax.sip.message.SIPResponse;  
13 -import org.springframework.beans.factory.annotation.Autowired;  
14 -import org.springframework.stereotype.Component;  
15 -  
16 -import javax.sip.InvalidArgumentException;  
17 -import javax.sip.PeerUnavailableException;  
18 -import javax.sip.SipException;  
19 -import javax.sip.SipFactory;  
20 -import javax.sip.address.Address;  
21 -import javax.sip.address.SipURI;  
22 -import javax.sip.header.*;  
23 -import javax.sip.message.Request;  
24 -import java.text.ParseException;  
25 -import java.util.ArrayList;  
26 -  
27 -/**  
28 - * @description:摄像头命令request创造器 TODO 冗余代码太多待优化  
29 - * @author: swwheihei  
30 - * @date: 2020年5月6日 上午9:29:02  
31 - */  
32 -@Component  
33 -public class SIPRequestHeaderProvider {  
34 -  
35 - @Autowired  
36 - private SipConfig sipConfig;  
37 -  
38 - @Autowired  
39 - private SipLayer sipLayer;  
40 -  
41 - @Autowired  
42 - private GitUtil gitUtil;  
43 -  
44 - @Autowired  
45 - private IRedisCatchStorage redisCatchStorage;  
46 -  
47 - @Autowired  
48 - private VideoStreamSessionManager streamSession;  
49 -  
50 - public Request createMessageRequest(Device device, String content, String viaTag, String fromTag, String toTag, CallIdHeader callIdHeader) throws ParseException, InvalidArgumentException, PeerUnavailableException {  
51 - Request request = null;  
52 - // sipuri  
53 - SipURI requestURI = SipFactory.getInstance().createAddressFactory().createSipURI(device.getDeviceId(), device.getHostAddress());  
54 - // via  
55 - ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();  
56 - ViaHeader viaHeader = SipFactory.getInstance().createHeaderFactory().createViaHeader(sipLayer.getLocalIp(device.getLocalIp()), sipConfig.getPort(), device.getTransport(), viaTag);  
57 - viaHeader.setRPort();  
58 - viaHeaders.add(viaHeader);  
59 - // from  
60 - SipURI fromSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), sipConfig.getDomain());  
61 - Address fromAddress = SipFactory.getInstance().createAddressFactory().createAddress(fromSipURI);  
62 - FromHeader fromHeader = SipFactory.getInstance().createHeaderFactory().createFromHeader(fromAddress, fromTag);  
63 - // to  
64 - SipURI toSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(device.getDeviceId(), device.getHostAddress());  
65 - Address toAddress = SipFactory.getInstance().createAddressFactory().createAddress(toSipURI);  
66 - ToHeader toHeader = SipFactory.getInstance().createHeaderFactory().createToHeader(toAddress, toTag);  
67 -  
68 - // Forwards  
69 - MaxForwardsHeader maxForwards = SipFactory.getInstance().createHeaderFactory().createMaxForwardsHeader(70);  
70 - // ceq  
71 - CSeqHeader cSeqHeader = SipFactory.getInstance().createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(), Request.MESSAGE);  
72 -  
73 - request = SipFactory.getInstance().createMessageFactory().createRequest(requestURI, Request.MESSAGE, callIdHeader, cSeqHeader, fromHeader,  
74 - toHeader, viaHeaders, maxForwards);  
75 -  
76 - request.addHeader(SipUtils.createUserAgentHeader(gitUtil));  
77 -  
78 - ContentTypeHeader contentTypeHeader = SipFactory.getInstance().createHeaderFactory().createContentTypeHeader("Application", "MANSCDP+xml");  
79 - request.setContent(content, contentTypeHeader);  
80 - return request;  
81 - }  
82 -  
83 - public Request createInviteRequest(Device device, String channelId, String content, String viaTag, String fromTag, String toTag, String ssrc, CallIdHeader callIdHeader) throws ParseException, InvalidArgumentException, PeerUnavailableException {  
84 - Request request = null;  
85 - //请求行  
86 - SipURI requestLine = SipFactory.getInstance().createAddressFactory().createSipURI(channelId, device.getHostAddress());  
87 - //via  
88 - ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();  
89 - HeaderFactory headerFactory = SipFactory.getInstance().createHeaderFactory();  
90 - ViaHeader viaHeader = SipFactory.getInstance().createHeaderFactory().createViaHeader(sipLayer.getLocalIp(device.getLocalIp()), sipConfig.getPort(), device.getTransport(), viaTag);  
91 - viaHeader.setRPort();  
92 - viaHeaders.add(viaHeader);  
93 -  
94 - //from  
95 - SipURI fromSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), sipConfig.getDomain());  
96 - Address fromAddress = SipFactory.getInstance().createAddressFactory().createAddress(fromSipURI);  
97 - FromHeader fromHeader = SipFactory.getInstance().createHeaderFactory().createFromHeader(fromAddress, fromTag); //必须要有标记,否则无法创建会话,无法回应ack  
98 - //to  
99 - SipURI toSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(channelId, device.getHostAddress());  
100 - Address toAddress = SipFactory.getInstance().createAddressFactory().createAddress(toSipURI);  
101 - ToHeader toHeader = SipFactory.getInstance().createHeaderFactory().createToHeader(toAddress,null);  
102 -  
103 - //Forwards  
104 - MaxForwardsHeader maxForwards = SipFactory.getInstance().createHeaderFactory().createMaxForwardsHeader(70);  
105 -  
106 - //ceq  
107 - CSeqHeader cSeqHeader = SipFactory.getInstance().createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(), Request.INVITE);  
108 - request = SipFactory.getInstance().createMessageFactory().createRequest(requestLine, Request.INVITE, callIdHeader, cSeqHeader,fromHeader, toHeader, viaHeaders, maxForwards);  
109 -  
110 - request.addHeader(SipUtils.createUserAgentHeader(gitUtil));  
111 -  
112 - Address concatAddress = SipFactory.getInstance().createAddressFactory().createAddress(SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), sipLayer.getLocalIp(device.getLocalIp())+":"+sipConfig.getPort()));  
113 - // Address concatAddress = SipFactory.getInstance().createAddressFactory().createAddress(SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), device.getHost().getIp()+":"+device.getHost().getPort()));  
114 - request.addHeader(SipFactory.getInstance().createHeaderFactory().createContactHeader(concatAddress));  
115 - // Subject  
116 - SubjectHeader subjectHeader = SipFactory.getInstance().createHeaderFactory().createSubjectHeader(String.format("%s:%s,%s:%s", channelId, ssrc, sipConfig.getId(), 0));  
117 - request.addHeader(subjectHeader);  
118 - ContentTypeHeader contentTypeHeader = SipFactory.getInstance().createHeaderFactory().createContentTypeHeader("APPLICATION", "SDP");  
119 - request.setContent(content, contentTypeHeader);  
120 - return request;  
121 - }  
122 -  
123 - public Request createPlaybackInviteRequest(Device device, String channelId, String content, String viaTag, String fromTag, String toTag, CallIdHeader callIdHeader, String ssrc) throws ParseException, InvalidArgumentException, PeerUnavailableException {  
124 - Request request = null;  
125 - //请求行  
126 - SipURI requestLine = SipFactory.getInstance().createAddressFactory().createSipURI(channelId, device.getHostAddress());  
127 - // via  
128 - ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();  
129 - ViaHeader viaHeader = SipFactory.getInstance().createHeaderFactory().createViaHeader(sipLayer.getLocalIp(device.getLocalIp()), sipConfig.getPort(), device.getTransport(), viaTag);  
130 - viaHeader.setRPort();  
131 - viaHeaders.add(viaHeader);  
132 - //from  
133 - SipURI fromSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), sipConfig.getDomain());  
134 - Address fromAddress = SipFactory.getInstance().createAddressFactory().createAddress(fromSipURI);  
135 - FromHeader fromHeader = SipFactory.getInstance().createHeaderFactory().createFromHeader(fromAddress, fromTag); //必须要有标记,否则无法创建会话,无法回应ack  
136 - //to  
137 - SipURI toSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(channelId, device.getHostAddress());  
138 - Address toAddress = SipFactory.getInstance().createAddressFactory().createAddress(toSipURI);  
139 - ToHeader toHeader = SipFactory.getInstance().createHeaderFactory().createToHeader(toAddress,null);  
140 -  
141 - //Forwards  
142 - MaxForwardsHeader maxForwards = SipFactory.getInstance().createHeaderFactory().createMaxForwardsHeader(70);  
143 -  
144 - //ceq  
145 - CSeqHeader cSeqHeader = SipFactory.getInstance().createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(), Request.INVITE);  
146 - request = SipFactory.getInstance().createMessageFactory().createRequest(requestLine, Request.INVITE, callIdHeader, cSeqHeader,fromHeader, toHeader, viaHeaders, maxForwards);  
147 -  
148 - Address concatAddress = SipFactory.getInstance().createAddressFactory().createAddress(SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), sipLayer.getLocalIp(device.getLocalIp())+":"+sipConfig.getPort()));  
149 - // Address concatAddress = SipFactory.getInstance().createAddressFactory().createAddress(SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), device.getHost().getIp()+":"+device.getHost().getPort()));  
150 - request.addHeader(SipFactory.getInstance().createHeaderFactory().createContactHeader(concatAddress));  
151 -  
152 - request.addHeader(SipUtils.createUserAgentHeader(gitUtil));  
153 -  
154 - // Subject  
155 - SubjectHeader subjectHeader = SipFactory.getInstance().createHeaderFactory().createSubjectHeader(String.format("%s:%s,%s:%s", channelId, ssrc, sipConfig.getId(), 0));  
156 - request.addHeader(subjectHeader);  
157 -  
158 - ContentTypeHeader contentTypeHeader = SipFactory.getInstance().createHeaderFactory().createContentTypeHeader("APPLICATION", "SDP");  
159 - request.setContent(content, contentTypeHeader);  
160 - return request;  
161 - }  
162 -  
163 - public Request createByteRequest(Device device, String channelId, SipTransactionInfo transactionInfo) throws ParseException, InvalidArgumentException, PeerUnavailableException {  
164 - Request request = null;  
165 - //请求行  
166 - SipURI requestLine = SipFactory.getInstance().createAddressFactory().createSipURI(channelId, device.getHostAddress());  
167 -// SipURI requestLine = SipFactory.getInstance().createAddressFactory().createSipURI(device.getDeviceId(), device.getHostAddress());  
168 - // via  
169 - ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();  
170 - ViaHeader viaHeader = SipFactory.getInstance().createHeaderFactory().createViaHeader(sipLayer.getLocalIp(device.getLocalIp()), sipConfig.getPort(), device.getTransport(), SipUtils.getNewViaTag());  
171 - viaHeaders.add(viaHeader);  
172 - //from  
173 - SipURI fromSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(),sipConfig.getDomain());  
174 - Address fromAddress = SipFactory.getInstance().createAddressFactory().createAddress(fromSipURI);  
175 - FromHeader fromHeader = SipFactory.getInstance().createHeaderFactory().createFromHeader(fromAddress, transactionInfo.getFromTag());  
176 - //to  
177 - SipURI toSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(channelId,device.getHostAddress());  
178 -// SipURI toSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(device.getDeviceId(),device.getHostAddress());  
179 - Address toAddress = SipFactory.getInstance().createAddressFactory().createAddress(toSipURI);  
180 - ToHeader toHeader = SipFactory.getInstance().createHeaderFactory().createToHeader(toAddress, transactionInfo.getToTag());  
181 -  
182 - //Forwards  
183 - MaxForwardsHeader maxForwards = SipFactory.getInstance().createHeaderFactory().createMaxForwardsHeader(70);  
184 -  
185 - //ceq  
186 - CSeqHeader cSeqHeader = SipFactory.getInstance().createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(), Request.BYE);  
187 - CallIdHeader callIdHeader = SipFactory.getInstance().createHeaderFactory().createCallIdHeader(transactionInfo.getCallId());  
188 - request = SipFactory.getInstance().createMessageFactory().createRequest(requestLine, Request.BYE, callIdHeader, cSeqHeader,fromHeader, toHeader, viaHeaders, maxForwards);  
189 -  
190 - request.addHeader(SipUtils.createUserAgentHeader(gitUtil));  
191 -  
192 - Address concatAddress = SipFactory.getInstance().createAddressFactory().createAddress(SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), sipLayer.getLocalIp(device.getLocalIp())+":"+sipConfig.getPort()));  
193 - request.addHeader(SipFactory.getInstance().createHeaderFactory().createContactHeader(concatAddress));  
194 -  
195 - request.addHeader(SipUtils.createUserAgentHeader(gitUtil));  
196 -  
197 - return request;  
198 - }  
199 -  
200 - public Request createSubscribeRequest(Device device, String content, SIPRequest requestOld, Integer expires, String event, CallIdHeader callIdHeader) throws ParseException, InvalidArgumentException, PeerUnavailableException {  
201 - Request request = null;  
202 - // sipuri  
203 - SipURI requestURI = SipFactory.getInstance().createAddressFactory().createSipURI(device.getDeviceId(), device.getHostAddress());  
204 - // via  
205 - ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();  
206 - ViaHeader viaHeader = SipFactory.getInstance().createHeaderFactory().createViaHeader(sipLayer.getLocalIp(device.getLocalIp()), sipConfig.getPort(),  
207 - device.getTransport(), SipUtils.getNewViaTag());  
208 - viaHeader.setRPort();  
209 - viaHeaders.add(viaHeader);  
210 - // from  
211 - SipURI fromSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), sipConfig.getDomain());  
212 - Address fromAddress = SipFactory.getInstance().createAddressFactory().createAddress(fromSipURI);  
213 - FromHeader fromHeader = SipFactory.getInstance().createHeaderFactory().createFromHeader(fromAddress, requestOld == null ? SipUtils.getNewFromTag() :requestOld.getFromTag());  
214 - // to  
215 - SipURI toSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(device.getDeviceId(), device.getHostAddress());  
216 - Address toAddress = SipFactory.getInstance().createAddressFactory().createAddress(toSipURI);  
217 - ToHeader toHeader = SipFactory.getInstance().createHeaderFactory().createToHeader(toAddress, requestOld == null ? null :requestOld.getToTag());  
218 -  
219 - // Forwards  
220 - MaxForwardsHeader maxForwards = SipFactory.getInstance().createHeaderFactory().createMaxForwardsHeader(70);  
221 -  
222 - // ceq  
223 - CSeqHeader cSeqHeader = SipFactory.getInstance().createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(), Request.SUBSCRIBE);  
224 -  
225 - request = SipFactory.getInstance().createMessageFactory().createRequest(requestURI, Request.SUBSCRIBE, callIdHeader, cSeqHeader, fromHeader,  
226 - toHeader, viaHeaders, maxForwards);  
227 -  
228 -  
229 - Address concatAddress = SipFactory.getInstance().createAddressFactory().createAddress(SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), sipLayer.getLocalIp(device.getLocalIp())+":"+sipConfig.getPort()));  
230 - request.addHeader(SipFactory.getInstance().createHeaderFactory().createContactHeader(concatAddress));  
231 -  
232 - // Expires  
233 - ExpiresHeader expireHeader = SipFactory.getInstance().createHeaderFactory().createExpiresHeader(expires);  
234 - request.addHeader(expireHeader);  
235 -  
236 - // Event  
237 - EventHeader eventHeader = SipFactory.getInstance().createHeaderFactory().createEventHeader(event);  
238 -  
239 - int random = (int) Math.floor(Math.random() * 10000);  
240 - eventHeader.setEventId(random + "");  
241 - request.addHeader(eventHeader);  
242 -  
243 - ContentTypeHeader contentTypeHeader = SipFactory.getInstance().createHeaderFactory().createContentTypeHeader("Application", "MANSCDP+xml");  
244 - request.setContent(content, contentTypeHeader);  
245 -  
246 - request.addHeader(SipUtils.createUserAgentHeader(gitUtil));  
247 -  
248 - return request;  
249 - }  
250 -  
251 - public SIPRequest createInfoRequest(Device device, String channelId, String content, SipTransactionInfo transactionInfo)  
252 - throws SipException, ParseException, InvalidArgumentException {  
253 - if (device == null || transactionInfo == null) {  
254 - return null;  
255 - }  
256 - SIPRequest request = null;  
257 - //请求行  
258 - SipURI requestLine = SipFactory.getInstance().createAddressFactory().createSipURI(channelId, device.getHostAddress());  
259 - // via  
260 - ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();  
261 - ViaHeader viaHeader = SipFactory.getInstance().createHeaderFactory().createViaHeader(sipLayer.getLocalIp(device.getLocalIp()), sipConfig.getPort(), device.getTransport(), SipUtils.getNewViaTag());  
262 - viaHeaders.add(viaHeader);  
263 - //from  
264 - SipURI fromSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(),sipConfig.getDomain());  
265 - Address fromAddress = SipFactory.getInstance().createAddressFactory().createAddress(fromSipURI);  
266 - FromHeader fromHeader = SipFactory.getInstance().createHeaderFactory().createFromHeader(fromAddress, transactionInfo.getFromTag());  
267 - //to  
268 - SipURI toSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(channelId,device.getHostAddress());  
269 - Address toAddress = SipFactory.getInstance().createAddressFactory().createAddress(toSipURI);  
270 - ToHeader toHeader = SipFactory.getInstance().createHeaderFactory().createToHeader(toAddress, transactionInfo.getToTag());  
271 -  
272 - //Forwards  
273 - MaxForwardsHeader maxForwards = SipFactory.getInstance().createHeaderFactory().createMaxForwardsHeader(70);  
274 -  
275 - //ceq  
276 - CSeqHeader cSeqHeader = SipFactory.getInstance().createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(), Request.INFO);  
277 - CallIdHeader callIdHeader = SipFactory.getInstance().createHeaderFactory().createCallIdHeader(transactionInfo.getCallId());  
278 - request = (SIPRequest)SipFactory.getInstance().createMessageFactory().createRequest(requestLine, Request.INFO, callIdHeader, cSeqHeader,fromHeader, toHeader, viaHeaders, maxForwards);  
279 -  
280 - request.addHeader(SipUtils.createUserAgentHeader(gitUtil));  
281 -  
282 - Address concatAddress = SipFactory.getInstance().createAddressFactory().createAddress(SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), sipLayer.getLocalIp(device.getLocalIp())+":"+sipConfig.getPort()));  
283 - request.addHeader(SipFactory.getInstance().createHeaderFactory().createContactHeader(concatAddress));  
284 -  
285 - request.addHeader(SipUtils.createUserAgentHeader(gitUtil));  
286 -  
287 - if (content != null) {  
288 - ContentTypeHeader contentTypeHeader = SipFactory.getInstance().createHeaderFactory().createContentTypeHeader("Application",  
289 - "MANSRTSP");  
290 - request.setContent(content, contentTypeHeader);  
291 - }  
292 - return request;  
293 - }  
294 -  
295 - public Request createAckRequest(String localIp, SipURI sipURI, SIPResponse sipResponse) throws ParseException, InvalidArgumentException, PeerUnavailableException {  
296 -  
297 -  
298 - // via  
299 - ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();  
300 - ViaHeader viaHeader = SipFactory.getInstance().createHeaderFactory().createViaHeader(localIp, sipConfig.getPort(), sipResponse.getTopmostViaHeader().getTransport(), SipUtils.getNewViaTag());  
301 - viaHeaders.add(viaHeader);  
302 -  
303 - //Forwards  
304 - MaxForwardsHeader maxForwards = SipFactory.getInstance().createHeaderFactory().createMaxForwardsHeader(70);  
305 -  
306 - //ceq  
307 - CSeqHeader cSeqHeader = SipFactory.getInstance().createHeaderFactory().createCSeqHeader(sipResponse.getCSeqHeader().getSeqNumber(), Request.ACK);  
308 -  
309 - Request request = SipFactory.getInstance().createMessageFactory().createRequest(sipURI, Request.ACK, sipResponse.getCallIdHeader(), cSeqHeader, sipResponse.getFromHeader(), sipResponse.getToHeader(), viaHeaders, maxForwards);  
310 -  
311 - request.addHeader(SipUtils.createUserAgentHeader(gitUtil));  
312 -  
313 - Address concatAddress = SipFactory.getInstance().createAddressFactory().createAddress(SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), localIp + ":"+sipConfig.getPort()));  
314 - request.addHeader(SipFactory.getInstance().createHeaderFactory().createContactHeader(concatAddress));  
315 -  
316 - request.addHeader(SipUtils.createUserAgentHeader(gitUtil));  
317 -  
318 - return request;  
319 - }  
320 -} 1 +package com.genersoft.iot.vmp.gb28181.transmit.cmd;
  2 +
  3 +import com.genersoft.iot.vmp.conf.SipConfig;
  4 +import com.genersoft.iot.vmp.gb28181.SipLayer;
  5 +import com.genersoft.iot.vmp.gb28181.bean.Device;
  6 +import com.genersoft.iot.vmp.gb28181.bean.SipTransactionInfo;
  7 +import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
  8 +import com.genersoft.iot.vmp.gb28181.utils.SipUtils;
  9 +import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
  10 +import com.genersoft.iot.vmp.utils.GitUtil;
  11 +import gov.nist.javax.sip.message.SIPRequest;
  12 +import gov.nist.javax.sip.message.SIPResponse;
  13 +import org.springframework.beans.factory.annotation.Autowired;
  14 +import org.springframework.stereotype.Component;
  15 +
  16 +import javax.sip.InvalidArgumentException;
  17 +import javax.sip.PeerUnavailableException;
  18 +import javax.sip.SipException;
  19 +import javax.sip.SipFactory;
  20 +import javax.sip.address.Address;
  21 +import javax.sip.address.SipURI;
  22 +import javax.sip.header.*;
  23 +import javax.sip.message.Request;
  24 +import java.text.ParseException;
  25 +import java.util.ArrayList;
  26 +
  27 +/**
  28 + * @description:摄像头命令request创造器 TODO 冗余代码太多待优化
  29 + * @author: swwheihei
  30 + * @date: 2020年5月6日 上午9:29:02
  31 + */
  32 +@Component
  33 +public class SIPRequestHeaderProvider {
  34 +
  35 + @Autowired
  36 + private SipConfig sipConfig;
  37 +
  38 + @Autowired
  39 + private SipLayer sipLayer;
  40 +
  41 + @Autowired
  42 + private GitUtil gitUtil;
  43 +
  44 + @Autowired
  45 + private IRedisCatchStorage redisCatchStorage;
  46 +
  47 + @Autowired
  48 + private VideoStreamSessionManager streamSession;
  49 +
  50 + public Request createMessageRequest(Device device, String content, String viaTag, String fromTag, String toTag, CallIdHeader callIdHeader) throws ParseException, InvalidArgumentException, PeerUnavailableException {
  51 + Request request = null;
  52 + // sipuri
  53 + SipURI requestURI = SipFactory.getInstance().createAddressFactory().createSipURI(device.getDeviceId(), device.getHostAddress());
  54 + // via
  55 + ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();
  56 + ViaHeader viaHeader = SipFactory.getInstance().createHeaderFactory().createViaHeader(sipLayer.getLocalIp(device.getLocalIp()), sipConfig.getPort(), device.getTransport(), viaTag);
  57 + viaHeader.setRPort();
  58 + viaHeaders.add(viaHeader);
  59 + // from
  60 + SipURI fromSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), sipConfig.getDomain());
  61 + Address fromAddress = SipFactory.getInstance().createAddressFactory().createAddress(fromSipURI);
  62 + FromHeader fromHeader = SipFactory.getInstance().createHeaderFactory().createFromHeader(fromAddress, fromTag);
  63 + // to
  64 + SipURI toSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(device.getDeviceId(), device.getHostAddress());
  65 + Address toAddress = SipFactory.getInstance().createAddressFactory().createAddress(toSipURI);
  66 + ToHeader toHeader = SipFactory.getInstance().createHeaderFactory().createToHeader(toAddress, toTag);
  67 +
  68 + // Forwards
  69 + MaxForwardsHeader maxForwards = SipFactory.getInstance().createHeaderFactory().createMaxForwardsHeader(70);
  70 + // ceq
  71 + CSeqHeader cSeqHeader = SipFactory.getInstance().createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(), Request.MESSAGE);
  72 +
  73 + request = SipFactory.getInstance().createMessageFactory().createRequest(requestURI, Request.MESSAGE, callIdHeader, cSeqHeader, fromHeader,
  74 + toHeader, viaHeaders, maxForwards);
  75 +
  76 + request.addHeader(SipUtils.createUserAgentHeader(gitUtil));
  77 +
  78 + ContentTypeHeader contentTypeHeader = SipFactory.getInstance().createHeaderFactory().createContentTypeHeader("Application", "MANSCDP+xml");
  79 + request.setContent(content, contentTypeHeader);
  80 + return request;
  81 + }
  82 +
  83 + public Request createInviteRequest(Device device, String channelId, String content, String viaTag, String fromTag, String toTag, String ssrc, CallIdHeader callIdHeader) throws ParseException, InvalidArgumentException, PeerUnavailableException {
  84 + Request request = null;
  85 + //请求行
  86 + SipURI requestLine = SipFactory.getInstance().createAddressFactory().createSipURI(channelId, device.getHostAddress());
  87 + //via
  88 + ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();
  89 + HeaderFactory headerFactory = SipFactory.getInstance().createHeaderFactory();
  90 + ViaHeader viaHeader = SipFactory.getInstance().createHeaderFactory().createViaHeader(sipLayer.getLocalIp(device.getLocalIp()), sipConfig.getPort(), device.getTransport(), viaTag);
  91 + viaHeader.setRPort();
  92 + viaHeaders.add(viaHeader);
  93 +
  94 + //from
  95 + SipURI fromSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), sipConfig.getDomain());
  96 + Address fromAddress = SipFactory.getInstance().createAddressFactory().createAddress(fromSipURI);
  97 + FromHeader fromHeader = SipFactory.getInstance().createHeaderFactory().createFromHeader(fromAddress, fromTag); //必须要有标记,否则无法创建会话,无法回应ack
  98 + //to
  99 + SipURI toSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(channelId, device.getHostAddress());
  100 + Address toAddress = SipFactory.getInstance().createAddressFactory().createAddress(toSipURI);
  101 + ToHeader toHeader = SipFactory.getInstance().createHeaderFactory().createToHeader(toAddress,null);
  102 +
  103 + //Forwards
  104 + MaxForwardsHeader maxForwards = SipFactory.getInstance().createHeaderFactory().createMaxForwardsHeader(70);
  105 +
  106 + //ceq
  107 + CSeqHeader cSeqHeader = SipFactory.getInstance().createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(), Request.INVITE);
  108 + request = SipFactory.getInstance().createMessageFactory().createRequest(requestLine, Request.INVITE, callIdHeader, cSeqHeader,fromHeader, toHeader, viaHeaders, maxForwards);
  109 +
  110 + request.addHeader(SipUtils.createUserAgentHeader(gitUtil));
  111 +
  112 + Address concatAddress = SipFactory.getInstance().createAddressFactory().createAddress(SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), sipLayer.getLocalIp(device.getLocalIp())+":"+sipConfig.getPort()));
  113 + // Address concatAddress = SipFactory.getInstance().createAddressFactory().createAddress(SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), device.getHost().getIp()+":"+device.getHost().getPort()));
  114 + request.addHeader(SipFactory.getInstance().createHeaderFactory().createContactHeader(concatAddress));
  115 + // Subject
  116 + SubjectHeader subjectHeader = SipFactory.getInstance().createHeaderFactory().createSubjectHeader(String.format("%s:%s,%s:%s", channelId, ssrc, sipConfig.getId(), 0));
  117 + request.addHeader(subjectHeader);
  118 + ContentTypeHeader contentTypeHeader = SipFactory.getInstance().createHeaderFactory().createContentTypeHeader("APPLICATION", "SDP");
  119 + request.setContent(content, contentTypeHeader);
  120 + return request;
  121 + }
  122 +
  123 + public Request createPlaybackInviteRequest(Device device, String channelId, String content, String viaTag, String fromTag, String toTag, CallIdHeader callIdHeader, String ssrc) throws ParseException, InvalidArgumentException, PeerUnavailableException {
  124 + Request request = null;
  125 + //请求行
  126 + SipURI requestLine = SipFactory.getInstance().createAddressFactory().createSipURI(channelId, device.getHostAddress());
  127 + // via
  128 + ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();
  129 + ViaHeader viaHeader = SipFactory.getInstance().createHeaderFactory().createViaHeader(sipLayer.getLocalIp(device.getLocalIp()), sipConfig.getPort(), device.getTransport(), viaTag);
  130 + viaHeader.setRPort();
  131 + viaHeaders.add(viaHeader);
  132 + //from
  133 + SipURI fromSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), sipConfig.getDomain());
  134 + Address fromAddress = SipFactory.getInstance().createAddressFactory().createAddress(fromSipURI);
  135 + FromHeader fromHeader = SipFactory.getInstance().createHeaderFactory().createFromHeader(fromAddress, fromTag); //必须要有标记,否则无法创建会话,无法回应ack
  136 + //to
  137 + SipURI toSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(channelId, device.getHostAddress());
  138 + Address toAddress = SipFactory.getInstance().createAddressFactory().createAddress(toSipURI);
  139 + ToHeader toHeader = SipFactory.getInstance().createHeaderFactory().createToHeader(toAddress,null);
  140 +
  141 + //Forwards
  142 + MaxForwardsHeader maxForwards = SipFactory.getInstance().createHeaderFactory().createMaxForwardsHeader(70);
  143 +
  144 + //ceq
  145 + CSeqHeader cSeqHeader = SipFactory.getInstance().createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(), Request.INVITE);
  146 + request = SipFactory.getInstance().createMessageFactory().createRequest(requestLine, Request.INVITE, callIdHeader, cSeqHeader,fromHeader, toHeader, viaHeaders, maxForwards);
  147 +
  148 + Address concatAddress = SipFactory.getInstance().createAddressFactory().createAddress(SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), sipLayer.getLocalIp(device.getLocalIp())+":"+sipConfig.getPort()));
  149 + // Address concatAddress = SipFactory.getInstance().createAddressFactory().createAddress(SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), device.getHost().getIp()+":"+device.getHost().getPort()));
  150 + request.addHeader(SipFactory.getInstance().createHeaderFactory().createContactHeader(concatAddress));
  151 +
  152 + request.addHeader(SipUtils.createUserAgentHeader(gitUtil));
  153 +
  154 + // Subject
  155 + SubjectHeader subjectHeader = SipFactory.getInstance().createHeaderFactory().createSubjectHeader(String.format("%s:%s,%s:%s", channelId, ssrc, sipConfig.getId(), 0));
  156 + request.addHeader(subjectHeader);
  157 +
  158 + ContentTypeHeader contentTypeHeader = SipFactory.getInstance().createHeaderFactory().createContentTypeHeader("APPLICATION", "SDP");
  159 + request.setContent(content, contentTypeHeader);
  160 + return request;
  161 + }
  162 +
  163 + public Request createByteRequest(Device device, String channelId, SipTransactionInfo transactionInfo) throws ParseException, InvalidArgumentException, PeerUnavailableException {
  164 + Request request = null;
  165 + //请求行
  166 + SipURI requestLine = SipFactory.getInstance().createAddressFactory().createSipURI(channelId, device.getHostAddress());
  167 +// SipURI requestLine = SipFactory.getInstance().createAddressFactory().createSipURI(device.getDeviceId(), device.getHostAddress());
  168 + // via
  169 + ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();
  170 + ViaHeader viaHeader = SipFactory.getInstance().createHeaderFactory().createViaHeader(sipLayer.getLocalIp(device.getLocalIp()), sipConfig.getPort(), device.getTransport(), SipUtils.getNewViaTag());
  171 + viaHeaders.add(viaHeader);
  172 + //from
  173 + SipURI fromSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(),sipConfig.getDomain());
  174 + Address fromAddress = SipFactory.getInstance().createAddressFactory().createAddress(fromSipURI);
  175 + FromHeader fromHeader = SipFactory.getInstance().createHeaderFactory().createFromHeader(fromAddress, transactionInfo.getFromTag());
  176 + //to
  177 + SipURI toSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(channelId,device.getHostAddress());
  178 +// SipURI toSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(device.getDeviceId(),device.getHostAddress());
  179 + Address toAddress = SipFactory.getInstance().createAddressFactory().createAddress(toSipURI);
  180 + ToHeader toHeader = SipFactory.getInstance().createHeaderFactory().createToHeader(toAddress, transactionInfo.getToTag());
  181 +
  182 + //Forwards
  183 + MaxForwardsHeader maxForwards = SipFactory.getInstance().createHeaderFactory().createMaxForwardsHeader(70);
  184 +
  185 + //ceq
  186 + CSeqHeader cSeqHeader = SipFactory.getInstance().createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(), Request.BYE);
  187 + CallIdHeader callIdHeader = SipFactory.getInstance().createHeaderFactory().createCallIdHeader(transactionInfo.getCallId());
  188 + request = SipFactory.getInstance().createMessageFactory().createRequest(requestLine, Request.BYE, callIdHeader, cSeqHeader,fromHeader, toHeader, viaHeaders, maxForwards);
  189 +
  190 + request.addHeader(SipUtils.createUserAgentHeader(gitUtil));
  191 +
  192 + Address concatAddress = SipFactory.getInstance().createAddressFactory().createAddress(SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), sipLayer.getLocalIp(device.getLocalIp())+":"+sipConfig.getPort()));
  193 + request.addHeader(SipFactory.getInstance().createHeaderFactory().createContactHeader(concatAddress));
  194 +
  195 + request.addHeader(SipUtils.createUserAgentHeader(gitUtil));
  196 +
  197 + return request;
  198 + }
  199 +
  200 + public Request createByteRequestForDeviceInvite(Device device, String channelId, SipTransactionInfo transactionInfo) throws ParseException, InvalidArgumentException, PeerUnavailableException {
  201 + Request request = null;
  202 + //请求行
  203 + SipURI requestLine = SipFactory.getInstance().createAddressFactory().createSipURI(channelId, device.getHostAddress());
  204 + // via
  205 + ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();
  206 + ViaHeader viaHeader = SipFactory.getInstance().createHeaderFactory().createViaHeader(sipLayer.getLocalIp(device.getLocalIp()), sipConfig.getPort(), device.getTransport(), SipUtils.getNewViaTag());
  207 + viaHeaders.add(viaHeader);
  208 + //from
  209 + SipURI fromSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(),sipConfig.getDomain());
  210 + Address fromAddress = SipFactory.getInstance().createAddressFactory().createAddress(fromSipURI);
  211 + FromHeader fromHeader = SipFactory.getInstance().createHeaderFactory().createFromHeader(fromAddress, transactionInfo.getToTag());
  212 + //to
  213 + SipURI toSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(channelId,device.getHostAddress());
  214 + Address toAddress = SipFactory.getInstance().createAddressFactory().createAddress(toSipURI);
  215 + ToHeader toHeader = SipFactory.getInstance().createHeaderFactory().createToHeader(toAddress, transactionInfo.getFromTag());
  216 +
  217 + //Forwards
  218 + MaxForwardsHeader maxForwards = SipFactory.getInstance().createHeaderFactory().createMaxForwardsHeader(70);
  219 +
  220 + //ceq
  221 + CSeqHeader cSeqHeader = SipFactory.getInstance().createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(), Request.BYE);
  222 + CallIdHeader callIdHeader = SipFactory.getInstance().createHeaderFactory().createCallIdHeader(transactionInfo.getCallId());
  223 + request = SipFactory.getInstance().createMessageFactory().createRequest(requestLine, Request.BYE, callIdHeader, cSeqHeader,fromHeader, toHeader, viaHeaders, maxForwards);
  224 +
  225 + request.addHeader(SipUtils.createUserAgentHeader(gitUtil));
  226 +
  227 + Address concatAddress = SipFactory.getInstance().createAddressFactory().createAddress(SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), sipLayer.getLocalIp(device.getLocalIp())+":"+sipConfig.getPort()));
  228 + request.addHeader(SipFactory.getInstance().createHeaderFactory().createContactHeader(concatAddress));
  229 +
  230 + request.addHeader(SipUtils.createUserAgentHeader(gitUtil));
  231 +
  232 + return request;
  233 + }
  234 +
  235 + public Request createSubscribeRequest(Device device, String content, SIPRequest requestOld, Integer expires, String event, CallIdHeader callIdHeader) throws ParseException, InvalidArgumentException, PeerUnavailableException {
  236 + Request request = null;
  237 + // sipuri
  238 + SipURI requestURI = SipFactory.getInstance().createAddressFactory().createSipURI(device.getDeviceId(), device.getHostAddress());
  239 + // via
  240 + ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();
  241 + ViaHeader viaHeader = SipFactory.getInstance().createHeaderFactory().createViaHeader(sipLayer.getLocalIp(device.getLocalIp()), sipConfig.getPort(),
  242 + device.getTransport(), SipUtils.getNewViaTag());
  243 + viaHeader.setRPort();
  244 + viaHeaders.add(viaHeader);
  245 + // from
  246 + SipURI fromSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), sipConfig.getDomain());
  247 + Address fromAddress = SipFactory.getInstance().createAddressFactory().createAddress(fromSipURI);
  248 + FromHeader fromHeader = SipFactory.getInstance().createHeaderFactory().createFromHeader(fromAddress, requestOld == null ? SipUtils.getNewFromTag() :requestOld.getFromTag());
  249 + // to
  250 + SipURI toSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(device.getDeviceId(), device.getHostAddress());
  251 + Address toAddress = SipFactory.getInstance().createAddressFactory().createAddress(toSipURI);
  252 + ToHeader toHeader = SipFactory.getInstance().createHeaderFactory().createToHeader(toAddress, requestOld == null ? null :requestOld.getToTag());
  253 +
  254 + // Forwards
  255 + MaxForwardsHeader maxForwards = SipFactory.getInstance().createHeaderFactory().createMaxForwardsHeader(70);
  256 +
  257 + // ceq
  258 + CSeqHeader cSeqHeader = SipFactory.getInstance().createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(), Request.SUBSCRIBE);
  259 +
  260 + request = SipFactory.getInstance().createMessageFactory().createRequest(requestURI, Request.SUBSCRIBE, callIdHeader, cSeqHeader, fromHeader,
  261 + toHeader, viaHeaders, maxForwards);
  262 +
  263 +
  264 + Address concatAddress = SipFactory.getInstance().createAddressFactory().createAddress(SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), sipLayer.getLocalIp(device.getLocalIp())+":"+sipConfig.getPort()));
  265 + request.addHeader(SipFactory.getInstance().createHeaderFactory().createContactHeader(concatAddress));
  266 +
  267 + // Expires
  268 + ExpiresHeader expireHeader = SipFactory.getInstance().createHeaderFactory().createExpiresHeader(expires);
  269 + request.addHeader(expireHeader);
  270 +
  271 + // Event
  272 + EventHeader eventHeader = SipFactory.getInstance().createHeaderFactory().createEventHeader(event);
  273 +
  274 + int random = (int) Math.floor(Math.random() * 10000);
  275 + eventHeader.setEventId(random + "");
  276 + request.addHeader(eventHeader);
  277 +
  278 + ContentTypeHeader contentTypeHeader = SipFactory.getInstance().createHeaderFactory().createContentTypeHeader("Application", "MANSCDP+xml");
  279 + request.setContent(content, contentTypeHeader);
  280 +
  281 + request.addHeader(SipUtils.createUserAgentHeader(gitUtil));
  282 +
  283 + return request;
  284 + }
  285 +
  286 + public SIPRequest createInfoRequest(Device device, String channelId, String content, SipTransactionInfo transactionInfo)
  287 + throws SipException, ParseException, InvalidArgumentException {
  288 + if (device == null || transactionInfo == null) {
  289 + return null;
  290 + }
  291 + SIPRequest request = null;
  292 + //请求行
  293 + SipURI requestLine = SipFactory.getInstance().createAddressFactory().createSipURI(channelId, device.getHostAddress());
  294 + // via
  295 + ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();
  296 + ViaHeader viaHeader = SipFactory.getInstance().createHeaderFactory().createViaHeader(sipLayer.getLocalIp(device.getLocalIp()), sipConfig.getPort(), device.getTransport(), SipUtils.getNewViaTag());
  297 + viaHeaders.add(viaHeader);
  298 + //from
  299 + SipURI fromSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(),sipConfig.getDomain());
  300 + Address fromAddress = SipFactory.getInstance().createAddressFactory().createAddress(fromSipURI);
  301 + FromHeader fromHeader = SipFactory.getInstance().createHeaderFactory().createFromHeader(fromAddress, transactionInfo.getFromTag());
  302 + //to
  303 + SipURI toSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(channelId,device.getHostAddress());
  304 + Address toAddress = SipFactory.getInstance().createAddressFactory().createAddress(toSipURI);
  305 + ToHeader toHeader = SipFactory.getInstance().createHeaderFactory().createToHeader(toAddress, transactionInfo.getToTag());
  306 +
  307 + //Forwards
  308 + MaxForwardsHeader maxForwards = SipFactory.getInstance().createHeaderFactory().createMaxForwardsHeader(70);
  309 +
  310 + //ceq
  311 + CSeqHeader cSeqHeader = SipFactory.getInstance().createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(), Request.INFO);
  312 + CallIdHeader callIdHeader = SipFactory.getInstance().createHeaderFactory().createCallIdHeader(transactionInfo.getCallId());
  313 + request = (SIPRequest)SipFactory.getInstance().createMessageFactory().createRequest(requestLine, Request.INFO, callIdHeader, cSeqHeader,fromHeader, toHeader, viaHeaders, maxForwards);
  314 +
  315 + request.addHeader(SipUtils.createUserAgentHeader(gitUtil));
  316 +
  317 + Address concatAddress = SipFactory.getInstance().createAddressFactory().createAddress(SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), sipLayer.getLocalIp(device.getLocalIp())+":"+sipConfig.getPort()));
  318 + request.addHeader(SipFactory.getInstance().createHeaderFactory().createContactHeader(concatAddress));
  319 +
  320 + request.addHeader(SipUtils.createUserAgentHeader(gitUtil));
  321 +
  322 + if (content != null) {
  323 + ContentTypeHeader contentTypeHeader = SipFactory.getInstance().createHeaderFactory().createContentTypeHeader("Application",
  324 + "MANSRTSP");
  325 + request.setContent(content, contentTypeHeader);
  326 + }
  327 + return request;
  328 + }
  329 +
  330 + public Request createAckRequest(String localIp, SipURI sipURI, SIPResponse sipResponse) throws ParseException, InvalidArgumentException, PeerUnavailableException {
  331 +
  332 +
  333 + // via
  334 + ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();
  335 + ViaHeader viaHeader = SipFactory.getInstance().createHeaderFactory().createViaHeader(localIp, sipConfig.getPort(), sipResponse.getTopmostViaHeader().getTransport(), SipUtils.getNewViaTag());
  336 + viaHeaders.add(viaHeader);
  337 +
  338 + //Forwards
  339 + MaxForwardsHeader maxForwards = SipFactory.getInstance().createHeaderFactory().createMaxForwardsHeader(70);
  340 +
  341 + //ceq
  342 + CSeqHeader cSeqHeader = SipFactory.getInstance().createHeaderFactory().createCSeqHeader(sipResponse.getCSeqHeader().getSeqNumber(), Request.ACK);
  343 +
  344 + Request request = SipFactory.getInstance().createMessageFactory().createRequest(sipURI, Request.ACK, sipResponse.getCallIdHeader(), cSeqHeader, sipResponse.getFromHeader(), sipResponse.getToHeader(), viaHeaders, maxForwards);
  345 +
  346 + request.addHeader(SipUtils.createUserAgentHeader(gitUtil));
  347 +
  348 + Address concatAddress = SipFactory.getInstance().createAddressFactory().createAddress(SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), localIp + ":"+sipConfig.getPort()));
  349 + request.addHeader(SipFactory.getInstance().createHeaderFactory().createContactHeader(concatAddress));
  350 +
  351 + request.addHeader(SipUtils.createUserAgentHeader(gitUtil));
  352 +
  353 + return request;
  354 + }
  355 + public Request createBroadcastMessageRequest(Device device, String channelId, String content, String viaTag, String fromTag, String toTag, CallIdHeader callIdHeader) throws ParseException, InvalidArgumentException, PeerUnavailableException {
  356 + Request request = null;
  357 + // sipuri
  358 + SipURI requestURI = SipFactory.getInstance().createAddressFactory().createSipURI(channelId, device.getHostAddress());
  359 + // via
  360 + ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();
  361 + ViaHeader viaHeader = SipFactory.getInstance().createHeaderFactory().createViaHeader(sipConfig.getIp(), sipConfig.getPort(), device.getTransport(), viaTag);
  362 + viaHeader.setRPort();
  363 + viaHeaders.add(viaHeader);
  364 + // from
  365 + SipURI fromSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), sipConfig.getDomain());
  366 + Address fromAddress = SipFactory.getInstance().createAddressFactory().createAddress(fromSipURI);
  367 + FromHeader fromHeader = SipFactory.getInstance().createHeaderFactory().createFromHeader(fromAddress, fromTag);
  368 + // to
  369 + SipURI toSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(channelId, device.getHostAddress());
  370 + Address toAddress = SipFactory.getInstance().createAddressFactory().createAddress(toSipURI);
  371 + ToHeader toHeader = SipFactory.getInstance().createHeaderFactory().createToHeader(toAddress, toTag);
  372 +
  373 + // Forwards
  374 + MaxForwardsHeader maxForwards = SipFactory.getInstance().createHeaderFactory().createMaxForwardsHeader(70);
  375 + // ceq
  376 + CSeqHeader cSeqHeader = SipFactory.getInstance().createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(), Request.MESSAGE);
  377 +
  378 + ContentTypeHeader contentTypeHeader = SipFactory.getInstance().createHeaderFactory().createContentTypeHeader("Application", "MANSCDP+xml");
  379 +
  380 + request = SipFactory.getInstance().createMessageFactory().createRequest(requestURI, Request.MESSAGE, callIdHeader, cSeqHeader, fromHeader,
  381 + toHeader, viaHeaders, maxForwards, contentTypeHeader, content);
  382 +
  383 + request.addHeader(SipUtils.createUserAgentHeader(gitUtil));
  384 +
  385 + return request;
  386 + }
  387 +}
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java
1 -package com.genersoft.iot.vmp.gb28181.transmit.cmd.impl;  
2 -  
3 -import com.genersoft.iot.vmp.common.InviteSessionType;  
4 -import com.genersoft.iot.vmp.common.StreamInfo;  
5 -import com.genersoft.iot.vmp.conf.SipConfig;  
6 -import com.genersoft.iot.vmp.conf.UserSetting;  
7 -import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException;  
8 -import com.genersoft.iot.vmp.gb28181.SipLayer;  
9 -import com.genersoft.iot.vmp.gb28181.bean.Device;  
10 -import com.genersoft.iot.vmp.gb28181.bean.DeviceAlarm;  
11 -import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;  
12 -import com.genersoft.iot.vmp.gb28181.bean.SsrcTransaction;  
13 -import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;  
14 -import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;  
15 -import com.genersoft.iot.vmp.gb28181.transmit.SIPSender;  
16 -import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander;  
17 -import com.genersoft.iot.vmp.gb28181.transmit.cmd.SIPRequestHeaderProvider;  
18 -import com.genersoft.iot.vmp.gb28181.utils.NumericUtil;  
19 -import com.genersoft.iot.vmp.gb28181.utils.SipUtils;  
20 -import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe;  
21 -import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeFactory;  
22 -import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForStreamChange;  
23 -import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;  
24 -import com.genersoft.iot.vmp.media.zlm.dto.hook.HookParam;  
25 -import com.genersoft.iot.vmp.service.IMediaServerService;  
26 -import com.genersoft.iot.vmp.service.bean.SSRCInfo;  
27 -import com.genersoft.iot.vmp.utils.DateUtil;  
28 -import gov.nist.javax.sip.message.SIPRequest;  
29 -import gov.nist.javax.sip.message.SIPResponse;  
30 -import org.slf4j.Logger;  
31 -import org.slf4j.LoggerFactory;  
32 -import org.springframework.beans.factory.annotation.Autowired;  
33 -import org.springframework.context.annotation.DependsOn;  
34 -import org.springframework.stereotype.Component;  
35 -import org.springframework.util.ObjectUtils;  
36 -  
37 -import javax.sip.InvalidArgumentException;  
38 -import javax.sip.ResponseEvent;  
39 -import javax.sip.SipException;  
40 -import javax.sip.SipFactory;  
41 -import javax.sip.header.CallIdHeader;  
42 -import javax.sip.message.Request;  
43 -import java.text.ParseException;  
44 -import java.util.List;  
45 -  
46 -/**  
47 - * @description:设备能力接口,用于定义设备的控制、查询能力  
48 - * @author: swwheihei  
49 - * @date: 2020年5月3日 下午9:22:48  
50 - */  
51 -@Component  
52 -@DependsOn("sipLayer")  
53 -public class SIPCommander implements ISIPCommander {  
54 -  
55 - private final Logger logger = LoggerFactory.getLogger(SIPCommander.class);  
56 -  
57 - @Autowired  
58 - private SipConfig sipConfig;  
59 -  
60 - @Autowired  
61 - private SipLayer sipLayer;  
62 -  
63 - @Autowired  
64 - private SIPSender sipSender;  
65 -  
66 - @Autowired  
67 - private SIPRequestHeaderProvider headerProvider;  
68 -  
69 - @Autowired  
70 - private VideoStreamSessionManager streamSession;  
71 -  
72 - @Autowired  
73 - private UserSetting userSetting;  
74 -  
75 - @Autowired  
76 - private ZlmHttpHookSubscribe subscribe;  
77 -  
78 -  
79 -  
80 - @Autowired  
81 - private IMediaServerService mediaServerService;  
82 -  
83 -  
84 - /**  
85 - * 云台方向放控制,使用配置文件中的默认镜头移动速度  
86 - *  
87 - * @param device 控制设备  
88 - * @param channelId 预览通道  
89 - * @param leftRight 镜头左移右移 0:停止 1:左移 2:右移  
90 - * @param upDown 镜头上移下移 0:停止 1:上移 2:下移  
91 - */  
92 - @Override  
93 - public void ptzdirectCmd(Device device, String channelId, int leftRight, int upDown) throws InvalidArgumentException, ParseException, SipException {  
94 - ptzCmd(device, channelId, leftRight, upDown, 0, sipConfig.getPtzSpeed(), 0);  
95 - }  
96 -  
97 - /**  
98 - * 云台方向放控制  
99 - *  
100 - * @param device 控制设备  
101 - * @param channelId 预览通道  
102 - * @param leftRight 镜头左移右移 0:停止 1:左移 2:右移  
103 - * @param upDown 镜头上移下移 0:停止 1:上移 2:下移  
104 - * @param moveSpeed 镜头移动速度  
105 - */  
106 - @Override  
107 - public void ptzdirectCmd(Device device, String channelId, int leftRight, int upDown, int moveSpeed) throws InvalidArgumentException, ParseException, SipException {  
108 - ptzCmd(device, channelId, leftRight, upDown, 0, moveSpeed, 0);  
109 - }  
110 -  
111 - /**  
112 - * 云台缩放控制,使用配置文件中的默认镜头缩放速度  
113 - *  
114 - * @param device 控制设备  
115 - * @param channelId 预览通道  
116 - * @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大  
117 - */  
118 - @Override  
119 - public void ptzZoomCmd(Device device, String channelId, int inOut) throws InvalidArgumentException, ParseException, SipException {  
120 - ptzCmd(device, channelId, 0, 0, inOut, 0, sipConfig.getPtzSpeed());  
121 - }  
122 -  
123 - /**  
124 - * 云台缩放控制  
125 - *  
126 - * @param device 控制设备  
127 - * @param channelId 预览通道  
128 - * @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大  
129 - * @param zoomSpeed 镜头缩放速度  
130 - */  
131 - @Override  
132 - public void ptzZoomCmd(Device device, String channelId, int inOut, int zoomSpeed) throws InvalidArgumentException, ParseException, SipException {  
133 - ptzCmd(device, channelId, 0, 0, inOut, 0, zoomSpeed);  
134 - }  
135 -  
136 - /**  
137 - * 云台指令码计算  
138 - *  
139 - * @param cmdCode 指令码  
140 - * @param parameter1 数据1  
141 - * @param parameter2 数据2  
142 - * @param combineCode2 组合码2  
143 - */  
144 - public static String frontEndCmdString(int cmdCode, int parameter1, int parameter2, int combineCode2) {  
145 - StringBuilder builder = new StringBuilder("A50F01");  
146 - String strTmp;  
147 - strTmp = String.format("%02X", cmdCode);  
148 - builder.append(strTmp, 0, 2);  
149 - strTmp = String.format("%02X", parameter1);  
150 - builder.append(strTmp, 0, 2);  
151 - strTmp = String.format("%02X", parameter2);  
152 - builder.append(strTmp, 0, 2);  
153 - //优化zoom变倍速率  
154 - if ((combineCode2 > 0) && (combineCode2 <16))  
155 - {  
156 - combineCode2 = 16;  
157 - }  
158 - strTmp = String.format("%X", combineCode2);  
159 - builder.append(strTmp, 0, 1).append("0");  
160 - //计算校验码  
161 - int checkCode = (0XA5 + 0X0F + 0X01 + cmdCode + parameter1 + parameter2 + (combineCode2 & 0XF0)) % 0X100;  
162 - strTmp = String.format("%02X", checkCode);  
163 - builder.append(strTmp, 0, 2);  
164 - return builder.toString();  
165 - }  
166 -  
167 - /**  
168 - * 云台控制,支持方向与缩放控制  
169 - *  
170 - * @param device 控制设备  
171 - * @param channelId 预览通道  
172 - * @param leftRight 镜头左移右移 0:停止 1:左移 2:右移  
173 - * @param upDown 镜头上移下移 0:停止 1:上移 2:下移  
174 - * @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大  
175 - * @param moveSpeed 镜头移动速度  
176 - * @param zoomSpeed 镜头缩放速度  
177 - */  
178 - @Override  
179 - public void ptzCmd(Device device, String channelId, int leftRight, int upDown, int inOut, int moveSpeed,  
180 - int zoomSpeed) throws InvalidArgumentException, SipException, ParseException {  
181 - String cmdStr = SipUtils.cmdString(leftRight, upDown, inOut, moveSpeed, zoomSpeed);  
182 - StringBuilder ptzXml = new StringBuilder(200);  
183 - String charset = device.getCharset();  
184 - ptzXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");  
185 - ptzXml.append("<Control>\r\n");  
186 - ptzXml.append("<CmdType>DeviceControl</CmdType>\r\n");  
187 - ptzXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");  
188 - ptzXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");  
189 - ptzXml.append("<PTZCmd>" + cmdStr + "</PTZCmd>\r\n");  
190 - ptzXml.append("<Info>\r\n");  
191 - ptzXml.append("<ControlPriority>5</ControlPriority>\r\n");  
192 - ptzXml.append("</Info>\r\n");  
193 - ptzXml.append("</Control>\r\n");  
194 -  
195 - Request request = headerProvider.createMessageRequest(device, ptzXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null, sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));  
196 -  
197 - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()),request);  
198 - }  
199 -  
200 - /**  
201 - * 前端控制,包括PTZ指令、FI指令、预置位指令、巡航指令、扫描指令和辅助开关指令  
202 - *  
203 - * @param device 控制设备  
204 - * @param channelId 预览通道  
205 - * @param cmdCode 指令码  
206 - * @param parameter1 数据1  
207 - * @param parameter2 数据2  
208 - * @param combineCode2 组合码2  
209 - */  
210 - @Override  
211 - public void frontEndCmd(Device device, String channelId, int cmdCode, int parameter1, int parameter2, int combineCode2) throws SipException, InvalidArgumentException, ParseException {  
212 -  
213 - String cmdStr = frontEndCmdString(cmdCode, parameter1, parameter2, combineCode2);  
214 - StringBuffer ptzXml = new StringBuffer(200);  
215 - String charset = device.getCharset();  
216 - ptzXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");  
217 - ptzXml.append("<Control>\r\n");  
218 - ptzXml.append("<CmdType>DeviceControl</CmdType>\r\n");  
219 - ptzXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");  
220 - ptzXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");  
221 - ptzXml.append("<PTZCmd>" + cmdStr + "</PTZCmd>\r\n");  
222 - ptzXml.append("<Info>\r\n");  
223 - ptzXml.append("<ControlPriority>5</ControlPriority>\r\n");  
224 - ptzXml.append("</Info>\r\n");  
225 - ptzXml.append("</Control>\r\n");  
226 -  
227 -  
228 -  
229 -  
230 - SIPRequest request = (SIPRequest) headerProvider.createMessageRequest(device, ptzXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));  
231 - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()),request);  
232 -  
233 - }  
234 -  
235 - /**  
236 - * 前端控制指令(用于转发上级指令)  
237 - *  
238 - * @param device 控制设备  
239 - * @param channelId 预览通道  
240 - * @param cmdString 前端控制指令串  
241 - */  
242 - @Override  
243 - public void fronEndCmd(Device device, String channelId, String cmdString, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException {  
244 -  
245 - StringBuffer ptzXml = new StringBuffer(200);  
246 - String charset = device.getCharset();  
247 - ptzXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");  
248 - ptzXml.append("<Control>\r\n");  
249 - ptzXml.append("<CmdType>DeviceControl</CmdType>\r\n");  
250 - ptzXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");  
251 - ptzXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");  
252 - ptzXml.append("<PTZCmd>" + cmdString + "</PTZCmd>\r\n");  
253 - ptzXml.append("<Info>\r\n");  
254 - ptzXml.append("<ControlPriority>5</ControlPriority>\r\n");  
255 - ptzXml.append("</Info>\r\n");  
256 - ptzXml.append("</Control>\r\n");  
257 -  
258 -  
259 - Request request = headerProvider.createMessageRequest(device, ptzXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));  
260 - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()),request, errorEvent, okEvent);  
261 -  
262 - }  
263 -  
264 - /**  
265 - * 请求预览视频流  
266 - *  
267 - * @param device 视频设备  
268 - * @param channel 预览通道  
269 - * @param event hook订阅  
270 - * @param errorEvent sip错误订阅  
271 - */  
272 - @Override  
273 - public void playStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, DeviceChannel channel,  
274 - ZlmHttpHookSubscribe.Event event, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException {  
275 - String stream = ssrcInfo.getStream();  
276 -  
277 - if (device == null) {  
278 - return;  
279 - }  
280 -  
281 - logger.info("{} 分配的ZLM为: {} [{}:{}]", stream, mediaServerItem.getId(), mediaServerItem.getSdpIp(), ssrcInfo.getPort());  
282 - HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", stream, true, "rtsp", mediaServerItem.getId());  
283 - subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, HookParam hookParam) -> {  
284 - if (event != null) {  
285 - event.response(mediaServerItemInUse, hookParam);  
286 - subscribe.removeSubscribe(hookSubscribe);  
287 - }  
288 - });  
289 - String sdpIp;  
290 - if (!ObjectUtils.isEmpty(device.getSdpIp())) {  
291 - sdpIp = device.getSdpIp();  
292 - }else {  
293 - sdpIp = mediaServerItem.getSdpIp();  
294 - }  
295 - StringBuffer content = new StringBuffer(200);  
296 - content.append("v=0\r\n");  
297 - content.append("o=" + channel.getChannelId() + " 0 0 IN IP4 " + sdpIp + "\r\n");  
298 - content.append("s=Play\r\n");  
299 - content.append("c=IN IP4 " + sdpIp + "\r\n");  
300 - content.append("t=0 0\r\n");  
301 -  
302 - if (userSetting.isSeniorSdp()) {  
303 - if ("TCP-PASSIVE".equalsIgnoreCase(device.getStreamMode())) {  
304 - content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 126 125 99 34 98 97\r\n");  
305 - } else if ("TCP-ACTIVE".equalsIgnoreCase(device.getStreamMode())) {  
306 - content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 126 125 99 34 98 97\r\n");  
307 - } else if ("UDP".equalsIgnoreCase(device.getStreamMode())) {  
308 - content.append("m=video " + ssrcInfo.getPort() + " RTP/AVP 96 126 125 99 34 98 97\r\n");  
309 - }  
310 - content.append("a=recvonly\r\n");  
311 - content.append("a=rtpmap:96 PS/90000\r\n");  
312 - content.append("a=fmtp:126 profile-level-id=42e01e\r\n");  
313 - content.append("a=rtpmap:126 H264/90000\r\n");  
314 - content.append("a=rtpmap:125 H264S/90000\r\n");  
315 - content.append("a=fmtp:125 profile-level-id=42e01e\r\n");  
316 - content.append("a=rtpmap:99 H265/90000\r\n");  
317 - content.append("a=rtpmap:98 H264/90000\r\n");  
318 - content.append("a=rtpmap:97 MPEG4/90000\r\n");  
319 - if ("TCP-PASSIVE".equalsIgnoreCase(device.getStreamMode())) { // tcp被动模式  
320 - content.append("a=setup:passive\r\n");  
321 - content.append("a=connection:new\r\n");  
322 - } else if ("TCP-ACTIVE".equalsIgnoreCase(device.getStreamMode())) { // tcp主动模式  
323 - content.append("a=setup:active\r\n");  
324 - content.append("a=connection:new\r\n");  
325 - }  
326 - } else {  
327 - if ("TCP-PASSIVE".equalsIgnoreCase(device.getStreamMode())) {  
328 - content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 97 98 99\r\n");  
329 - } else if ("TCP-ACTIVE".equalsIgnoreCase(device.getStreamMode())) {  
330 - content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 97 98 99\r\n");  
331 - } else if ("UDP".equalsIgnoreCase(device.getStreamMode())) {  
332 - content.append("m=video " + ssrcInfo.getPort() + " RTP/AVP 96 97 98 99\r\n");  
333 - }  
334 - content.append("a=recvonly\r\n");  
335 - content.append("a=rtpmap:96 PS/90000\r\n");  
336 - content.append("a=rtpmap:98 H264/90000\r\n");  
337 - content.append("a=rtpmap:97 MPEG4/90000\r\n");  
338 - content.append("a=rtpmap:99 H265/90000\r\n");  
339 - if ("TCP-PASSIVE".equalsIgnoreCase(device.getStreamMode())) { // tcp被动模式  
340 - content.append("a=setup:passive\r\n");  
341 - content.append("a=connection:new\r\n");  
342 - } else if ("TCP-ACTIVE".equalsIgnoreCase(device.getStreamMode())) { // tcp主动模式  
343 - content.append("a=setup:active\r\n");  
344 - content.append("a=connection:new\r\n");  
345 - }  
346 - }  
347 -  
348 - if (!ObjectUtils.isEmpty(channel.getStreamIdentification())) {  
349 - content.append("a=" + channel.getStreamIdentification() + "\r\n");  
350 - }  
351 -  
352 - content.append("y=" + ssrcInfo.getSsrc() + "\r\n");//ssrc  
353 - // f字段:f= v/编码格式/分辨率/帧率/码率类型/码率大小a/编码格式/码率大小/采样率  
354 -// content.append("f=v/2/5/25/1/4000a/1/8/1" + "\r\n"); // 未发现支持此特性的设备  
355 -  
356 -  
357 -  
358 - Request request = headerProvider.createInviteRequest(device, channel.getChannelId(), content.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null, ssrcInfo.getSsrc(),sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));  
359 - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, (e -> {  
360 - streamSession.remove(device.getDeviceId(), channel.getChannelId(), ssrcInfo.getStream());  
361 - mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());  
362 - errorEvent.response(e);  
363 - }), e -> {  
364 - ResponseEvent responseEvent = (ResponseEvent) e.event;  
365 - SIPResponse response = (SIPResponse) responseEvent.getResponse();  
366 - String callId = response.getCallIdHeader().getCallId();  
367 - streamSession.put(device.getDeviceId(), channel.getChannelId(), callId, stream, ssrcInfo.getSsrc(), mediaServerItem.getId(), response,  
368 - InviteSessionType.PLAY);  
369 - okEvent.response(e);  
370 - });  
371 - }  
372 -  
373 - /**  
374 - * 请求回放视频流  
375 - *  
376 - * @param device 视频设备  
377 - * @param channelId 预览通道  
378 - * @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss  
379 - * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss  
380 - */  
381 - @Override  
382 - public void playbackStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId,  
383 - String startTime, String endTime, ZlmHttpHookSubscribe.Event hookEvent,  
384 - SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException {  
385 -  
386 -  
387 - logger.info("{} 分配的ZLM为: {} [{}:{}]", ssrcInfo.getStream(), mediaServerItem.getId(), mediaServerItem.getSdpIp(), ssrcInfo.getPort());  
388 - String sdpIp;  
389 - if (!ObjectUtils.isEmpty(device.getSdpIp())) {  
390 - sdpIp = device.getSdpIp();  
391 - }else {  
392 - sdpIp = mediaServerItem.getSdpIp();  
393 - }  
394 - StringBuffer content = new StringBuffer(200);  
395 - content.append("v=0\r\n");  
396 - content.append("o=" + channelId + " 0 0 IN IP4 " + sdpIp + "\r\n");  
397 - content.append("s=Playback\r\n");  
398 - content.append("u=" + channelId + ":0\r\n");  
399 - content.append("c=IN IP4 " + sdpIp + "\r\n");  
400 - content.append("t=" + DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(startTime) + " "  
401 - + DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(endTime) + "\r\n");  
402 -  
403 - String streamMode = device.getStreamMode();  
404 -  
405 - if (userSetting.isSeniorSdp()) {  
406 - if ("TCP-PASSIVE".equalsIgnoreCase(streamMode)) {  
407 - content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 126 125 99 34 98 97\r\n");  
408 - } else if ("TCP-ACTIVE".equalsIgnoreCase(streamMode)) {  
409 - content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 126 125 99 34 98 97\r\n");  
410 - } else if ("UDP".equalsIgnoreCase(streamMode)) {  
411 - content.append("m=video " + ssrcInfo.getPort() + " RTP/AVP 96 126 125 99 34 98 97\r\n");  
412 - }  
413 - content.append("a=recvonly\r\n");  
414 - content.append("a=rtpmap:96 PS/90000\r\n");  
415 - content.append("a=fmtp:126 profile-level-id=42e01e\r\n");  
416 - content.append("a=rtpmap:126 H264/90000\r\n");  
417 - content.append("a=rtpmap:125 H264S/90000\r\n");  
418 - content.append("a=fmtp:125 profile-level-id=42e01e\r\n");  
419 - content.append("a=rtpmap:99 H265/90000\r\n");  
420 - content.append("a=rtpmap:98 H264/90000\r\n");  
421 - content.append("a=rtpmap:97 MPEG4/90000\r\n");  
422 - if ("TCP-PASSIVE".equalsIgnoreCase(streamMode)) { // tcp被动模式  
423 - content.append("a=setup:passive\r\n");  
424 - content.append("a=connection:new\r\n");  
425 - } else if ("TCP-ACTIVE".equalsIgnoreCase(streamMode)) { // tcp主动模式  
426 - content.append("a=setup:active\r\n");  
427 - content.append("a=connection:new\r\n");  
428 - }  
429 - } else {  
430 - if ("TCP-PASSIVE".equalsIgnoreCase(streamMode)) {  
431 - content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 97 98 99\r\n");  
432 - } else if ("TCP-ACTIVE".equalsIgnoreCase(streamMode)) {  
433 - content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 97 98 99\r\n");  
434 - } else if ("UDP".equalsIgnoreCase(streamMode)) {  
435 - content.append("m=video " + ssrcInfo.getPort() + " RTP/AVP 96 97 98 99\r\n");  
436 - }  
437 - content.append("a=recvonly\r\n");  
438 - content.append("a=rtpmap:96 PS/90000\r\n");  
439 - content.append("a=rtpmap:97 MPEG4/90000\r\n");  
440 - content.append("a=rtpmap:98 H264/90000\r\n");  
441 - content.append("a=rtpmap:99 H265/90000\r\n");  
442 - if ("TCP-PASSIVE".equalsIgnoreCase(streamMode)) {  
443 - // tcp被动模式  
444 - content.append("a=setup:passive\r\n");  
445 - content.append("a=connection:new\r\n");  
446 - } else if ("TCP-ACTIVE".equalsIgnoreCase(streamMode)) {  
447 - // tcp主动模式  
448 - content.append("a=setup:active\r\n");  
449 - content.append("a=connection:new\r\n");  
450 - }  
451 - }  
452 -  
453 - //ssrc  
454 - content.append("y=" + ssrcInfo.getSsrc() + "\r\n");  
455 -  
456 - HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", ssrcInfo.getStream(), true, "rtsp", mediaServerItem.getId());  
457 - // 添加订阅  
458 - subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, HookParam hookParam) -> {  
459 - if (hookEvent != null) {  
460 - hookEvent.response(mediaServerItemInUse, hookParam);  
461 - }  
462 - subscribe.removeSubscribe(hookSubscribe);  
463 - });  
464 - Request request = headerProvider.createPlaybackInviteRequest(device, channelId, content.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()), ssrcInfo.getSsrc());  
465 -  
466 - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent, event -> {  
467 - ResponseEvent responseEvent = (ResponseEvent) event.event;  
468 - SIPResponse response = (SIPResponse) responseEvent.getResponse();  
469 - streamSession.put(device.getDeviceId(), channelId,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()).getCallId(), ssrcInfo.getStream(), ssrcInfo.getSsrc(), mediaServerItem.getId(), response, InviteSessionType.PLAYBACK);  
470 - okEvent.response(event);  
471 - });  
472 - }  
473 -  
474 - /**  
475 - * 请求历史媒体下载  
476 - *  
477 - * @param device 视频设备  
478 - * @param channelId 预览通道  
479 - * @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss  
480 - * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss  
481 - * @param downloadSpeed 下载倍速参数  
482 - */  
483 - @Override  
484 - public void downloadStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId,  
485 - String startTime, String endTime, int downloadSpeed,  
486 - ZlmHttpHookSubscribe.Event hookEvent,  
487 - SipSubscribe.Event errorEvent,SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException {  
488 -  
489 - logger.info("{} 分配的ZLM为: {} [{}:{}]", ssrcInfo.getStream(), mediaServerItem.getId(), mediaServerItem.getSdpIp(), ssrcInfo.getPort());  
490 - String sdpIp;  
491 - if (!ObjectUtils.isEmpty(device.getSdpIp())) {  
492 - sdpIp = device.getSdpIp();  
493 - }else {  
494 - sdpIp = mediaServerItem.getSdpIp();  
495 - }  
496 - StringBuffer content = new StringBuffer(200);  
497 - content.append("v=0\r\n");  
498 - content.append("o=" + channelId + " 0 0 IN IP4 " + sdpIp + "\r\n");  
499 - content.append("s=Download\r\n");  
500 - content.append("u=" + channelId + ":0\r\n");  
501 - content.append("c=IN IP4 " + sdpIp + "\r\n");  
502 - content.append("t=" + DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(startTime) + " "  
503 - + DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(endTime) + "\r\n");  
504 -  
505 - String streamMode = device.getStreamMode().toUpperCase();  
506 -  
507 - if (userSetting.isSeniorSdp()) {  
508 - if ("TCP-PASSIVE".equals(streamMode)) {  
509 - content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 126 125 99 34 98 97\r\n");  
510 - } else if ("TCP-ACTIVE".equals(streamMode)) {  
511 - content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 126 125 99 34 98 97\r\n");  
512 - } else if ("UDP".equals(streamMode)) {  
513 - content.append("m=video " + ssrcInfo.getPort() + " RTP/AVP 96 126 125 99 34 98 97\r\n");  
514 - }  
515 - content.append("a=recvonly\r\n");  
516 - content.append("a=rtpmap:96 PS/90000\r\n");  
517 - content.append("a=fmtp:126 profile-level-id=42e01e\r\n");  
518 - content.append("a=rtpmap:126 H264/90000\r\n");  
519 - content.append("a=rtpmap:125 H264S/90000\r\n");  
520 - content.append("a=fmtp:125 profile-level-id=42e01e\r\n");  
521 - content.append("a=rtpmap:99 MP4V-ES/90000\r\n");  
522 - content.append("a=fmtp:99 profile-level-id=3\r\n");  
523 - content.append("a=rtpmap:98 H264/90000\r\n");  
524 - content.append("a=rtpmap:97 MPEG4/90000\r\n");  
525 - if ("TCP-PASSIVE".equals(streamMode)) { // tcp被动模式  
526 - content.append("a=setup:passive\r\n");  
527 - content.append("a=connection:new\r\n");  
528 - } else if ("TCP-ACTIVE".equals(streamMode)) { // tcp主动模式  
529 - content.append("a=setup:active\r\n");  
530 - content.append("a=connection:new\r\n");  
531 - }  
532 - } else {  
533 - if ("TCP-PASSIVE".equals(streamMode)) {  
534 - content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 97 98 99\r\n");  
535 - } else if ("TCP-ACTIVE".equals(streamMode)) {  
536 - content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 97 98 99\r\n");  
537 - } else if ("UDP".equals(streamMode)) {  
538 - content.append("m=video " + ssrcInfo.getPort() + " RTP/AVP 96 97 98 99\r\n");  
539 - }  
540 - content.append("a=recvonly\r\n");  
541 - content.append("a=rtpmap:96 PS/90000\r\n");  
542 - content.append("a=rtpmap:97 MPEG4/90000\r\n");  
543 - content.append("a=rtpmap:98 H264/90000\r\n");  
544 - content.append("a=rtpmap:99 H265/90000\r\n");  
545 - if ("TCP-PASSIVE".equals(streamMode)) { // tcp被动模式  
546 - content.append("a=setup:passive\r\n");  
547 - content.append("a=connection:new\r\n");  
548 - } else if ("TCP-ACTIVE".equals(streamMode)) { // tcp主动模式  
549 - content.append("a=setup:active\r\n");  
550 - content.append("a=connection:new\r\n");  
551 - }  
552 - }  
553 - content.append("a=downloadspeed:" + downloadSpeed + "\r\n");  
554 -  
555 - content.append("y=" + ssrcInfo.getSsrc() + "\r\n");//ssrc  
556 - logger.debug("此时请求下载信令的ssrc===>{}",ssrcInfo.getSsrc());  
557 - HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", ssrcInfo.getStream(), true, "rtsp", mediaServerItem.getId());  
558 - // 添加订阅  
559 - CallIdHeader newCallIdHeader = sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()), device.getTransport());  
560 - String callId= newCallIdHeader.getCallId();  
561 - subscribe.addSubscribe(hookSubscribe, (mediaServerItemInUse, hookParam) -> {  
562 - logger.debug("sipc 添加订阅===callId {}",callId);  
563 - hookEvent.response(mediaServerItemInUse, hookParam);  
564 - subscribe.removeSubscribe(hookSubscribe);  
565 - hookSubscribe.getContent().put("regist", false);  
566 - hookSubscribe.getContent().put("schema", "rtsp");  
567 - // 添加流注销的订阅,注销了后向设备发送bye  
568 - subscribe.addSubscribe(hookSubscribe,  
569 - (mediaServerItemForEnd, hookParam1) -> {  
570 - logger.info("[录像]下载结束, 发送BYE");  
571 - try {  
572 - streamByeCmd(device, channelId, ssrcInfo.getStream(), callId);  
573 - } catch (InvalidArgumentException | ParseException | SipException |  
574 - SsrcTransactionNotFoundException e) {  
575 - logger.error("[录像]下载结束, 发送BYE失败 {}", e.getMessage());  
576 - }  
577 - });  
578 - });  
579 -  
580 - Request request = headerProvider.createPlaybackInviteRequest(device, channelId, content.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,newCallIdHeader, ssrcInfo.getSsrc());  
581 -  
582 - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent, event -> {  
583 - ResponseEvent responseEvent = (ResponseEvent) event.event;  
584 - SIPResponse response = (SIPResponse) responseEvent.getResponse();  
585 - String contentString =new String(response.getRawContent());  
586 - String ssrc = SipUtils.getSsrcFromSdp(contentString);  
587 - streamSession.put(device.getDeviceId(), channelId, response.getCallIdHeader().getCallId(), ssrcInfo.getStream(), ssrc, mediaServerItem.getId(), response, InviteSessionType.DOWNLOAD);  
588 - okEvent.response(event);  
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 - if (device == null) {  
606 - logger.warn("[发送BYE] device为null");  
607 - return;  
608 - }  
609 - List<SsrcTransaction> ssrcTransactionList = streamSession.getSsrcTransactionForAll(device.getDeviceId(), channelId, callId, stream);  
610 - if (ssrcTransactionList == null || ssrcTransactionList.isEmpty()) {  
611 - logger.info("[发送BYE] 未找到事务信息,设备: device: {}, channel: {}", device.getDeviceId(), channelId);  
612 - throw new SsrcTransactionNotFoundException(device.getDeviceId(), channelId, callId, stream);  
613 - }  
614 -  
615 - for (SsrcTransaction ssrcTransaction : ssrcTransactionList) {  
616 - logger.info("[发送BYE] 设备: device: {}, channel: {}, callId: {}", device.getDeviceId(), channelId, ssrcTransaction.getCallId());  
617 - mediaServerService.releaseSsrc(ssrcTransaction.getMediaServerId(), ssrcTransaction.getSsrc());  
618 -  
619 - mediaServerService.closeRTPServer(ssrcTransaction.getMediaServerId(), ssrcTransaction.getStream());  
620 - streamSession.removeByCallId(ssrcTransaction.getDeviceId(), ssrcTransaction.getChannelId(), ssrcTransaction.getCallId());  
621 - Request byteRequest = headerProvider.createByteRequest(device, channelId, ssrcTransaction.getSipTransactionInfo());  
622 - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), byteRequest, null, okEvent);  
623 -  
624 - }  
625 - }  
626 -  
627 - /**  
628 - * 语音广播  
629 - *  
630 - * @param device 视频设备  
631 - * @param channelId 预览通道  
632 - */  
633 - @Override  
634 - public void audioBroadcastCmd(Device device, String channelId) {  
635 - }  
636 -  
637 - /**  
638 - * 语音广播  
639 - *  
640 - * @param device 视频设备  
641 - */  
642 - @Override  
643 - public void audioBroadcastCmd(Device device) throws InvalidArgumentException, SipException, ParseException {  
644 -  
645 - StringBuffer broadcastXml = new StringBuffer(200);  
646 - String charset = device.getCharset();  
647 - broadcastXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");  
648 - broadcastXml.append("<Notify>\r\n");  
649 - broadcastXml.append("<CmdType>Broadcast</CmdType>\r\n");  
650 - broadcastXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");  
651 - broadcastXml.append("<SourceID>" + sipConfig.getId() + "</SourceID>\r\n");  
652 - broadcastXml.append("<TargetID>" + device.getDeviceId() + "</TargetID>\r\n");  
653 - broadcastXml.append("</Notify>\r\n");  
654 -  
655 -  
656 -  
657 - Request request = headerProvider.createMessageRequest(device, broadcastXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));  
658 - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request);  
659 -  
660 - }  
661 -  
662 - @Override  
663 - public void audioBroadcastCmd(Device device, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException {  
664 -  
665 - StringBuffer broadcastXml = new StringBuffer(200);  
666 - String charset = device.getCharset();  
667 - broadcastXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");  
668 - broadcastXml.append("<Notify>\r\n");  
669 - broadcastXml.append("<CmdType>Broadcast</CmdType>\r\n");  
670 - broadcastXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");  
671 - broadcastXml.append("<SourceID>" + sipConfig.getId() + "</SourceID>\r\n");  
672 - broadcastXml.append("<TargetID>" + device.getDeviceId() + "</TargetID>\r\n");  
673 - broadcastXml.append("</Notify>\r\n");  
674 -  
675 -  
676 -  
677 - Request request = headerProvider.createMessageRequest(device, broadcastXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));  
678 - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent);  
679 -  
680 - }  
681 -  
682 -  
683 - /**  
684 - * 音视频录像控制  
685 - *  
686 - * @param device 视频设备  
687 - * @param channelId 预览通道  
688 - * @param recordCmdStr 录像命令:Record / StopRecord  
689 - */  
690 - @Override  
691 - public void recordCmd(Device device, String channelId, String recordCmdStr, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException {  
692 - StringBuffer cmdXml = new StringBuffer(200);  
693 - String charset = device.getCharset();  
694 - cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");  
695 - cmdXml.append("<Control>\r\n");  
696 - cmdXml.append("<CmdType>DeviceControl</CmdType>\r\n");  
697 - cmdXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");  
698 - if (ObjectUtils.isEmpty(channelId)) {  
699 - cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");  
700 - } else {  
701 - cmdXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");  
702 - }  
703 - cmdXml.append("<RecordCmd>" + recordCmdStr + "</RecordCmd>\r\n");  
704 - cmdXml.append("</Control>\r\n");  
705 -  
706 -  
707 -  
708 - Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));  
709 - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent,okEvent);  
710 - }  
711 -  
712 - /**  
713 - * 远程启动控制命令  
714 - *  
715 - * @param device 视频设备  
716 - */  
717 - @Override  
718 - public void teleBootCmd(Device device) throws InvalidArgumentException, SipException, ParseException {  
719 -  
720 - StringBuffer cmdXml = new StringBuffer(200);  
721 - String charset = device.getCharset();  
722 - cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");  
723 - cmdXml.append("<Control>\r\n");  
724 - cmdXml.append("<CmdType>DeviceControl</CmdType>\r\n");  
725 - cmdXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");  
726 - cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");  
727 - cmdXml.append("<TeleBoot>Boot</TeleBoot>\r\n");  
728 - cmdXml.append("</Control>\r\n");  
729 -  
730 -  
731 -  
732 - Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));  
733 - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request);  
734 - }  
735 -  
736 - /**  
737 - * 报警布防/撤防命令  
738 - *  
739 - * @param device 视频设备  
740 - * @param guardCmdStr "SetGuard"/"ResetGuard"  
741 - */  
742 - @Override  
743 - public void guardCmd(Device device, String guardCmdStr, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException {  
744 -  
745 - StringBuffer cmdXml = new StringBuffer(200);  
746 - String charset = device.getCharset();  
747 - cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");  
748 - cmdXml.append("<Control>\r\n");  
749 - cmdXml.append("<CmdType>DeviceControl</CmdType>\r\n");  
750 - cmdXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");  
751 - cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");  
752 - cmdXml.append("<GuardCmd>" + guardCmdStr + "</GuardCmd>\r\n");  
753 - cmdXml.append("</Control>\r\n");  
754 -  
755 - Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));  
756 - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent,okEvent);  
757 - }  
758 -  
759 - /**  
760 - * 报警复位命令  
761 - *  
762 - * @param device 视频设备  
763 - */  
764 - @Override  
765 - public void alarmCmd(Device device, String alarmMethod, String alarmType, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException {  
766 -  
767 - StringBuffer cmdXml = new StringBuffer(200);  
768 - String charset = device.getCharset();  
769 - cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");  
770 - cmdXml.append("<Control>\r\n");  
771 - cmdXml.append("<CmdType>DeviceControl</CmdType>\r\n");  
772 - cmdXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");  
773 - cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");  
774 - cmdXml.append("<AlarmCmd>ResetAlarm</AlarmCmd>\r\n");  
775 - if (!ObjectUtils.isEmpty(alarmMethod) || !ObjectUtils.isEmpty(alarmType)) {  
776 - cmdXml.append("<Info>\r\n");  
777 - }  
778 - if (!ObjectUtils.isEmpty(alarmMethod)) {  
779 - cmdXml.append("<AlarmMethod>" + alarmMethod + "</AlarmMethod>\r\n");  
780 - }  
781 - if (!ObjectUtils.isEmpty(alarmType)) {  
782 - cmdXml.append("<AlarmType>" + alarmType + "</AlarmType>\r\n");  
783 - }  
784 - if (!ObjectUtils.isEmpty(alarmMethod) || !ObjectUtils.isEmpty(alarmType)) {  
785 - cmdXml.append("</Info>\r\n");  
786 - }  
787 - cmdXml.append("</Control>\r\n");  
788 -  
789 -  
790 -  
791 - Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));  
792 - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent,okEvent);  
793 - }  
794 -  
795 - /**  
796 - * 强制关键帧命令,设备收到此命令应立刻发送一个IDR帧  
797 - *  
798 - * @param device 视频设备  
799 - * @param channelId 预览通道  
800 - */  
801 - @Override  
802 - public void iFrameCmd(Device device, String channelId) throws InvalidArgumentException, SipException, ParseException {  
803 -  
804 - StringBuffer cmdXml = new StringBuffer(200);  
805 - String charset = device.getCharset();  
806 - cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");  
807 - cmdXml.append("<Control>\r\n");  
808 - cmdXml.append("<CmdType>DeviceControl</CmdType>\r\n");  
809 - cmdXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");  
810 - if (ObjectUtils.isEmpty(channelId)) {  
811 - cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");  
812 - } else {  
813 - cmdXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");  
814 - }  
815 - cmdXml.append("<IFameCmd>Send</IFameCmd>\r\n");  
816 - cmdXml.append("</Control>\r\n");  
817 -  
818 -  
819 -  
820 - Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));  
821 - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request);  
822 - }  
823 -  
824 - /**  
825 - * 看守位控制命令  
826 - *  
827 - * @param device 视频设备  
828 - * @param channelId 通道id,非通道则是设备本身  
829 - * @param enabled 看守位使能:1 = 开启,0 = 关闭  
830 - * @param resetTime 自动归位时间间隔,开启看守位时使用,单位:秒(s)  
831 - * @param presetIndex 调用预置位编号,开启看守位时使用,取值范围0~255  
832 - */  
833 - @Override  
834 - public void homePositionCmd(Device device, String channelId, String enabled, String resetTime, String presetIndex, SipSubscribe.Event errorEvent,SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException {  
835 -  
836 - StringBuffer cmdXml = new StringBuffer(200);  
837 - String charset = device.getCharset();  
838 - cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");  
839 - cmdXml.append("<Control>\r\n");  
840 - cmdXml.append("<CmdType>DeviceControl</CmdType>\r\n");  
841 - cmdXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");  
842 - if (ObjectUtils.isEmpty(channelId)) {  
843 - cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");  
844 - } else {  
845 - cmdXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");  
846 - }  
847 - cmdXml.append("<HomePosition>\r\n");  
848 - if (NumericUtil.isInteger(enabled) && (!enabled.equals("0"))) {  
849 - cmdXml.append("<Enabled>1</Enabled>\r\n");  
850 - if (NumericUtil.isInteger(resetTime)) {  
851 - cmdXml.append("<ResetTime>" + resetTime + "</ResetTime>\r\n");  
852 - } else {  
853 - cmdXml.append("<ResetTime>0</ResetTime>\r\n");  
854 - }  
855 - if (NumericUtil.isInteger(presetIndex)) {  
856 - cmdXml.append("<PresetIndex>" + presetIndex + "</PresetIndex>\r\n");  
857 - } else {  
858 - cmdXml.append("<PresetIndex>0</PresetIndex>\r\n");  
859 - }  
860 - } else {  
861 - cmdXml.append("<Enabled>0</Enabled>\r\n");  
862 - }  
863 - cmdXml.append("</HomePosition>\r\n");  
864 - cmdXml.append("</Control>\r\n");  
865 -  
866 -  
867 -  
868 - Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));  
869 - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent,okEvent);  
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 -  
930 -  
931 - Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));  
932 - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent);  
933 - }  
934 -  
935 - /**  
936 - * 查询设备状态  
937 - *  
938 - * @param device 视频设备  
939 - */  
940 - @Override  
941 - public void deviceStatusQuery(Device device, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException {  
942 -  
943 - String charset = device.getCharset();  
944 - StringBuffer catalogXml = new StringBuffer(200);  
945 - catalogXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");  
946 - catalogXml.append("<Query>\r\n");  
947 - catalogXml.append("<CmdType>DeviceStatus</CmdType>\r\n");  
948 - catalogXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");  
949 - catalogXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");  
950 - catalogXml.append("</Query>\r\n");  
951 -  
952 - Request request = headerProvider.createMessageRequest(device, catalogXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));  
953 -  
954 - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent);  
955 - }  
956 -  
957 - /**  
958 - * 查询设备信息  
959 - *  
960 - * @param device 视频设备  
961 - */  
962 - @Override  
963 - public void deviceInfoQuery(Device device) throws InvalidArgumentException, SipException, ParseException {  
964 -  
965 - StringBuffer catalogXml = new StringBuffer(200);  
966 - String charset = device.getCharset();  
967 - catalogXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");  
968 - catalogXml.append("<Query>\r\n");  
969 - catalogXml.append("<CmdType>DeviceInfo</CmdType>\r\n");  
970 - catalogXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");  
971 - catalogXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");  
972 - catalogXml.append("</Query>\r\n");  
973 -  
974 -  
975 -  
976 - Request request = headerProvider.createMessageRequest(device, catalogXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));  
977 -  
978 - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request);  
979 -  
980 - }  
981 -  
982 - /**  
983 - * 查询目录列表  
984 - *  
985 - * @param device 视频设备  
986 - */  
987 - @Override  
988 - public void catalogQuery(Device device, int sn, SipSubscribe.Event errorEvent) throws SipException, InvalidArgumentException, ParseException {  
989 -  
990 - StringBuffer catalogXml = new StringBuffer(200);  
991 - String charset = device.getCharset();  
992 - catalogXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");  
993 - catalogXml.append("<Query>\r\n");  
994 - catalogXml.append(" <CmdType>Catalog</CmdType>\r\n");  
995 - catalogXml.append(" <SN>" + sn + "</SN>\r\n");  
996 - catalogXml.append(" <DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");  
997 - catalogXml.append("</Query>\r\n");  
998 -  
999 -  
1000 -  
1001 - Request request = headerProvider.createMessageRequest(device, catalogXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));  
1002 -  
1003 - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent);  
1004 - }  
1005 -  
1006 - /**  
1007 - * 查询录像信息  
1008 - *  
1009 - * @param device 视频设备  
1010 - * @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss  
1011 - * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss  
1012 - */  
1013 - @Override  
1014 - 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 {  
1015 - if (secrecy == null) {  
1016 - secrecy = 0;  
1017 - }  
1018 - if (type == null) {  
1019 - type = "all";  
1020 - }  
1021 -  
1022 - StringBuffer recordInfoXml = new StringBuffer(200);  
1023 - String charset = device.getCharset();  
1024 - recordInfoXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");  
1025 - recordInfoXml.append("<Query>\r\n");  
1026 - recordInfoXml.append("<CmdType>RecordInfo</CmdType>\r\n");  
1027 - recordInfoXml.append("<SN>" + sn + "</SN>\r\n");  
1028 - recordInfoXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");  
1029 - if (startTime != null) {  
1030 - recordInfoXml.append("<StartTime>" + DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(startTime) + "</StartTime>\r\n");  
1031 - }  
1032 - if (endTime != null) {  
1033 - recordInfoXml.append("<EndTime>" + DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(endTime) + "</EndTime>\r\n");  
1034 - }  
1035 - if (secrecy != null) {  
1036 - recordInfoXml.append("<Secrecy> " + secrecy + " </Secrecy>\r\n");  
1037 - }  
1038 - if (type != null) {  
1039 - // 大华NVR要求必须增加一个值为all的文本元素节点Type  
1040 - recordInfoXml.append("<Type>" + type + "</Type>\r\n");  
1041 - }  
1042 - recordInfoXml.append("</Query>\r\n");  
1043 -  
1044 -  
1045 -  
1046 - Request request = headerProvider.createMessageRequest(device, recordInfoXml.toString(),  
1047 - SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));  
1048 -  
1049 - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent, okEvent);  
1050 - }  
1051 -  
1052 - /**  
1053 - * 查询报警信息  
1054 - *  
1055 - * @param device 视频设备  
1056 - * @param startPriority 报警起始级别(可选)  
1057 - * @param endPriority 报警终止级别(可选)  
1058 - * @param alarmMethod 报警方式条件(可选)  
1059 - * @param alarmType 报警类型  
1060 - * @param startTime 报警发生起始时间(可选)  
1061 - * @param endTime 报警发生终止时间(可选)  
1062 - * @return true = 命令发送成功  
1063 - */  
1064 - @Override  
1065 - public void alarmInfoQuery(Device device, String startPriority, String endPriority, String alarmMethod, String alarmType,  
1066 - String startTime, String endTime, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException {  
1067 -  
1068 - StringBuffer cmdXml = new StringBuffer(200);  
1069 - String charset = device.getCharset();  
1070 - cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");  
1071 - cmdXml.append("<Query>\r\n");  
1072 - cmdXml.append("<CmdType>Alarm</CmdType>\r\n");  
1073 - cmdXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");  
1074 - cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");  
1075 - if (!ObjectUtils.isEmpty(startPriority)) {  
1076 - cmdXml.append("<StartAlarmPriority>" + startPriority + "</StartAlarmPriority>\r\n");  
1077 - }  
1078 - if (!ObjectUtils.isEmpty(endPriority)) {  
1079 - cmdXml.append("<EndAlarmPriority>" + endPriority + "</EndAlarmPriority>\r\n");  
1080 - }  
1081 - if (!ObjectUtils.isEmpty(alarmMethod)) {  
1082 - cmdXml.append("<AlarmMethod>" + alarmMethod + "</AlarmMethod>\r\n");  
1083 - }  
1084 - if (!ObjectUtils.isEmpty(alarmType)) {  
1085 - cmdXml.append("<AlarmType>" + alarmType + "</AlarmType>\r\n");  
1086 - }  
1087 - if (!ObjectUtils.isEmpty(startTime)) {  
1088 - cmdXml.append("<StartAlarmTime>" + startTime + "</StartAlarmTime>\r\n");  
1089 - }  
1090 - if (!ObjectUtils.isEmpty(endTime)) {  
1091 - cmdXml.append("<EndAlarmTime>" + endTime + "</EndAlarmTime>\r\n");  
1092 - }  
1093 - cmdXml.append("</Query>\r\n");  
1094 -  
1095 -  
1096 -  
1097 - Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));  
1098 - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent);  
1099 - }  
1100 -  
1101 - /**  
1102 - * 查询设备配置  
1103 - *  
1104 - * @param device 视频设备  
1105 - * @param channelId 通道编码(可选)  
1106 - * @param configType 配置类型:  
1107 - */  
1108 - @Override  
1109 - public void deviceConfigQuery(Device device, String channelId, String configType, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException {  
1110 -  
1111 - StringBuffer cmdXml = new StringBuffer(200);  
1112 - String charset = device.getCharset();  
1113 - cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");  
1114 - cmdXml.append("<Query>\r\n");  
1115 - cmdXml.append("<CmdType>ConfigDownload</CmdType>\r\n");  
1116 - cmdXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");  
1117 - if (ObjectUtils.isEmpty(channelId)) {  
1118 - cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");  
1119 - } else {  
1120 - cmdXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");  
1121 - }  
1122 - cmdXml.append("<ConfigType>" + configType + "</ConfigType>\r\n");  
1123 - cmdXml.append("</Query>\r\n");  
1124 -  
1125 -  
1126 -  
1127 - Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));  
1128 - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent);  
1129 - }  
1130 -  
1131 - /**  
1132 - * 查询设备预置位置  
1133 - *  
1134 - * @param device 视频设备  
1135 - */  
1136 - @Override  
1137 - public void presetQuery(Device device, String channelId, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException {  
1138 -  
1139 - StringBuffer cmdXml = new StringBuffer(200);  
1140 - String charset = device.getCharset();  
1141 - cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");  
1142 - cmdXml.append("<Query>\r\n");  
1143 - cmdXml.append("<CmdType>PresetQuery</CmdType>\r\n");  
1144 - cmdXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");  
1145 - if (ObjectUtils.isEmpty(channelId)) {  
1146 - cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");  
1147 - } else {  
1148 - cmdXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");  
1149 - }  
1150 - cmdXml.append("</Query>\r\n");  
1151 -  
1152 -  
1153 - Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));  
1154 - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent);  
1155 - }  
1156 -  
1157 - /**  
1158 - * 查询移动设备位置数据  
1159 - *  
1160 - * @param device 视频设备  
1161 - */  
1162 - @Override  
1163 - public void mobilePostitionQuery(Device device, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException {  
1164 -  
1165 - StringBuffer mobilePostitionXml = new StringBuffer(200);  
1166 - String charset = device.getCharset();  
1167 - mobilePostitionXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");  
1168 - mobilePostitionXml.append("<Query>\r\n");  
1169 - mobilePostitionXml.append("<CmdType>MobilePosition</CmdType>\r\n");  
1170 - mobilePostitionXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");  
1171 - mobilePostitionXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");  
1172 - mobilePostitionXml.append("<Interval>60</Interval>\r\n");  
1173 - mobilePostitionXml.append("</Query>\r\n");  
1174 -  
1175 -  
1176 -  
1177 - Request request = headerProvider.createMessageRequest(device, mobilePostitionXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));  
1178 -  
1179 - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent);  
1180 -  
1181 - }  
1182 -  
1183 - /**  
1184 - * 订阅、取消订阅移动位置  
1185 - *  
1186 - * @param device 视频设备  
1187 - * @return true = 命令发送成功  
1188 - */  
1189 - @Override  
1190 - public SIPRequest mobilePositionSubscribe(Device device, SIPRequest requestOld, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException {  
1191 -  
1192 - StringBuffer subscribePostitionXml = new StringBuffer(200);  
1193 - String charset = device.getCharset();  
1194 - subscribePostitionXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");  
1195 - subscribePostitionXml.append("<Query>\r\n");  
1196 - subscribePostitionXml.append("<CmdType>MobilePosition</CmdType>\r\n");  
1197 - subscribePostitionXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");  
1198 - subscribePostitionXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");  
1199 - if (device.getSubscribeCycleForMobilePosition() > 0) {  
1200 - subscribePostitionXml.append("<Interval>" + device.getMobilePositionSubmissionInterval() + "</Interval>\r\n");  
1201 - }  
1202 - subscribePostitionXml.append("</Query>\r\n");  
1203 -  
1204 - CallIdHeader callIdHeader;  
1205 -  
1206 - if (requestOld != null) {  
1207 - callIdHeader = SipFactory.getInstance().createHeaderFactory().createCallIdHeader(requestOld.getCallIdHeader().getCallId());  
1208 - } else {  
1209 - callIdHeader = sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport());  
1210 - }  
1211 - SIPRequest request = (SIPRequest) headerProvider.createSubscribeRequest(device, subscribePostitionXml.toString(), requestOld, device.getSubscribeCycleForMobilePosition(), "presence",callIdHeader); //Position;id=" + tm.substring(tm.length() - 4));  
1212 -  
1213 - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent, okEvent);  
1214 - return request;  
1215 - }  
1216 -  
1217 - /**  
1218 - * 订阅、取消订阅报警信息  
1219 - *  
1220 - * @param device 视频设备  
1221 - * @param expires 订阅过期时间(0 = 取消订阅)  
1222 - * @param startPriority 报警起始级别(可选)  
1223 - * @param endPriority 报警终止级别(可选)  
1224 - * @param alarmMethod 报警方式条件(可选)  
1225 - * @param alarmType 报警类型  
1226 - * @param startTime 报警发生起始时间(可选)  
1227 - * @param endTime 报警发生终止时间(可选)  
1228 - * @return true = 命令发送成功  
1229 - */  
1230 - @Override  
1231 - public void alarmSubscribe(Device device, int expires, String startPriority, String endPriority, String alarmMethod, String startTime, String endTime) throws InvalidArgumentException, SipException, ParseException {  
1232 -  
1233 - StringBuffer cmdXml = new StringBuffer(200);  
1234 - String charset = device.getCharset();  
1235 - cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");  
1236 - cmdXml.append("<Query>\r\n");  
1237 - cmdXml.append("<CmdType>Alarm</CmdType>\r\n");  
1238 - cmdXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");  
1239 - cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");  
1240 - if (!ObjectUtils.isEmpty(startPriority)) {  
1241 - cmdXml.append("<StartAlarmPriority>" + startPriority + "</StartAlarmPriority>\r\n");  
1242 - }  
1243 - if (!ObjectUtils.isEmpty(endPriority)) {  
1244 - cmdXml.append("<EndAlarmPriority>" + endPriority + "</EndAlarmPriority>\r\n");  
1245 - }  
1246 - if (!ObjectUtils.isEmpty(alarmMethod)) {  
1247 - cmdXml.append("<AlarmMethod>" + alarmMethod + "</AlarmMethod>\r\n");  
1248 - }  
1249 - if (!ObjectUtils.isEmpty(startTime)) {  
1250 - cmdXml.append("<StartAlarmTime>" + startTime + "</StartAlarmTime>\r\n");  
1251 - }  
1252 - if (!ObjectUtils.isEmpty(endTime)) {  
1253 - cmdXml.append("<EndAlarmTime>" + endTime + "</EndAlarmTime>\r\n");  
1254 - }  
1255 - cmdXml.append("</Query>\r\n");  
1256 -  
1257 -  
1258 -  
1259 - Request request = headerProvider.createSubscribeRequest(device, cmdXml.toString(), null, expires, "presence",sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));  
1260 - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request);  
1261 -  
1262 - }  
1263 -  
1264 - @Override  
1265 - public SIPRequest catalogSubscribe(Device device, SIPRequest requestOld, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException {  
1266 -  
1267 - StringBuffer cmdXml = new StringBuffer(200);  
1268 - String charset = device.getCharset();  
1269 - cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");  
1270 - cmdXml.append("<Query>\r\n");  
1271 - cmdXml.append("<CmdType>Catalog</CmdType>\r\n");  
1272 - cmdXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");  
1273 - cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");  
1274 - cmdXml.append("</Query>\r\n");  
1275 -  
1276 - CallIdHeader callIdHeader;  
1277 -  
1278 - if (requestOld != null) {  
1279 - callIdHeader = SipFactory.getInstance().createHeaderFactory().createCallIdHeader(requestOld.getCallIdHeader().getCallId());  
1280 - } else {  
1281 - callIdHeader = sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport());  
1282 - }  
1283 -  
1284 - // 有效时间默认为60秒以上  
1285 - SIPRequest request = (SIPRequest) headerProvider.createSubscribeRequest(device, cmdXml.toString(), requestOld, device.getSubscribeCycleForCatalog(), "Catalog",  
1286 - callIdHeader);  
1287 - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent, okEvent);  
1288 - return request;  
1289 - }  
1290 -  
1291 - @Override  
1292 - public void dragZoomCmd(Device device, String channelId, String cmdString) throws InvalidArgumentException, SipException, ParseException {  
1293 -  
1294 - StringBuffer dragXml = new StringBuffer(200);  
1295 - String charset = device.getCharset();  
1296 - dragXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");  
1297 - dragXml.append("<Control>\r\n");  
1298 - dragXml.append("<CmdType>DeviceControl</CmdType>\r\n");  
1299 - dragXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");  
1300 - if (ObjectUtils.isEmpty(channelId)) {  
1301 - dragXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");  
1302 - } else {  
1303 - dragXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");  
1304 - }  
1305 - dragXml.append(cmdString);  
1306 - dragXml.append("</Control>\r\n");  
1307 -  
1308 - Request request = headerProvider.createMessageRequest(device, dragXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));  
1309 - logger.debug("拉框信令: " + request.toString());  
1310 - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()),request);  
1311 - }  
1312 -  
1313 -  
1314 -  
1315 -  
1316 -  
1317 - /**  
1318 - * 回放暂停  
1319 - */  
1320 - @Override  
1321 - public void playPauseCmd(Device device, StreamInfo streamInfo) throws InvalidArgumentException, ParseException, SipException {  
1322 - StringBuffer content = new StringBuffer(200);  
1323 - content.append("PAUSE RTSP/1.0\r\n");  
1324 - content.append("CSeq: " + getInfoCseq() + "\r\n");  
1325 - content.append("PauseTime: now\r\n");  
1326 -  
1327 - playbackControlCmd(device, streamInfo, content.toString(), null, null);  
1328 - }  
1329 -  
1330 -  
1331 - /**  
1332 - * 回放恢复  
1333 - */  
1334 - @Override  
1335 - public void playResumeCmd(Device device, StreamInfo streamInfo) throws InvalidArgumentException, ParseException, SipException {  
1336 - StringBuffer content = new StringBuffer(200);  
1337 - content.append("PLAY RTSP/1.0\r\n");  
1338 - content.append("CSeq: " + getInfoCseq() + "\r\n");  
1339 - content.append("Range: npt=now-\r\n");  
1340 -  
1341 - playbackControlCmd(device, streamInfo, content.toString(), null, null);  
1342 - }  
1343 -  
1344 - /**  
1345 - * 回放拖动播放  
1346 - */  
1347 - @Override  
1348 - public void playSeekCmd(Device device, StreamInfo streamInfo, long seekTime) throws InvalidArgumentException, ParseException, SipException {  
1349 - StringBuffer content = new StringBuffer(200);  
1350 - content.append("PLAY RTSP/1.0\r\n");  
1351 - content.append("CSeq: " + getInfoCseq() + "\r\n");  
1352 - content.append("Range: npt=" + Math.abs(seekTime) + "-\r\n");  
1353 -  
1354 - playbackControlCmd(device, streamInfo, content.toString(), null, null);  
1355 - }  
1356 -  
1357 - /**  
1358 - * 回放倍速播放  
1359 - */  
1360 - @Override  
1361 - public void playSpeedCmd(Device device, StreamInfo streamInfo, Double speed) throws InvalidArgumentException, ParseException, SipException {  
1362 - StringBuffer content = new StringBuffer(200);  
1363 - content.append("PLAY RTSP/1.0\r\n");  
1364 - content.append("CSeq: " + getInfoCseq() + "\r\n");  
1365 - content.append("Scale: " + String.format("%.6f", speed) + "\r\n");  
1366 -  
1367 - playbackControlCmd(device, streamInfo, content.toString(), null, null);  
1368 - }  
1369 -  
1370 - private int getInfoCseq() {  
1371 - return (int) ((Math.random() * 9 + 1) * Math.pow(10, 8));  
1372 - }  
1373 -  
1374 - @Override  
1375 - public void playbackControlCmd(Device device, StreamInfo streamInfo, String content, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws SipException, InvalidArgumentException, ParseException {  
1376 -  
1377 - SsrcTransaction ssrcTransaction = streamSession.getSsrcTransaction(device.getDeviceId(), streamInfo.getChannelId(), null, streamInfo.getStream());  
1378 - if (ssrcTransaction == null) {  
1379 - logger.info("[回放控制]未找到视频流信息,设备:{}, 流ID: {}", device.getDeviceId(), streamInfo.getStream());  
1380 - return;  
1381 - }  
1382 -  
1383 - SIPRequest request = headerProvider.createInfoRequest(device, streamInfo.getChannelId(), content.toString(), ssrcTransaction.getSipTransactionInfo());  
1384 - if (request == null) {  
1385 - logger.info("[回放控制]构建Request信息失败,设备:{}, 流ID: {}", device.getDeviceId(), streamInfo.getStream());  
1386 - return;  
1387 - }  
1388 -  
1389 - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent, okEvent);  
1390 - }  
1391 -  
1392 - @Override  
1393 - public void sendAlarmMessage(Device device, DeviceAlarm deviceAlarm) throws InvalidArgumentException, SipException, ParseException {  
1394 - if (device == null) {  
1395 - return;  
1396 - }  
1397 - logger.info("[发送报警通知]设备: {}/{}->{},{}", device.getDeviceId(), deviceAlarm.getChannelId(),  
1398 - deviceAlarm.getLongitude(), deviceAlarm.getLatitude());  
1399 -  
1400 - String characterSet = device.getCharset();  
1401 - StringBuffer deviceStatusXml = new StringBuffer(600);  
1402 - deviceStatusXml.append("<?xml version=\"1.0\" encoding=\"" + characterSet + "\"?>\r\n");  
1403 - deviceStatusXml.append("<Notify>\r\n");  
1404 - deviceStatusXml.append("<CmdType>Alarm</CmdType>\r\n");  
1405 - deviceStatusXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");  
1406 - deviceStatusXml.append("<DeviceID>" + deviceAlarm.getChannelId() + "</DeviceID>\r\n");  
1407 - deviceStatusXml.append("<AlarmPriority>" + deviceAlarm.getAlarmPriority() + "</AlarmPriority>\r\n");  
1408 - deviceStatusXml.append("<AlarmMethod>" + deviceAlarm.getAlarmMethod() + "</AlarmMethod>\r\n");  
1409 - deviceStatusXml.append("<AlarmTime>" + DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(deviceAlarm.getAlarmTime()) + "</AlarmTime>\r\n");  
1410 - deviceStatusXml.append("<AlarmDescription>" + deviceAlarm.getAlarmDescription() + "</AlarmDescription>\r\n");  
1411 - deviceStatusXml.append("<Longitude>" + deviceAlarm.getLongitude() + "</Longitude>\r\n");  
1412 - deviceStatusXml.append("<Latitude>" + deviceAlarm.getLatitude() + "</Latitude>\r\n");  
1413 - deviceStatusXml.append("<info>\r\n");  
1414 - deviceStatusXml.append("<AlarmType>" + deviceAlarm.getAlarmType() + "</AlarmType>\r\n");  
1415 - deviceStatusXml.append("</info>\r\n");  
1416 - deviceStatusXml.append("</Notify>\r\n");  
1417 -  
1418 -  
1419 - Request request = headerProvider.createMessageRequest(device, deviceStatusXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));  
1420 - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()),request);  
1421 -  
1422 -  
1423 - }  
1424 -} 1 +package com.genersoft.iot.vmp.gb28181.transmit.cmd.impl;
  2 +
  3 +import com.genersoft.iot.vmp.common.InviteSessionType;
  4 +import com.genersoft.iot.vmp.common.StreamInfo;
  5 +import com.genersoft.iot.vmp.conf.SipConfig;
  6 +import com.genersoft.iot.vmp.conf.UserSetting;
  7 +import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException;
  8 +import com.genersoft.iot.vmp.gb28181.SipLayer;
  9 +import com.genersoft.iot.vmp.gb28181.bean.*;
  10 +import com.genersoft.iot.vmp.gb28181.bean.Device;
  11 +import com.genersoft.iot.vmp.gb28181.bean.DeviceAlarm;
  12 +import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
  13 +import com.genersoft.iot.vmp.gb28181.bean.SsrcTransaction;
  14 +import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
  15 +import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
  16 +import com.genersoft.iot.vmp.gb28181.transmit.SIPSender;
  17 +import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander;
  18 +import com.genersoft.iot.vmp.gb28181.transmit.cmd.SIPRequestHeaderProvider;
  19 +import com.genersoft.iot.vmp.gb28181.utils.NumericUtil;
  20 +import com.genersoft.iot.vmp.gb28181.utils.SipUtils;
  21 +import com.genersoft.iot.vmp.media.zlm.ZLMServerFactory;
  22 +import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe;
  23 +import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeFactory;
  24 +import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForStreamChange;
  25 +import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForStreamPush;
  26 +import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
  27 +import com.genersoft.iot.vmp.media.zlm.dto.hook.HookParam;
  28 +import com.genersoft.iot.vmp.service.IMediaServerService;
  29 +import com.genersoft.iot.vmp.service.bean.SSRCInfo;
  30 +import com.genersoft.iot.vmp.utils.DateUtil;
  31 +import gov.nist.javax.sip.message.SIPRequest;
  32 +import gov.nist.javax.sip.message.SIPResponse;
  33 +import org.slf4j.Logger;
  34 +import org.slf4j.LoggerFactory;
  35 +import org.springframework.beans.factory.annotation.Autowired;
  36 +import org.springframework.context.annotation.DependsOn;
  37 +import org.springframework.stereotype.Component;
  38 +import org.springframework.util.ObjectUtils;
  39 +
  40 +import javax.sip.InvalidArgumentException;
  41 +import javax.sip.ResponseEvent;
  42 +import javax.sip.SipException;
  43 +import javax.sip.SipFactory;
  44 +import javax.sip.header.CallIdHeader;
  45 +import javax.sip.message.Request;
  46 +import java.text.ParseException;
  47 +import java.util.ArrayList;
  48 +import java.util.List;
  49 +
  50 +/**
  51 + * @description:设备能力接口,用于定义设备的控制、查询能力
  52 + * @author: swwheihei
  53 + * @date: 2020年5月3日 下午9:22:48
  54 + */
  55 +@Component
  56 +@DependsOn("sipLayer")
  57 +public class SIPCommander implements ISIPCommander {
  58 +
  59 + private final Logger logger = LoggerFactory.getLogger(SIPCommander.class);
  60 +
  61 + @Autowired
  62 + private SipConfig sipConfig;
  63 +
  64 + @Autowired
  65 + private SipLayer sipLayer;
  66 +
  67 + @Autowired
  68 + private SIPSender sipSender;
  69 +
  70 + @Autowired
  71 + private SIPRequestHeaderProvider headerProvider;
  72 +
  73 + @Autowired
  74 + private VideoStreamSessionManager streamSession;
  75 +
  76 + @Autowired
  77 + private UserSetting userSetting;
  78 +
  79 + @Autowired
  80 + private ZlmHttpHookSubscribe subscribe;
  81 +
  82 + @Autowired
  83 + private IMediaServerService mediaServerService;
  84 +
  85 + @Autowired
  86 + private ZLMServerFactory zlmServerFactory;
  87 +
  88 +
  89 + /**
  90 + * 云台方向放控制,使用配置文件中的默认镜头移动速度
  91 + *
  92 + * @param device 控制设备
  93 + * @param channelId 预览通道
  94 + * @param leftRight 镜头左移右移 0:停止 1:左移 2:右移
  95 + * @param upDown 镜头上移下移 0:停止 1:上移 2:下移
  96 + */
  97 + @Override
  98 + public void ptzdirectCmd(Device device, String channelId, int leftRight, int upDown) throws InvalidArgumentException, ParseException, SipException {
  99 + ptzCmd(device, channelId, leftRight, upDown, 0, sipConfig.getPtzSpeed(), 0);
  100 + }
  101 +
  102 + /**
  103 + * 云台方向放控制
  104 + *
  105 + * @param device 控制设备
  106 + * @param channelId 预览通道
  107 + * @param leftRight 镜头左移右移 0:停止 1:左移 2:右移
  108 + * @param upDown 镜头上移下移 0:停止 1:上移 2:下移
  109 + * @param moveSpeed 镜头移动速度
  110 + */
  111 + @Override
  112 + public void ptzdirectCmd(Device device, String channelId, int leftRight, int upDown, int moveSpeed) throws InvalidArgumentException, ParseException, SipException {
  113 + ptzCmd(device, channelId, leftRight, upDown, 0, moveSpeed, 0);
  114 + }
  115 +
  116 + /**
  117 + * 云台缩放控制,使用配置文件中的默认镜头缩放速度
  118 + *
  119 + * @param device 控制设备
  120 + * @param channelId 预览通道
  121 + * @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大
  122 + */
  123 + @Override
  124 + public void ptzZoomCmd(Device device, String channelId, int inOut) throws InvalidArgumentException, ParseException, SipException {
  125 + ptzCmd(device, channelId, 0, 0, inOut, 0, sipConfig.getPtzSpeed());
  126 + }
  127 +
  128 + /**
  129 + * 云台缩放控制
  130 + *
  131 + * @param device 控制设备
  132 + * @param channelId 预览通道
  133 + * @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大
  134 + * @param zoomSpeed 镜头缩放速度
  135 + */
  136 + @Override
  137 + public void ptzZoomCmd(Device device, String channelId, int inOut, int zoomSpeed) throws InvalidArgumentException, ParseException, SipException {
  138 + ptzCmd(device, channelId, 0, 0, inOut, 0, zoomSpeed);
  139 + }
  140 +
  141 + /**
  142 + * 云台指令码计算
  143 + *
  144 + * @param cmdCode 指令码
  145 + * @param parameter1 数据1
  146 + * @param parameter2 数据2
  147 + * @param combineCode2 组合码2
  148 + */
  149 + public static String frontEndCmdString(int cmdCode, int parameter1, int parameter2, int combineCode2) {
  150 + StringBuilder builder = new StringBuilder("A50F01");
  151 + String strTmp;
  152 + strTmp = String.format("%02X", cmdCode);
  153 + builder.append(strTmp, 0, 2);
  154 + strTmp = String.format("%02X", parameter1);
  155 + builder.append(strTmp, 0, 2);
  156 + strTmp = String.format("%02X", parameter2);
  157 + builder.append(strTmp, 0, 2);
  158 + //优化zoom变倍速率
  159 + if ((combineCode2 > 0) && (combineCode2 <16))
  160 + {
  161 + combineCode2 = 16;
  162 + }
  163 + strTmp = String.format("%X", combineCode2);
  164 + builder.append(strTmp, 0, 1).append("0");
  165 + //计算校验码
  166 + int checkCode = (0XA5 + 0X0F + 0X01 + cmdCode + parameter1 + parameter2 + (combineCode2 & 0XF0)) % 0X100;
  167 + strTmp = String.format("%02X", checkCode);
  168 + builder.append(strTmp, 0, 2);
  169 + return builder.toString();
  170 + }
  171 +
  172 + /**
  173 + * 云台控制,支持方向与缩放控制
  174 + *
  175 + * @param device 控制设备
  176 + * @param channelId 预览通道
  177 + * @param leftRight 镜头左移右移 0:停止 1:左移 2:右移
  178 + * @param upDown 镜头上移下移 0:停止 1:上移 2:下移
  179 + * @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大
  180 + * @param moveSpeed 镜头移动速度
  181 + * @param zoomSpeed 镜头缩放速度
  182 + */
  183 + @Override
  184 + public void ptzCmd(Device device, String channelId, int leftRight, int upDown, int inOut, int moveSpeed,
  185 + int zoomSpeed) throws InvalidArgumentException, SipException, ParseException {
  186 + String cmdStr = SipUtils.cmdString(leftRight, upDown, inOut, moveSpeed, zoomSpeed);
  187 + StringBuilder ptzXml = new StringBuilder(200);
  188 + String charset = device.getCharset();
  189 + ptzXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
  190 + ptzXml.append("<Control>\r\n");
  191 + ptzXml.append("<CmdType>DeviceControl</CmdType>\r\n");
  192 + ptzXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");
  193 + ptzXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
  194 + ptzXml.append("<PTZCmd>" + cmdStr + "</PTZCmd>\r\n");
  195 + ptzXml.append("<Info>\r\n");
  196 + ptzXml.append("<ControlPriority>5</ControlPriority>\r\n");
  197 + ptzXml.append("</Info>\r\n");
  198 + ptzXml.append("</Control>\r\n");
  199 +
  200 + Request request = headerProvider.createMessageRequest(device, ptzXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null, sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));
  201 +
  202 + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()),request);
  203 + }
  204 +
  205 + /**
  206 + * 前端控制,包括PTZ指令、FI指令、预置位指令、巡航指令、扫描指令和辅助开关指令
  207 + *
  208 + * @param device 控制设备
  209 + * @param channelId 预览通道
  210 + * @param cmdCode 指令码
  211 + * @param parameter1 数据1
  212 + * @param parameter2 数据2
  213 + * @param combineCode2 组合码2
  214 + */
  215 + @Override
  216 + public void frontEndCmd(Device device, String channelId, int cmdCode, int parameter1, int parameter2, int combineCode2) throws SipException, InvalidArgumentException, ParseException {
  217 +
  218 + String cmdStr = frontEndCmdString(cmdCode, parameter1, parameter2, combineCode2);
  219 + StringBuffer ptzXml = new StringBuffer(200);
  220 + String charset = device.getCharset();
  221 + ptzXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
  222 + ptzXml.append("<Control>\r\n");
  223 + ptzXml.append("<CmdType>DeviceControl</CmdType>\r\n");
  224 + ptzXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");
  225 + ptzXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
  226 + ptzXml.append("<PTZCmd>" + cmdStr + "</PTZCmd>\r\n");
  227 + ptzXml.append("<Info>\r\n");
  228 + ptzXml.append("<ControlPriority>5</ControlPriority>\r\n");
  229 + ptzXml.append("</Info>\r\n");
  230 + ptzXml.append("</Control>\r\n");
  231 +
  232 +
  233 +
  234 +
  235 + SIPRequest request = (SIPRequest) headerProvider.createMessageRequest(device, ptzXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));
  236 + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()),request);
  237 +
  238 + }
  239 +
  240 + /**
  241 + * 前端控制指令(用于转发上级指令)
  242 + *
  243 + * @param device 控制设备
  244 + * @param channelId 预览通道
  245 + * @param cmdString 前端控制指令串
  246 + */
  247 + @Override
  248 + public void fronEndCmd(Device device, String channelId, String cmdString, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException {
  249 +
  250 + StringBuffer ptzXml = new StringBuffer(200);
  251 + String charset = device.getCharset();
  252 + ptzXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
  253 + ptzXml.append("<Control>\r\n");
  254 + ptzXml.append("<CmdType>DeviceControl</CmdType>\r\n");
  255 + ptzXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");
  256 + ptzXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
  257 + ptzXml.append("<PTZCmd>" + cmdString + "</PTZCmd>\r\n");
  258 + ptzXml.append("<Info>\r\n");
  259 + ptzXml.append("<ControlPriority>5</ControlPriority>\r\n");
  260 + ptzXml.append("</Info>\r\n");
  261 + ptzXml.append("</Control>\r\n");
  262 +
  263 +
  264 + Request request = headerProvider.createMessageRequest(device, ptzXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));
  265 + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()),request, errorEvent, okEvent);
  266 +
  267 + }
  268 +
  269 + /**
  270 + * 请求预览视频流
  271 + *
  272 + * @param device 视频设备
  273 + * @param channel 预览通道
  274 + * @param event hook订阅
  275 + * @param errorEvent sip错误订阅
  276 + */
  277 + @Override
  278 + public void playStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, DeviceChannel channel,
  279 + ZlmHttpHookSubscribe.Event event, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException {
  280 + String stream = ssrcInfo.getStream();
  281 +
  282 + if (device == null) {
  283 + return;
  284 + }
  285 +
  286 + logger.info("{} 分配的ZLM为: {} [{}:{}]", stream, mediaServerItem.getId(), mediaServerItem.getSdpIp(), ssrcInfo.getPort());
  287 + HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", stream, true, "rtsp", mediaServerItem.getId());
  288 + subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, HookParam hookParam) -> {
  289 + if (event != null) {
  290 + event.response(mediaServerItemInUse, hookParam);
  291 + subscribe.removeSubscribe(hookSubscribe);
  292 + }
  293 + });
  294 + String sdpIp;
  295 + if (!ObjectUtils.isEmpty(device.getSdpIp())) {
  296 + sdpIp = device.getSdpIp();
  297 + }else {
  298 + sdpIp = mediaServerItem.getSdpIp();
  299 + }
  300 + StringBuffer content = new StringBuffer(200);
  301 + content.append("v=0\r\n");
  302 + content.append("o=" + channel.getChannelId() + " 0 0 IN IP4 " + sdpIp + "\r\n");
  303 + content.append("s=Play\r\n");
  304 + content.append("c=IN IP4 " + sdpIp + "\r\n");
  305 + content.append("t=0 0\r\n");
  306 +
  307 + if (userSetting.isSeniorSdp()) {
  308 + if ("TCP-PASSIVE".equalsIgnoreCase(device.getStreamMode())) {
  309 + content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 126 125 99 34 98 97\r\n");
  310 + } else if ("TCP-ACTIVE".equalsIgnoreCase(device.getStreamMode())) {
  311 + content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 126 125 99 34 98 97\r\n");
  312 + } else if ("UDP".equalsIgnoreCase(device.getStreamMode())) {
  313 + content.append("m=video " + ssrcInfo.getPort() + " RTP/AVP 96 126 125 99 34 98 97\r\n");
  314 + }
  315 + content.append("a=recvonly\r\n");
  316 + content.append("a=rtpmap:96 PS/90000\r\n");
  317 + content.append("a=fmtp:126 profile-level-id=42e01e\r\n");
  318 + content.append("a=rtpmap:126 H264/90000\r\n");
  319 + content.append("a=rtpmap:125 H264S/90000\r\n");
  320 + content.append("a=fmtp:125 profile-level-id=42e01e\r\n");
  321 + content.append("a=rtpmap:99 H265/90000\r\n");
  322 + content.append("a=rtpmap:98 H264/90000\r\n");
  323 + content.append("a=rtpmap:97 MPEG4/90000\r\n");
  324 + if ("TCP-PASSIVE".equalsIgnoreCase(device.getStreamMode())) { // tcp被动模式
  325 + content.append("a=setup:passive\r\n");
  326 + content.append("a=connection:new\r\n");
  327 + } else if ("TCP-ACTIVE".equalsIgnoreCase(device.getStreamMode())) { // tcp主动模式
  328 + content.append("a=setup:active\r\n");
  329 + content.append("a=connection:new\r\n");
  330 + }
  331 + } else {
  332 + if ("TCP-PASSIVE".equalsIgnoreCase(device.getStreamMode())) {
  333 + content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 97 98 99\r\n");
  334 + } else if ("TCP-ACTIVE".equalsIgnoreCase(device.getStreamMode())) {
  335 + content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 97 98 99\r\n");
  336 + } else if ("UDP".equalsIgnoreCase(device.getStreamMode())) {
  337 + content.append("m=video " + ssrcInfo.getPort() + " RTP/AVP 96 97 98 99\r\n");
  338 + }
  339 + content.append("a=recvonly\r\n");
  340 + content.append("a=rtpmap:96 PS/90000\r\n");
  341 + content.append("a=rtpmap:98 H264/90000\r\n");
  342 + content.append("a=rtpmap:97 MPEG4/90000\r\n");
  343 + content.append("a=rtpmap:99 H265/90000\r\n");
  344 + if ("TCP-PASSIVE".equalsIgnoreCase(device.getStreamMode())) { // tcp被动模式
  345 + content.append("a=setup:passive\r\n");
  346 + content.append("a=connection:new\r\n");
  347 + } else if ("TCP-ACTIVE".equalsIgnoreCase(device.getStreamMode())) { // tcp主动模式
  348 + content.append("a=setup:active\r\n");
  349 + content.append("a=connection:new\r\n");
  350 + }
  351 + }
  352 +
  353 + if (!ObjectUtils.isEmpty(channel.getStreamIdentification())) {
  354 + content.append("a=" + channel.getStreamIdentification() + "\r\n");
  355 + }
  356 +
  357 + content.append("y=" + ssrcInfo.getSsrc() + "\r\n");//ssrc
  358 + // f字段:f= v/编码格式/分辨率/帧率/码率类型/码率大小a/编码格式/码率大小/采样率
  359 +// content.append("f=v/2/5/25/1/4000a/1/8/1" + "\r\n"); // 未发现支持此特性的设备
  360 +
  361 +
  362 +
  363 + Request request = headerProvider.createInviteRequest(device, channel.getChannelId(), content.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null, ssrcInfo.getSsrc(),sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));
  364 + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, (e -> {
  365 + streamSession.remove(device.getDeviceId(), channel.getChannelId(), ssrcInfo.getStream());
  366 + mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
  367 + errorEvent.response(e);
  368 + }), e -> {
  369 + ResponseEvent responseEvent = (ResponseEvent) e.event;
  370 + SIPResponse response = (SIPResponse) responseEvent.getResponse();
  371 + String callId = response.getCallIdHeader().getCallId();
  372 + streamSession.put(device.getDeviceId(), channel.getChannelId(), callId, stream, ssrcInfo.getSsrc(), mediaServerItem.getId(), response,
  373 + InviteSessionType.PLAY);
  374 + okEvent.response(e);
  375 + });
  376 + }
  377 +
  378 + /**
  379 + * 请求回放视频流
  380 + *
  381 + * @param device 视频设备
  382 + * @param channelId 预览通道
  383 + * @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss
  384 + * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss
  385 + */
  386 + @Override
  387 + public void playbackStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId,
  388 + String startTime, String endTime, ZlmHttpHookSubscribe.Event hookEvent,
  389 + SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException {
  390 +
  391 +
  392 + logger.info("{} 分配的ZLM为: {} [{}:{}]", ssrcInfo.getStream(), mediaServerItem.getId(), mediaServerItem.getSdpIp(), ssrcInfo.getPort());
  393 + String sdpIp;
  394 + if (!ObjectUtils.isEmpty(device.getSdpIp())) {
  395 + sdpIp = device.getSdpIp();
  396 + }else {
  397 + sdpIp = mediaServerItem.getSdpIp();
  398 + }
  399 + StringBuffer content = new StringBuffer(200);
  400 + content.append("v=0\r\n");
  401 + content.append("o=" + channelId + " 0 0 IN IP4 " + sdpIp + "\r\n");
  402 + content.append("s=Playback\r\n");
  403 + content.append("u=" + channelId + ":0\r\n");
  404 + content.append("c=IN IP4 " + sdpIp + "\r\n");
  405 + content.append("t=" + DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(startTime) + " "
  406 + + DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(endTime) + "\r\n");
  407 +
  408 + String streamMode = device.getStreamMode();
  409 +
  410 + if (userSetting.isSeniorSdp()) {
  411 + if ("TCP-PASSIVE".equalsIgnoreCase(streamMode)) {
  412 + content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 126 125 99 34 98 97\r\n");
  413 + } else if ("TCP-ACTIVE".equalsIgnoreCase(streamMode)) {
  414 + content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 126 125 99 34 98 97\r\n");
  415 + } else if ("UDP".equalsIgnoreCase(streamMode)) {
  416 + content.append("m=video " + ssrcInfo.getPort() + " RTP/AVP 96 126 125 99 34 98 97\r\n");
  417 + }
  418 + content.append("a=recvonly\r\n");
  419 + content.append("a=rtpmap:96 PS/90000\r\n");
  420 + content.append("a=fmtp:126 profile-level-id=42e01e\r\n");
  421 + content.append("a=rtpmap:126 H264/90000\r\n");
  422 + content.append("a=rtpmap:125 H264S/90000\r\n");
  423 + content.append("a=fmtp:125 profile-level-id=42e01e\r\n");
  424 + content.append("a=rtpmap:99 H265/90000\r\n");
  425 + content.append("a=rtpmap:98 H264/90000\r\n");
  426 + content.append("a=rtpmap:97 MPEG4/90000\r\n");
  427 + if ("TCP-PASSIVE".equalsIgnoreCase(streamMode)) { // tcp被动模式
  428 + content.append("a=setup:passive\r\n");
  429 + content.append("a=connection:new\r\n");
  430 + } else if ("TCP-ACTIVE".equalsIgnoreCase(streamMode)) { // tcp主动模式
  431 + content.append("a=setup:active\r\n");
  432 + content.append("a=connection:new\r\n");
  433 + }
  434 + } else {
  435 + if ("TCP-PASSIVE".equalsIgnoreCase(streamMode)) {
  436 + content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 97 98 99\r\n");
  437 + } else if ("TCP-ACTIVE".equalsIgnoreCase(streamMode)) {
  438 + content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 97 98 99\r\n");
  439 + } else if ("UDP".equalsIgnoreCase(streamMode)) {
  440 + content.append("m=video " + ssrcInfo.getPort() + " RTP/AVP 96 97 98 99\r\n");
  441 + }
  442 + content.append("a=recvonly\r\n");
  443 + content.append("a=rtpmap:96 PS/90000\r\n");
  444 + content.append("a=rtpmap:97 MPEG4/90000\r\n");
  445 + content.append("a=rtpmap:98 H264/90000\r\n");
  446 + content.append("a=rtpmap:99 H265/90000\r\n");
  447 + if ("TCP-PASSIVE".equalsIgnoreCase(streamMode)) {
  448 + // tcp被动模式
  449 + content.append("a=setup:passive\r\n");
  450 + content.append("a=connection:new\r\n");
  451 + } else if ("TCP-ACTIVE".equalsIgnoreCase(streamMode)) {
  452 + // tcp主动模式
  453 + content.append("a=setup:active\r\n");
  454 + content.append("a=connection:new\r\n");
  455 + }
  456 + }
  457 +
  458 + //ssrc
  459 + content.append("y=" + ssrcInfo.getSsrc() + "\r\n");
  460 +
  461 + HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", ssrcInfo.getStream(), true, "rtsp", mediaServerItem.getId());
  462 + // 添加订阅
  463 + subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, HookParam hookParam) -> {
  464 + if (hookEvent != null) {
  465 + hookEvent.response(mediaServerItemInUse, hookParam);
  466 + }
  467 + subscribe.removeSubscribe(hookSubscribe);
  468 + });
  469 + Request request = headerProvider.createPlaybackInviteRequest(device, channelId, content.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()), ssrcInfo.getSsrc());
  470 +
  471 + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent, event -> {
  472 + ResponseEvent responseEvent = (ResponseEvent) event.event;
  473 + SIPResponse response = (SIPResponse) responseEvent.getResponse();
  474 + streamSession.put(device.getDeviceId(), channelId,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()).getCallId(), ssrcInfo.getStream(), ssrcInfo.getSsrc(), mediaServerItem.getId(), response, InviteSessionType.PLAYBACK);
  475 + okEvent.response(event);
  476 + });
  477 + }
  478 +
  479 + /**
  480 + * 请求历史媒体下载
  481 + *
  482 + * @param device 视频设备
  483 + * @param channelId 预览通道
  484 + * @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss
  485 + * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss
  486 + * @param downloadSpeed 下载倍速参数
  487 + */
  488 + @Override
  489 + public void downloadStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId,
  490 + String startTime, String endTime, int downloadSpeed,
  491 + ZlmHttpHookSubscribe.Event hookEvent,
  492 + SipSubscribe.Event errorEvent,SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException {
  493 +
  494 + logger.info("{} 分配的ZLM为: {} [{}:{}]", ssrcInfo.getStream(), mediaServerItem.getId(), mediaServerItem.getSdpIp(), ssrcInfo.getPort());
  495 + String sdpIp;
  496 + if (!ObjectUtils.isEmpty(device.getSdpIp())) {
  497 + sdpIp = device.getSdpIp();
  498 + }else {
  499 + sdpIp = mediaServerItem.getSdpIp();
  500 + }
  501 + StringBuffer content = new StringBuffer(200);
  502 + content.append("v=0\r\n");
  503 + content.append("o=" + channelId + " 0 0 IN IP4 " + sdpIp + "\r\n");
  504 + content.append("s=Download\r\n");
  505 + content.append("u=" + channelId + ":0\r\n");
  506 + content.append("c=IN IP4 " + sdpIp + "\r\n");
  507 + content.append("t=" + DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(startTime) + " "
  508 + + DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(endTime) + "\r\n");
  509 +
  510 + String streamMode = device.getStreamMode().toUpperCase();
  511 +
  512 + if (userSetting.isSeniorSdp()) {
  513 + if ("TCP-PASSIVE".equals(streamMode)) {
  514 + content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 126 125 99 34 98 97\r\n");
  515 + } else if ("TCP-ACTIVE".equals(streamMode)) {
  516 + content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 126 125 99 34 98 97\r\n");
  517 + } else if ("UDP".equals(streamMode)) {
  518 + content.append("m=video " + ssrcInfo.getPort() + " RTP/AVP 96 126 125 99 34 98 97\r\n");
  519 + }
  520 + content.append("a=recvonly\r\n");
  521 + content.append("a=rtpmap:96 PS/90000\r\n");
  522 + content.append("a=fmtp:126 profile-level-id=42e01e\r\n");
  523 + content.append("a=rtpmap:126 H264/90000\r\n");
  524 + content.append("a=rtpmap:125 H264S/90000\r\n");
  525 + content.append("a=fmtp:125 profile-level-id=42e01e\r\n");
  526 + content.append("a=rtpmap:99 MP4V-ES/90000\r\n");
  527 + content.append("a=fmtp:99 profile-level-id=3\r\n");
  528 + content.append("a=rtpmap:98 H264/90000\r\n");
  529 + content.append("a=rtpmap:97 MPEG4/90000\r\n");
  530 + if ("TCP-PASSIVE".equals(streamMode)) { // tcp被动模式
  531 + content.append("a=setup:passive\r\n");
  532 + content.append("a=connection:new\r\n");
  533 + } else if ("TCP-ACTIVE".equals(streamMode)) { // tcp主动模式
  534 + content.append("a=setup:active\r\n");
  535 + content.append("a=connection:new\r\n");
  536 + }
  537 + } else {
  538 + if ("TCP-PASSIVE".equals(streamMode)) {
  539 + content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 97 98 99\r\n");
  540 + } else if ("TCP-ACTIVE".equals(streamMode)) {
  541 + content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 97 98 99\r\n");
  542 + } else if ("UDP".equals(streamMode)) {
  543 + content.append("m=video " + ssrcInfo.getPort() + " RTP/AVP 96 97 98 99\r\n");
  544 + }
  545 + content.append("a=recvonly\r\n");
  546 + content.append("a=rtpmap:96 PS/90000\r\n");
  547 + content.append("a=rtpmap:97 MPEG4/90000\r\n");
  548 + content.append("a=rtpmap:98 H264/90000\r\n");
  549 + content.append("a=rtpmap:99 H265/90000\r\n");
  550 + if ("TCP-PASSIVE".equals(streamMode)) { // tcp被动模式
  551 + content.append("a=setup:passive\r\n");
  552 + content.append("a=connection:new\r\n");
  553 + } else if ("TCP-ACTIVE".equals(streamMode)) { // tcp主动模式
  554 + content.append("a=setup:active\r\n");
  555 + content.append("a=connection:new\r\n");
  556 + }
  557 + }
  558 + content.append("a=downloadspeed:" + downloadSpeed + "\r\n");
  559 +
  560 + content.append("y=" + ssrcInfo.getSsrc() + "\r\n");//ssrc
  561 + logger.debug("此时请求下载信令的ssrc===>{}",ssrcInfo.getSsrc());
  562 + HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", ssrcInfo.getStream(), true, "rtsp", mediaServerItem.getId());
  563 + // 添加订阅
  564 + CallIdHeader newCallIdHeader = sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()), device.getTransport());
  565 + String callId= newCallIdHeader.getCallId();
  566 + subscribe.addSubscribe(hookSubscribe, (mediaServerItemInUse, hookParam) -> {
  567 + logger.debug("sipc 添加订阅===callId {}",callId);
  568 + hookEvent.response(mediaServerItemInUse, hookParam);
  569 + subscribe.removeSubscribe(hookSubscribe);
  570 + hookSubscribe.getContent().put("regist", false);
  571 + hookSubscribe.getContent().put("schema", "rtsp");
  572 + // 添加流注销的订阅,注销了后向设备发送bye
  573 + subscribe.addSubscribe(hookSubscribe,
  574 + (mediaServerItemForEnd, hookParam1) -> {
  575 + logger.info("[录像]下载结束, 发送BYE");
  576 + try {
  577 + streamByeCmd(device, channelId, ssrcInfo.getStream(), callId);
  578 + } catch (InvalidArgumentException | ParseException | SipException |
  579 + SsrcTransactionNotFoundException e) {
  580 + logger.error("[录像]下载结束, 发送BYE失败 {}", e.getMessage());
  581 + }
  582 + });
  583 + });
  584 +
  585 + Request request = headerProvider.createPlaybackInviteRequest(device, channelId, content.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,newCallIdHeader, ssrcInfo.getSsrc());
  586 +
  587 + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent, event -> {
  588 + ResponseEvent responseEvent = (ResponseEvent) event.event;
  589 + SIPResponse response = (SIPResponse) responseEvent.getResponse();
  590 + String contentString =new String(response.getRawContent());
  591 + String ssrc = SipUtils.getSsrcFromSdp(contentString);
  592 + streamSession.put(device.getDeviceId(), channelId, response.getCallIdHeader().getCallId(), ssrcInfo.getStream(), ssrc, mediaServerItem.getId(), response, InviteSessionType.DOWNLOAD);
  593 + okEvent.response(event);
  594 + });
  595 + }
  596 +
  597 + @Override
  598 + public void talkStreamCmd(MediaServerItem mediaServerItem, SendRtpItem sendRtpItem, Device device, String channelId, String callId, ZlmHttpHookSubscribe.Event event, ZlmHttpHookSubscribe.Event eventForPush, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException {
  599 +
  600 + String stream = sendRtpItem.getStream();
  601 +
  602 + if (device == null) {
  603 + return;
  604 + }
  605 + if (!mediaServerItem.isRtpEnable()) {
  606 + // 单端口暂不支持语音喊话
  607 + logger.info("[语音喊话] 单端口暂不支持此操作");
  608 + return;
  609 + }
  610 +
  611 + logger.info("[语音喊话] {} 分配的ZLM为: {} [{}:{}]", stream, mediaServerItem.getId(), mediaServerItem.getIp(), sendRtpItem.getPort());
  612 + HookSubscribeForStreamChange hookSubscribeForStreamChange = HookSubscribeFactory.on_stream_changed("rtp", stream, true, "rtsp", mediaServerItem.getId());
  613 + subscribe.addSubscribe(hookSubscribeForStreamChange, (mediaServerItemInUse, hookParam) -> {
  614 + if (event != null) {
  615 + event.response(mediaServerItemInUse, hookParam);
  616 + subscribe.removeSubscribe(hookSubscribeForStreamChange);
  617 + }
  618 + });
  619 +
  620 + CallIdHeader callIdHeader = sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()), device.getTransport());
  621 + callIdHeader.setCallId(callId);
  622 + HookSubscribeForStreamPush hookSubscribeForStreamPush = HookSubscribeFactory.on_publish("rtp", stream, null, mediaServerItem.getId());
  623 + subscribe.addSubscribe(hookSubscribeForStreamPush, (mediaServerItemInUse, hookParam) -> {
  624 + if (eventForPush != null) {
  625 + eventForPush.response(mediaServerItemInUse, hookParam);
  626 + }
  627 + });
  628 + //
  629 + StringBuffer content = new StringBuffer(200);
  630 + content.append("v=0\r\n");
  631 + content.append("o=" + channelId + " 0 0 IN IP4 " + mediaServerItem.getSdpIp() + "\r\n");
  632 + content.append("s=Talk\r\n");
  633 + content.append("c=IN IP4 " + mediaServerItem.getSdpIp() + "\r\n");
  634 + content.append("t=0 0\r\n");
  635 +
  636 + content.append("m=audio " + sendRtpItem.getPort() + " TCP/RTP/AVP 8\r\n");
  637 + content.append("a=setup:passive\r\n");
  638 + content.append("a=connection:new\r\n");
  639 + content.append("a=sendrecv\r\n");
  640 + content.append("a=rtpmap:8 PCMA/8000\r\n");
  641 +
  642 + content.append("y=" + sendRtpItem.getSsrc() + "\r\n");//ssrc
  643 + // f字段:f= v/编码格式/分辨率/帧率/码率类型/码率大小a/编码格式/码率大小/采样率
  644 + content.append("f=v/////a/1/8/1" + "\r\n");
  645 +
  646 + Request request = headerProvider.createInviteRequest(device, channelId, content.toString(),
  647 + SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null, sendRtpItem.getSsrc(), callIdHeader);
  648 + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, (e -> {
  649 + streamSession.remove(device.getDeviceId(), channelId, sendRtpItem.getStream());
  650 + mediaServerService.releaseSsrc(mediaServerItem.getId(), sendRtpItem.getSsrc());
  651 + errorEvent.response(e);
  652 + }), e -> {
  653 + // 这里为例避免一个通道的点播只有一个callID这个参数使用一个固定值
  654 + ResponseEvent responseEvent = (ResponseEvent) e.event;
  655 + SIPResponse response = (SIPResponse) responseEvent.getResponse();
  656 + streamSession.put(device.getDeviceId(), channelId, "talk", stream, sendRtpItem.getSsrc(), mediaServerItem.getId(), response, InviteSessionType.TALK);
  657 + okEvent.response(e);
  658 + });
  659 + }
  660 +
  661 + /**
  662 + * 视频流停止, 不使用回调
  663 + */
  664 + @Override
  665 + public void streamByeCmd(Device device, String channelId, String stream, String callId) throws InvalidArgumentException, ParseException, SipException, SsrcTransactionNotFoundException {
  666 + streamByeCmd(device, channelId, stream, callId, null);
  667 + }
  668 +
  669 + /**
  670 + * 视频流停止
  671 + */
  672 + @Override
  673 + public void streamByeCmd(Device device, String channelId, String stream, String callId, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException, SsrcTransactionNotFoundException {
  674 + if (device == null) {
  675 + logger.warn("[发送BYE] device为null");
  676 + return;
  677 + }
  678 + List<SsrcTransaction> ssrcTransactionList = streamSession.getSsrcTransactionForAll(device.getDeviceId(), channelId, callId, stream);
  679 + if (ssrcTransactionList == null || ssrcTransactionList.isEmpty()) {
  680 + logger.info("[发送BYE] 未找到事务信息,设备: device: {}, channel: {}", device.getDeviceId(), channelId);
  681 + throw new SsrcTransactionNotFoundException(device.getDeviceId(), channelId, callId, stream);
  682 + }
  683 +
  684 + for (SsrcTransaction ssrcTransaction : ssrcTransactionList) {
  685 + logger.info("[发送BYE] 设备: device: {}, channel: {}, callId: {}", device.getDeviceId(), channelId, ssrcTransaction.getCallId());
  686 + mediaServerService.releaseSsrc(ssrcTransaction.getMediaServerId(), ssrcTransaction.getSsrc());
  687 +
  688 + mediaServerService.closeRTPServer(ssrcTransaction.getMediaServerId(), ssrcTransaction.getStream());
  689 + streamSession.removeByCallId(ssrcTransaction.getDeviceId(), ssrcTransaction.getChannelId(), ssrcTransaction.getCallId());
  690 + Request byteRequest = headerProvider.createByteRequest(device, channelId, ssrcTransaction.getSipTransactionInfo());
  691 + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), byteRequest, null, okEvent);
  692 + }
  693 + }
  694 +
  695 + @Override
  696 + public void streamByeCmd(Device device, String channelId, SipTransactionInfo sipTransactionInfo, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException, SsrcTransactionNotFoundException {
  697 + Request byteRequest = headerProvider.createByteRequest(device, channelId, sipTransactionInfo);
  698 + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), byteRequest, null, okEvent);
  699 + }
  700 +
  701 + @Override
  702 + public void streamByeCmdForDeviceInvite(Device device, String channelId, SipTransactionInfo sipTransactionInfo, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException, SsrcTransactionNotFoundException {
  703 + Request byteRequest = headerProvider.createByteRequestForDeviceInvite(device, channelId, sipTransactionInfo);
  704 + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), byteRequest, null, okEvent);
  705 + }
  706 +
  707 + /**
  708 + * 语音广播
  709 + *
  710 + * @param device 视频设备
  711 + */
  712 + @Override
  713 + public void audioBroadcastCmd(Device device, String channelId, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException {
  714 + StringBuffer broadcastXml = new StringBuffer(200);
  715 + String charset = device.getCharset();
  716 + broadcastXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
  717 + broadcastXml.append("<Notify>\r\n");
  718 + broadcastXml.append("<CmdType>Broadcast</CmdType>\r\n");
  719 + broadcastXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
  720 + broadcastXml.append("<SourceID>" + sipConfig.getId() + "</SourceID>\r\n");
  721 + broadcastXml.append("<TargetID>" + channelId + "</TargetID>\r\n");
  722 + broadcastXml.append("</Notify>\r\n");
  723 +
  724 + Request request = headerProvider.createMessageRequest(device, broadcastXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));
  725 + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent, okEvent);
  726 +
  727 + }
  728 +
  729 +
  730 + /**
  731 + * 音视频录像控制
  732 + *
  733 + * @param device 视频设备
  734 + * @param channelId 预览通道
  735 + * @param recordCmdStr 录像命令:Record / StopRecord
  736 + */
  737 + @Override
  738 + public void recordCmd(Device device, String channelId, String recordCmdStr, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException {
  739 + StringBuffer cmdXml = new StringBuffer(200);
  740 + String charset = device.getCharset();
  741 + cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
  742 + cmdXml.append("<Control>\r\n");
  743 + cmdXml.append("<CmdType>DeviceControl</CmdType>\r\n");
  744 + cmdXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");
  745 + if (ObjectUtils.isEmpty(channelId)) {
  746 + cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
  747 + } else {
  748 + cmdXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
  749 + }
  750 + cmdXml.append("<RecordCmd>" + recordCmdStr + "</RecordCmd>\r\n");
  751 + cmdXml.append("</Control>\r\n");
  752 +
  753 +
  754 +
  755 + Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));
  756 + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent,okEvent);
  757 + }
  758 +
  759 + /**
  760 + * 远程启动控制命令
  761 + *
  762 + * @param device 视频设备
  763 + */
  764 + @Override
  765 + public void teleBootCmd(Device device) throws InvalidArgumentException, SipException, ParseException {
  766 +
  767 + StringBuffer cmdXml = new StringBuffer(200);
  768 + String charset = device.getCharset();
  769 + cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
  770 + cmdXml.append("<Control>\r\n");
  771 + cmdXml.append("<CmdType>DeviceControl</CmdType>\r\n");
  772 + cmdXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");
  773 + cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
  774 + cmdXml.append("<TeleBoot>Boot</TeleBoot>\r\n");
  775 + cmdXml.append("</Control>\r\n");
  776 +
  777 +
  778 +
  779 + Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));
  780 + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request);
  781 + }
  782 +
  783 + /**
  784 + * 报警布防/撤防命令
  785 + *
  786 + * @param device 视频设备
  787 + * @param guardCmdStr "SetGuard"/"ResetGuard"
  788 + */
  789 + @Override
  790 + public void guardCmd(Device device, String guardCmdStr, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException {
  791 +
  792 + StringBuffer cmdXml = new StringBuffer(200);
  793 + String charset = device.getCharset();
  794 + cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
  795 + cmdXml.append("<Control>\r\n");
  796 + cmdXml.append("<CmdType>DeviceControl</CmdType>\r\n");
  797 + cmdXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");
  798 + cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
  799 + cmdXml.append("<GuardCmd>" + guardCmdStr + "</GuardCmd>\r\n");
  800 + cmdXml.append("</Control>\r\n");
  801 +
  802 +
  803 +
  804 + Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));
  805 + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent,okEvent);
  806 + }
  807 +
  808 + /**
  809 + * 报警复位命令
  810 + *
  811 + * @param device 视频设备
  812 + */
  813 + @Override
  814 + public void alarmCmd(Device device, String alarmMethod, String alarmType, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException {
  815 +
  816 + StringBuffer cmdXml = new StringBuffer(200);
  817 + String charset = device.getCharset();
  818 + cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
  819 + cmdXml.append("<Control>\r\n");
  820 + cmdXml.append("<CmdType>DeviceControl</CmdType>\r\n");
  821 + cmdXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");
  822 + cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
  823 + cmdXml.append("<AlarmCmd>ResetAlarm</AlarmCmd>\r\n");
  824 + if (!ObjectUtils.isEmpty(alarmMethod) || !ObjectUtils.isEmpty(alarmType)) {
  825 + cmdXml.append("<Info>\r\n");
  826 + }
  827 + if (!ObjectUtils.isEmpty(alarmMethod)) {
  828 + cmdXml.append("<AlarmMethod>" + alarmMethod + "</AlarmMethod>\r\n");
  829 + }
  830 + if (!ObjectUtils.isEmpty(alarmType)) {
  831 + cmdXml.append("<AlarmType>" + alarmType + "</AlarmType>\r\n");
  832 + }
  833 + if (!ObjectUtils.isEmpty(alarmMethod) || !ObjectUtils.isEmpty(alarmType)) {
  834 + cmdXml.append("</Info>\r\n");
  835 + }
  836 + cmdXml.append("</Control>\r\n");
  837 +
  838 +
  839 +
  840 + Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));
  841 + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent,okEvent);
  842 + }
  843 +
  844 + /**
  845 + * 强制关键帧命令,设备收到此命令应立刻发送一个IDR帧
  846 + *
  847 + * @param device 视频设备
  848 + * @param channelId 预览通道
  849 + */
  850 + @Override
  851 + public void iFrameCmd(Device device, String channelId) throws InvalidArgumentException, SipException, ParseException {
  852 +
  853 + StringBuffer cmdXml = new StringBuffer(200);
  854 + String charset = device.getCharset();
  855 + cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
  856 + cmdXml.append("<Control>\r\n");
  857 + cmdXml.append("<CmdType>DeviceControl</CmdType>\r\n");
  858 + cmdXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");
  859 + if (ObjectUtils.isEmpty(channelId)) {
  860 + cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
  861 + } else {
  862 + cmdXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
  863 + }
  864 + cmdXml.append("<IFameCmd>Send</IFameCmd>\r\n");
  865 + cmdXml.append("</Control>\r\n");
  866 +
  867 +
  868 +
  869 + Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));
  870 + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request);
  871 + }
  872 +
  873 + /**
  874 + * 看守位控制命令
  875 + *
  876 + * @param device 视频设备
  877 + * @param channelId 通道id,非通道则是设备本身
  878 + * @param enabled 看守位使能:1 = 开启,0 = 关闭
  879 + * @param resetTime 自动归位时间间隔,开启看守位时使用,单位:秒(s)
  880 + * @param presetIndex 调用预置位编号,开启看守位时使用,取值范围0~255
  881 + */
  882 + @Override
  883 + public void homePositionCmd(Device device, String channelId, String enabled, String resetTime, String presetIndex, SipSubscribe.Event errorEvent,SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException {
  884 +
  885 + StringBuffer cmdXml = new StringBuffer(200);
  886 + String charset = device.getCharset();
  887 + cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
  888 + cmdXml.append("<Control>\r\n");
  889 + cmdXml.append("<CmdType>DeviceControl</CmdType>\r\n");
  890 + cmdXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");
  891 + if (ObjectUtils.isEmpty(channelId)) {
  892 + cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
  893 + } else {
  894 + cmdXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
  895 + }
  896 + cmdXml.append("<HomePosition>\r\n");
  897 + if (NumericUtil.isInteger(enabled) && (!enabled.equals("0"))) {
  898 + cmdXml.append("<Enabled>1</Enabled>\r\n");
  899 + if (NumericUtil.isInteger(resetTime)) {
  900 + cmdXml.append("<ResetTime>" + resetTime + "</ResetTime>\r\n");
  901 + } else {
  902 + cmdXml.append("<ResetTime>0</ResetTime>\r\n");
  903 + }
  904 + if (NumericUtil.isInteger(presetIndex)) {
  905 + cmdXml.append("<PresetIndex>" + presetIndex + "</PresetIndex>\r\n");
  906 + } else {
  907 + cmdXml.append("<PresetIndex>0</PresetIndex>\r\n");
  908 + }
  909 + } else {
  910 + cmdXml.append("<Enabled>0</Enabled>\r\n");
  911 + }
  912 + cmdXml.append("</HomePosition>\r\n");
  913 + cmdXml.append("</Control>\r\n");
  914 +
  915 +
  916 +
  917 + Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));
  918 + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent,okEvent);
  919 + }
  920 +
  921 + /**
  922 + * 设备配置命令
  923 + *
  924 + * @param device 视频设备
  925 + */
  926 + @Override
  927 + public void deviceConfigCmd(Device device) {
  928 + // TODO Auto-generated method stub
  929 + }
  930 +
  931 + /**
  932 + * 设备配置命令:basicParam
  933 + *
  934 + * @param device 视频设备
  935 + * @param channelId 通道编码(可选)
  936 + * @param name 设备/通道名称(可选)
  937 + * @param expiration 注册过期时间(可选)
  938 + * @param heartBeatInterval 心跳间隔时间(可选)
  939 + * @param heartBeatCount 心跳超时次数(可选)
  940 + */
  941 + @Override
  942 + public void deviceBasicConfigCmd(Device device, String channelId, String name, String expiration,
  943 + String heartBeatInterval, String heartBeatCount, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException {
  944 +
  945 + StringBuffer cmdXml = new StringBuffer(200);
  946 + String charset = device.getCharset();
  947 + cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
  948 + cmdXml.append("<Control>\r\n");
  949 + cmdXml.append("<CmdType>DeviceConfig</CmdType>\r\n");
  950 + cmdXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");
  951 + if (ObjectUtils.isEmpty(channelId)) {
  952 + cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
  953 + } else {
  954 + cmdXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
  955 + }
  956 + cmdXml.append("<BasicParam>\r\n");
  957 + if (!ObjectUtils.isEmpty(name)) {
  958 + cmdXml.append("<Name>" + name + "</Name>\r\n");
  959 + }
  960 + if (NumericUtil.isInteger(expiration)) {
  961 + if (Integer.valueOf(expiration) > 0) {
  962 + cmdXml.append("<Expiration>" + expiration + "</Expiration>\r\n");
  963 + }
  964 + }
  965 + if (NumericUtil.isInteger(heartBeatInterval)) {
  966 + if (Integer.valueOf(heartBeatInterval) > 0) {
  967 + cmdXml.append("<HeartBeatInterval>" + heartBeatInterval + "</HeartBeatInterval>\r\n");
  968 + }
  969 + }
  970 + if (NumericUtil.isInteger(heartBeatCount)) {
  971 + if (Integer.valueOf(heartBeatCount) > 0) {
  972 + cmdXml.append("<HeartBeatCount>" + heartBeatCount + "</HeartBeatCount>\r\n");
  973 + }
  974 + }
  975 + cmdXml.append("</BasicParam>\r\n");
  976 + cmdXml.append("</Control>\r\n");
  977 +
  978 +
  979 +
  980 + Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));
  981 + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent);
  982 + }
  983 +
  984 + /**
  985 + * 查询设备状态
  986 + *
  987 + * @param device 视频设备
  988 + */
  989 + @Override
  990 + public void deviceStatusQuery(Device device, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException {
  991 +
  992 + String charset = device.getCharset();
  993 + StringBuffer catalogXml = new StringBuffer(200);
  994 + catalogXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
  995 + catalogXml.append("<Query>\r\n");
  996 + catalogXml.append("<CmdType>DeviceStatus</CmdType>\r\n");
  997 + catalogXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");
  998 + catalogXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
  999 + catalogXml.append("</Query>\r\n");
  1000 +
  1001 +
  1002 +
  1003 + Request request = headerProvider.createMessageRequest(device, catalogXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));
  1004 +
  1005 + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent);
  1006 + }
  1007 +
  1008 + /**
  1009 + * 查询设备信息
  1010 + *
  1011 + * @param device 视频设备
  1012 + */
  1013 + @Override
  1014 + public void deviceInfoQuery(Device device) throws InvalidArgumentException, SipException, ParseException {
  1015 +
  1016 + StringBuffer catalogXml = new StringBuffer(200);
  1017 + String charset = device.getCharset();
  1018 + catalogXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
  1019 + catalogXml.append("<Query>\r\n");
  1020 + catalogXml.append("<CmdType>DeviceInfo</CmdType>\r\n");
  1021 + catalogXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");
  1022 + catalogXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
  1023 + catalogXml.append("</Query>\r\n");
  1024 +
  1025 +
  1026 +
  1027 + Request request = headerProvider.createMessageRequest(device, catalogXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));
  1028 +
  1029 + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request);
  1030 +
  1031 + }
  1032 +
  1033 + /**
  1034 + * 查询目录列表
  1035 + *
  1036 + * @param device 视频设备
  1037 + */
  1038 + @Override
  1039 + public void catalogQuery(Device device, int sn, SipSubscribe.Event errorEvent) throws SipException, InvalidArgumentException, ParseException {
  1040 +
  1041 + StringBuffer catalogXml = new StringBuffer(200);
  1042 + String charset = device.getCharset();
  1043 + catalogXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
  1044 + catalogXml.append("<Query>\r\n");
  1045 + catalogXml.append(" <CmdType>Catalog</CmdType>\r\n");
  1046 + catalogXml.append(" <SN>" + sn + "</SN>\r\n");
  1047 + catalogXml.append(" <DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
  1048 + catalogXml.append("</Query>\r\n");
  1049 +
  1050 +
  1051 +
  1052 + Request request = headerProvider.createMessageRequest(device, catalogXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));
  1053 +
  1054 + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent);
  1055 + }
  1056 +
  1057 + /**
  1058 + * 查询录像信息
  1059 + *
  1060 + * @param device 视频设备
  1061 + * @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss
  1062 + * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss
  1063 + */
  1064 + @Override
  1065 + 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 {
  1066 + if (secrecy == null) {
  1067 + secrecy = 0;
  1068 + }
  1069 + if (type == null) {
  1070 + type = "all";
  1071 + }
  1072 +
  1073 + StringBuffer recordInfoXml = new StringBuffer(200);
  1074 + String charset = device.getCharset();
  1075 + recordInfoXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
  1076 + recordInfoXml.append("<Query>\r\n");
  1077 + recordInfoXml.append("<CmdType>RecordInfo</CmdType>\r\n");
  1078 + recordInfoXml.append("<SN>" + sn + "</SN>\r\n");
  1079 + recordInfoXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
  1080 + if (startTime != null) {
  1081 + recordInfoXml.append("<StartTime>" + DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(startTime) + "</StartTime>\r\n");
  1082 + }
  1083 + if (endTime != null) {
  1084 + recordInfoXml.append("<EndTime>" + DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(endTime) + "</EndTime>\r\n");
  1085 + }
  1086 + if (secrecy != null) {
  1087 + recordInfoXml.append("<Secrecy> " + secrecy + " </Secrecy>\r\n");
  1088 + }
  1089 + if (type != null) {
  1090 + // 大华NVR要求必须增加一个值为all的文本元素节点Type
  1091 + recordInfoXml.append("<Type>" + type + "</Type>\r\n");
  1092 + }
  1093 + recordInfoXml.append("</Query>\r\n");
  1094 +
  1095 +
  1096 +
  1097 + Request request = headerProvider.createMessageRequest(device, recordInfoXml.toString(),
  1098 + SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));
  1099 +
  1100 + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent, okEvent);
  1101 + }
  1102 +
  1103 + /**
  1104 + * 查询报警信息
  1105 + *
  1106 + * @param device 视频设备
  1107 + * @param startPriority 报警起始级别(可选)
  1108 + * @param endPriority 报警终止级别(可选)
  1109 + * @param alarmMethod 报警方式条件(可选)
  1110 + * @param alarmType 报警类型
  1111 + * @param startTime 报警发生起始时间(可选)
  1112 + * @param endTime 报警发生终止时间(可选)
  1113 + * @return true = 命令发送成功
  1114 + */
  1115 + @Override
  1116 + public void alarmInfoQuery(Device device, String startPriority, String endPriority, String alarmMethod, String alarmType,
  1117 + String startTime, String endTime, 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>Alarm</CmdType>\r\n");
  1124 + cmdXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");
  1125 + cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
  1126 + if (!ObjectUtils.isEmpty(startPriority)) {
  1127 + cmdXml.append("<StartAlarmPriority>" + startPriority + "</StartAlarmPriority>\r\n");
  1128 + }
  1129 + if (!ObjectUtils.isEmpty(endPriority)) {
  1130 + cmdXml.append("<EndAlarmPriority>" + endPriority + "</EndAlarmPriority>\r\n");
  1131 + }
  1132 + if (!ObjectUtils.isEmpty(alarmMethod)) {
  1133 + cmdXml.append("<AlarmMethod>" + alarmMethod + "</AlarmMethod>\r\n");
  1134 + }
  1135 + if (!ObjectUtils.isEmpty(alarmType)) {
  1136 + cmdXml.append("<AlarmType>" + alarmType + "</AlarmType>\r\n");
  1137 + }
  1138 + if (!ObjectUtils.isEmpty(startTime)) {
  1139 + cmdXml.append("<StartAlarmTime>" + startTime + "</StartAlarmTime>\r\n");
  1140 + }
  1141 + if (!ObjectUtils.isEmpty(endTime)) {
  1142 + cmdXml.append("<EndAlarmTime>" + endTime + "</EndAlarmTime>\r\n");
  1143 + }
  1144 + cmdXml.append("</Query>\r\n");
  1145 +
  1146 +
  1147 +
  1148 + Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));
  1149 + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent);
  1150 + }
  1151 +
  1152 + /**
  1153 + * 查询设备配置
  1154 + *
  1155 + * @param device 视频设备
  1156 + * @param channelId 通道编码(可选)
  1157 + * @param configType 配置类型:
  1158 + */
  1159 + @Override
  1160 + public void deviceConfigQuery(Device device, String channelId, String configType, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException {
  1161 +
  1162 + StringBuffer cmdXml = new StringBuffer(200);
  1163 + String charset = device.getCharset();
  1164 + cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
  1165 + cmdXml.append("<Query>\r\n");
  1166 + cmdXml.append("<CmdType>ConfigDownload</CmdType>\r\n");
  1167 + cmdXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");
  1168 + if (ObjectUtils.isEmpty(channelId)) {
  1169 + cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
  1170 + } else {
  1171 + cmdXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
  1172 + }
  1173 + cmdXml.append("<ConfigType>" + configType + "</ConfigType>\r\n");
  1174 + cmdXml.append("</Query>\r\n");
  1175 +
  1176 +
  1177 +
  1178 + Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));
  1179 + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent);
  1180 + }
  1181 +
  1182 + /**
  1183 + * 查询设备预置位置
  1184 + *
  1185 + * @param device 视频设备
  1186 + */
  1187 + @Override
  1188 + public void presetQuery(Device device, String channelId, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException {
  1189 +
  1190 + StringBuffer cmdXml = new StringBuffer(200);
  1191 + String charset = device.getCharset();
  1192 + cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
  1193 + cmdXml.append("<Query>\r\n");
  1194 + cmdXml.append("<CmdType>PresetQuery</CmdType>\r\n");
  1195 + cmdXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");
  1196 + if (ObjectUtils.isEmpty(channelId)) {
  1197 + cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
  1198 + } else {
  1199 + cmdXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
  1200 + }
  1201 + cmdXml.append("</Query>\r\n");
  1202 +
  1203 +
  1204 + Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));
  1205 + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent);
  1206 + }
  1207 +
  1208 + /**
  1209 + * 查询移动设备位置数据
  1210 + *
  1211 + * @param device 视频设备
  1212 + */
  1213 + @Override
  1214 + public void mobilePostitionQuery(Device device, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException {
  1215 +
  1216 + StringBuffer mobilePostitionXml = new StringBuffer(200);
  1217 + String charset = device.getCharset();
  1218 + mobilePostitionXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
  1219 + mobilePostitionXml.append("<Query>\r\n");
  1220 + mobilePostitionXml.append("<CmdType>MobilePosition</CmdType>\r\n");
  1221 + mobilePostitionXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");
  1222 + mobilePostitionXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
  1223 + mobilePostitionXml.append("<Interval>60</Interval>\r\n");
  1224 + mobilePostitionXml.append("</Query>\r\n");
  1225 +
  1226 +
  1227 +
  1228 + Request request = headerProvider.createMessageRequest(device, mobilePostitionXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));
  1229 +
  1230 + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent);
  1231 +
  1232 + }
  1233 +
  1234 + /**
  1235 + * 订阅、取消订阅移动位置
  1236 + *
  1237 + * @param device 视频设备
  1238 + * @return true = 命令发送成功
  1239 + */
  1240 + @Override
  1241 + public SIPRequest mobilePositionSubscribe(Device device, SIPRequest requestOld, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException {
  1242 +
  1243 + StringBuffer subscribePostitionXml = new StringBuffer(200);
  1244 + String charset = device.getCharset();
  1245 + subscribePostitionXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
  1246 + subscribePostitionXml.append("<Query>\r\n");
  1247 + subscribePostitionXml.append("<CmdType>MobilePosition</CmdType>\r\n");
  1248 + subscribePostitionXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");
  1249 + subscribePostitionXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
  1250 + if (device.getSubscribeCycleForMobilePosition() > 0) {
  1251 + subscribePostitionXml.append("<Interval>" + device.getMobilePositionSubmissionInterval() + "</Interval>\r\n");
  1252 + }
  1253 + subscribePostitionXml.append("</Query>\r\n");
  1254 +
  1255 + CallIdHeader callIdHeader;
  1256 +
  1257 + if (requestOld != null) {
  1258 + callIdHeader = SipFactory.getInstance().createHeaderFactory().createCallIdHeader(requestOld.getCallIdHeader().getCallId());
  1259 + } else {
  1260 + callIdHeader = sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport());
  1261 + }
  1262 + SIPRequest request = (SIPRequest) headerProvider.createSubscribeRequest(device, subscribePostitionXml.toString(), requestOld, device.getSubscribeCycleForMobilePosition(), "presence",callIdHeader); //Position;id=" + tm.substring(tm.length() - 4));
  1263 +
  1264 + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent, okEvent);
  1265 + return request;
  1266 + }
  1267 +
  1268 + /**
  1269 + * 订阅、取消订阅报警信息
  1270 + *
  1271 + * @param device 视频设备
  1272 + * @param expires 订阅过期时间(0 = 取消订阅)
  1273 + * @param startPriority 报警起始级别(可选)
  1274 + * @param endPriority 报警终止级别(可选)
  1275 + * @param alarmMethod 报警方式条件(可选)
  1276 + * @param alarmType 报警类型
  1277 + * @param startTime 报警发生起始时间(可选)
  1278 + * @param endTime 报警发生终止时间(可选)
  1279 + * @return true = 命令发送成功
  1280 + */
  1281 + @Override
  1282 + public void alarmSubscribe(Device device, int expires, String startPriority, String endPriority, String alarmMethod, String startTime, String endTime) 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>Alarm</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 + if (!ObjectUtils.isEmpty(startPriority)) {
  1292 + cmdXml.append("<StartAlarmPriority>" + startPriority + "</StartAlarmPriority>\r\n");
  1293 + }
  1294 + if (!ObjectUtils.isEmpty(endPriority)) {
  1295 + cmdXml.append("<EndAlarmPriority>" + endPriority + "</EndAlarmPriority>\r\n");
  1296 + }
  1297 + if (!ObjectUtils.isEmpty(alarmMethod)) {
  1298 + cmdXml.append("<AlarmMethod>" + alarmMethod + "</AlarmMethod>\r\n");
  1299 + }
  1300 + if (!ObjectUtils.isEmpty(startTime)) {
  1301 + cmdXml.append("<StartAlarmTime>" + startTime + "</StartAlarmTime>\r\n");
  1302 + }
  1303 + if (!ObjectUtils.isEmpty(endTime)) {
  1304 + cmdXml.append("<EndAlarmTime>" + endTime + "</EndAlarmTime>\r\n");
  1305 + }
  1306 + cmdXml.append("</Query>\r\n");
  1307 +
  1308 +
  1309 +
  1310 + Request request = headerProvider.createSubscribeRequest(device, cmdXml.toString(), null, expires, "presence",sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));
  1311 + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request);
  1312 +
  1313 + }
  1314 +
  1315 + @Override
  1316 + public SIPRequest catalogSubscribe(Device device, SIPRequest requestOld, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException {
  1317 +
  1318 + StringBuffer cmdXml = new StringBuffer(200);
  1319 + String charset = device.getCharset();
  1320 + cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
  1321 + cmdXml.append("<Query>\r\n");
  1322 + cmdXml.append("<CmdType>Catalog</CmdType>\r\n");
  1323 + cmdXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");
  1324 + cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
  1325 + cmdXml.append("</Query>\r\n");
  1326 +
  1327 + CallIdHeader callIdHeader;
  1328 +
  1329 + if (requestOld != null) {
  1330 + callIdHeader = SipFactory.getInstance().createHeaderFactory().createCallIdHeader(requestOld.getCallIdHeader().getCallId());
  1331 + } else {
  1332 + callIdHeader = sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport());
  1333 + }
  1334 +
  1335 + // 有效时间默认为60秒以上
  1336 + SIPRequest request = (SIPRequest) headerProvider.createSubscribeRequest(device, cmdXml.toString(), requestOld, device.getSubscribeCycleForCatalog(), "Catalog",
  1337 + callIdHeader);
  1338 + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent, okEvent);
  1339 + return request;
  1340 + }
  1341 +
  1342 + @Override
  1343 + public void dragZoomCmd(Device device, String channelId, String cmdString) throws InvalidArgumentException, SipException, ParseException {
  1344 +
  1345 + StringBuffer dragXml = new StringBuffer(200);
  1346 + String charset = device.getCharset();
  1347 + dragXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
  1348 + dragXml.append("<Control>\r\n");
  1349 + dragXml.append("<CmdType>DeviceControl</CmdType>\r\n");
  1350 + dragXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");
  1351 + if (ObjectUtils.isEmpty(channelId)) {
  1352 + dragXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
  1353 + } else {
  1354 + dragXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
  1355 + }
  1356 + dragXml.append(cmdString);
  1357 + dragXml.append("</Control>\r\n");
  1358 +
  1359 + Request request = headerProvider.createMessageRequest(device, dragXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));
  1360 + logger.debug("拉框信令: " + request.toString());
  1361 + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()),request);
  1362 + }
  1363 +
  1364 +
  1365 +
  1366 + /**
  1367 + * 回放暂停
  1368 + */
  1369 + @Override
  1370 + public void playPauseCmd(Device device, StreamInfo streamInfo) throws InvalidArgumentException, ParseException, SipException {
  1371 + StringBuffer content = new StringBuffer(200);
  1372 + content.append("PAUSE RTSP/1.0\r\n");
  1373 + content.append("CSeq: " + getInfoCseq() + "\r\n");
  1374 + content.append("PauseTime: now\r\n");
  1375 +
  1376 + playbackControlCmd(device, streamInfo, content.toString(), null, null);
  1377 + }
  1378 +
  1379 +
  1380 + /**
  1381 + * 回放恢复
  1382 + */
  1383 + @Override
  1384 + public void playResumeCmd(Device device, StreamInfo streamInfo) throws InvalidArgumentException, ParseException, SipException {
  1385 + StringBuffer content = new StringBuffer(200);
  1386 + content.append("PLAY RTSP/1.0\r\n");
  1387 + content.append("CSeq: " + getInfoCseq() + "\r\n");
  1388 + content.append("Range: npt=now-\r\n");
  1389 +
  1390 + playbackControlCmd(device, streamInfo, content.toString(), null, null);
  1391 + }
  1392 +
  1393 + /**
  1394 + * 回放拖动播放
  1395 + */
  1396 + @Override
  1397 + public void playSeekCmd(Device device, StreamInfo streamInfo, long seekTime) throws InvalidArgumentException, ParseException, SipException {
  1398 + StringBuffer content = new StringBuffer(200);
  1399 + content.append("PLAY RTSP/1.0\r\n");
  1400 + content.append("CSeq: " + getInfoCseq() + "\r\n");
  1401 + content.append("Range: npt=" + Math.abs(seekTime) + "-\r\n");
  1402 +
  1403 + playbackControlCmd(device, streamInfo, content.toString(), null, null);
  1404 + }
  1405 +
  1406 + /**
  1407 + * 回放倍速播放
  1408 + */
  1409 + @Override
  1410 + public void playSpeedCmd(Device device, StreamInfo streamInfo, Double speed) throws InvalidArgumentException, ParseException, SipException {
  1411 + StringBuffer content = new StringBuffer(200);
  1412 + content.append("PLAY RTSP/1.0\r\n");
  1413 + content.append("CSeq: " + getInfoCseq() + "\r\n");
  1414 + content.append("Scale: " + String.format("%.6f", speed) + "\r\n");
  1415 +
  1416 + playbackControlCmd(device, streamInfo, content.toString(), null, null);
  1417 + }
  1418 +
  1419 + private int getInfoCseq() {
  1420 + return (int) ((Math.random() * 9 + 1) * Math.pow(10, 8));
  1421 + }
  1422 +
  1423 + @Override
  1424 + public void playbackControlCmd(Device device, StreamInfo streamInfo, String content, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws SipException, InvalidArgumentException, ParseException {
  1425 +
  1426 + SsrcTransaction ssrcTransaction = streamSession.getSsrcTransaction(device.getDeviceId(), streamInfo.getChannelId(), null, streamInfo.getStream());
  1427 + if (ssrcTransaction == null) {
  1428 + logger.info("[回放控制]未找到视频流信息,设备:{}, 流ID: {}", device.getDeviceId(), streamInfo.getStream());
  1429 + return;
  1430 + }
  1431 +
  1432 + SIPRequest request = headerProvider.createInfoRequest(device, streamInfo.getChannelId(), content.toString(), ssrcTransaction.getSipTransactionInfo());
  1433 + if (request == null) {
  1434 + logger.info("[回放控制]构建Request信息失败,设备:{}, 流ID: {}", device.getDeviceId(), streamInfo.getStream());
  1435 + return;
  1436 + }
  1437 +
  1438 + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent, okEvent);
  1439 + }
  1440 +
  1441 + @Override
  1442 + public void sendAlarmMessage(Device device, DeviceAlarm deviceAlarm) throws InvalidArgumentException, SipException, ParseException {
  1443 + if (device == null) {
  1444 + return;
  1445 + }
  1446 + logger.info("[发送报警通知]设备: {}/{}->{},{}", device.getDeviceId(), deviceAlarm.getChannelId(),
  1447 + deviceAlarm.getLongitude(), deviceAlarm.getLatitude());
  1448 +
  1449 + String characterSet = device.getCharset();
  1450 + StringBuffer deviceStatusXml = new StringBuffer(600);
  1451 + deviceStatusXml.append("<?xml version=\"1.0\" encoding=\"" + characterSet + "\"?>\r\n");
  1452 + deviceStatusXml.append("<Notify>\r\n");
  1453 + deviceStatusXml.append("<CmdType>Alarm</CmdType>\r\n");
  1454 + deviceStatusXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");
  1455 + deviceStatusXml.append("<DeviceID>" + deviceAlarm.getChannelId() + "</DeviceID>\r\n");
  1456 + deviceStatusXml.append("<AlarmPriority>" + deviceAlarm.getAlarmPriority() + "</AlarmPriority>\r\n");
  1457 + deviceStatusXml.append("<AlarmMethod>" + deviceAlarm.getAlarmMethod() + "</AlarmMethod>\r\n");
  1458 + deviceStatusXml.append("<AlarmTime>" + DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(deviceAlarm.getAlarmTime()) + "</AlarmTime>\r\n");
  1459 + deviceStatusXml.append("<AlarmDescription>" + deviceAlarm.getAlarmDescription() + "</AlarmDescription>\r\n");
  1460 + deviceStatusXml.append("<Longitude>" + deviceAlarm.getLongitude() + "</Longitude>\r\n");
  1461 + deviceStatusXml.append("<Latitude>" + deviceAlarm.getLatitude() + "</Latitude>\r\n");
  1462 + deviceStatusXml.append("<info>\r\n");
  1463 + deviceStatusXml.append("<AlarmType>" + deviceAlarm.getAlarmType() + "</AlarmType>\r\n");
  1464 + deviceStatusXml.append("</info>\r\n");
  1465 + deviceStatusXml.append("</Notify>\r\n");
  1466 +
  1467 +
  1468 + Request request = headerProvider.createMessageRequest(device, deviceStatusXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));
  1469 + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()),request);
  1470 +
  1471 +
  1472 + }
  1473 +}
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java
1 package com.genersoft.iot.vmp.gb28181.transmit.cmd.impl; 1 package com.genersoft.iot.vmp.gb28181.transmit.cmd.impl;
2 2
3 import com.alibaba.fastjson2.JSON; 3 import com.alibaba.fastjson2.JSON;
  4 +import com.genersoft.iot.vmp.common.InviteSessionType;
4 import com.genersoft.iot.vmp.conf.DynamicTask; 5 import com.genersoft.iot.vmp.conf.DynamicTask;
  6 +import com.genersoft.iot.vmp.conf.UserSetting;
  7 +import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException;
5 import com.genersoft.iot.vmp.gb28181.SipLayer; 8 import com.genersoft.iot.vmp.gb28181.SipLayer;
6 import com.genersoft.iot.vmp.gb28181.bean.*; 9 import com.genersoft.iot.vmp.gb28181.bean.*;
7 import com.genersoft.iot.vmp.gb28181.event.SipSubscribe; 10 import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
  11 +import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
8 import com.genersoft.iot.vmp.gb28181.transmit.SIPSender; 12 import com.genersoft.iot.vmp.gb28181.transmit.SIPSender;
9 import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform; 13 import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform;
10 import com.genersoft.iot.vmp.gb28181.transmit.cmd.SIPRequestHeaderPlarformProvider; 14 import com.genersoft.iot.vmp.gb28181.transmit.cmd.SIPRequestHeaderPlarformProvider;
11 import com.genersoft.iot.vmp.gb28181.utils.SipUtils; 15 import com.genersoft.iot.vmp.gb28181.utils.SipUtils;
  16 +import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe;
  17 +import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeFactory;
  18 +import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForStreamChange;
12 import com.genersoft.iot.vmp.media.zlm.ZLMServerFactory; 19 import com.genersoft.iot.vmp.media.zlm.ZLMServerFactory;
13 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; 20 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
  21 +import com.genersoft.iot.vmp.media.zlm.dto.hook.HookParam;
14 import com.genersoft.iot.vmp.service.IMediaServerService; 22 import com.genersoft.iot.vmp.service.IMediaServerService;
15 import com.genersoft.iot.vmp.service.bean.GPSMsgInfo; 23 import com.genersoft.iot.vmp.service.bean.GPSMsgInfo;
  24 +import com.genersoft.iot.vmp.service.bean.SSRCInfo;
16 import com.genersoft.iot.vmp.storager.IRedisCatchStorage; 25 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
17 import com.genersoft.iot.vmp.storager.dao.dto.PlatformRegisterInfo; 26 import com.genersoft.iot.vmp.storager.dao.dto.PlatformRegisterInfo;
18 import com.genersoft.iot.vmp.utils.DateUtil; 27 import com.genersoft.iot.vmp.utils.DateUtil;
19 import com.genersoft.iot.vmp.utils.GitUtil; 28 import com.genersoft.iot.vmp.utils.GitUtil;
20 import gov.nist.javax.sip.message.MessageFactoryImpl; 29 import gov.nist.javax.sip.message.MessageFactoryImpl;
21 import gov.nist.javax.sip.message.SIPRequest; 30 import gov.nist.javax.sip.message.SIPRequest;
  31 +import gov.nist.javax.sip.message.SIPResponse;
22 import org.slf4j.Logger; 32 import org.slf4j.Logger;
23 import org.slf4j.LoggerFactory; 33 import org.slf4j.LoggerFactory;
24 import org.springframework.beans.factory.annotation.Autowired; 34 import org.springframework.beans.factory.annotation.Autowired;
@@ -28,6 +38,7 @@ import org.springframework.stereotype.Component; @@ -28,6 +38,7 @@ import org.springframework.stereotype.Component;
28 import org.springframework.util.ObjectUtils; 38 import org.springframework.util.ObjectUtils;
29 39
30 import javax.sip.InvalidArgumentException; 40 import javax.sip.InvalidArgumentException;
  41 +import javax.sip.ResponseEvent;
31 import javax.sip.SipException; 42 import javax.sip.SipException;
32 import javax.sip.SipFactory; 43 import javax.sip.SipFactory;
33 import javax.sip.header.CallIdHeader; 44 import javax.sip.header.CallIdHeader;
@@ -65,6 +76,16 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { @@ -65,6 +76,16 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform {
65 private SIPSender sipSender; 76 private SIPSender sipSender;
66 77
67 @Autowired 78 @Autowired
  79 + private ZlmHttpHookSubscribe subscribe;
  80 +
  81 + @Autowired
  82 + private UserSetting userSetting;
  83 +
  84 +
  85 + @Autowired
  86 + private VideoStreamSessionManager streamSession;
  87 +
  88 + @Autowired
68 private DynamicTask dynamicTask; 89 private DynamicTask dynamicTask;
69 90
70 @Autowired 91 @Autowired
@@ -462,6 +483,7 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { @@ -462,6 +483,7 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform {
462 sipSender.transmitRequest(parentPlatform.getDeviceIp(), request); 483 sipSender.transmitRequest(parentPlatform.getDeviceIp(), request);
463 } 484 }
464 485
  486 +
465 /** 487 /**
466 * 向上级回复DeviceStatus查询信息 488 * 向上级回复DeviceStatus查询信息
467 * @param parentPlatform 平台信息 489 * @param parentPlatform 平台信息
@@ -811,26 +833,129 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { @@ -811,26 +833,129 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform {
811 } 833 }
812 834
813 @Override 835 @Override
814 - public void streamByeCmd(ParentPlatform parentPlatform, SendRtpItem sendRtpItem) throws SipException, InvalidArgumentException, ParseException { 836 + public synchronized void streamByeCmd(ParentPlatform platform, SendRtpItem sendRtpItem) throws SipException, InvalidArgumentException, ParseException {
815 if (sendRtpItem == null ) { 837 if (sendRtpItem == null ) {
816 logger.info("[向上级发送BYE], sendRtpItem 为NULL"); 838 logger.info("[向上级发送BYE], sendRtpItem 为NULL");
817 return; 839 return;
818 } 840 }
819 - if (parentPlatform == null) { 841 + if (platform == null) {
820 logger.info("[向上级发送BYE], platform 为NULL"); 842 logger.info("[向上级发送BYE], platform 为NULL");
821 return; 843 return;
822 } 844 }
823 - logger.info("[向上级发送BYE], {}/{}", parentPlatform.getServerGBId(), sendRtpItem.getChannelId()); 845 + logger.info("[向上级发送BYE], {}/{}", platform.getServerGBId(), sendRtpItem.getChannelId());
824 String mediaServerId = sendRtpItem.getMediaServerId(); 846 String mediaServerId = sendRtpItem.getMediaServerId();
825 MediaServerItem mediaServerItem = mediaServerService.getOne(mediaServerId); 847 MediaServerItem mediaServerItem = mediaServerService.getOne(mediaServerId);
826 if (mediaServerItem != null) { 848 if (mediaServerItem != null) {
827 mediaServerService.releaseSsrc(mediaServerItem.getId(), sendRtpItem.getSsrc()); 849 mediaServerService.releaseSsrc(mediaServerItem.getId(), sendRtpItem.getSsrc());
828 - zlmServerFactory.closeRtpServer(mediaServerItem, sendRtpItem.getStreamId()); 850 + zlmServerFactory.closeRtpServer(mediaServerItem, sendRtpItem.getStream());
829 } 851 }
830 - SIPRequest byeRequest = headerProviderPlatformProvider.createByeRequest(parentPlatform, sendRtpItem); 852 + SIPRequest byeRequest = headerProviderPlatformProvider.createByeRequest(platform, sendRtpItem);
831 if (byeRequest == null) { 853 if (byeRequest == null) {
832 logger.warn("[向上级发送bye]:无法创建 byeRequest"); 854 logger.warn("[向上级发送bye]:无法创建 byeRequest");
833 } 855 }
834 - sipSender.transmitRequest(parentPlatform.getDeviceIp(),byeRequest); 856 + sipSender.transmitRequest(platform.getDeviceIp(),byeRequest);
  857 + }
  858 +
  859 + @Override
  860 + public void streamByeCmd(ParentPlatform platform, String channelId, String stream, String callId, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException, SsrcTransactionNotFoundException {
  861 + SsrcTransaction ssrcTransaction = streamSession.getSsrcTransaction(platform.getServerGBId(), channelId, callId, stream);
  862 + if (ssrcTransaction == null) {
  863 + throw new SsrcTransactionNotFoundException(platform.getServerGBId(), channelId, callId, stream);
  864 + }
  865 +
  866 + mediaServerService.releaseSsrc(ssrcTransaction.getMediaServerId(), ssrcTransaction.getSsrc());
  867 + mediaServerService.closeRTPServer(ssrcTransaction.getMediaServerId(), ssrcTransaction.getStream());
  868 + streamSession.remove(ssrcTransaction.getDeviceId(), ssrcTransaction.getChannelId(), ssrcTransaction.getStream());
  869 +
  870 + Request byteRequest = headerProviderPlatformProvider.createByteRequest(platform, channelId, ssrcTransaction.getSipTransactionInfo());
  871 + sipSender.transmitRequest(sipLayer.getLocalIp(platform.getDeviceIp()), byteRequest, null, okEvent);
  872 + }
  873 +
  874 + @Override
  875 + public void broadcastResultCmd(ParentPlatform platform, DeviceChannel deviceChannel, String sn, boolean result, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException {
  876 + if (platform == null || deviceChannel == null) {
  877 + return;
  878 + }
  879 + String characterSet = platform.getCharacterSet();
  880 + StringBuffer mediaStatusXml = new StringBuffer(200);
  881 + mediaStatusXml.append("<?xml version=\"1.0\" encoding=\"" + characterSet + "\"?>\r\n");
  882 + mediaStatusXml.append("<Response>\r\n");
  883 + mediaStatusXml.append("<CmdType>Broadcast</CmdType>\r\n");
  884 + mediaStatusXml.append("<SN>" + sn + "</SN>\r\n");
  885 + mediaStatusXml.append("<DeviceID>" + deviceChannel.getChannelId() + "</DeviceID>\r\n");
  886 + mediaStatusXml.append("<Result>" + (result?"OK":"ERROR") + "</Result>\r\n");
  887 + mediaStatusXml.append("</Response>\r\n");
  888 +
  889 + CallIdHeader callIdHeader = sipSender.getNewCallIdHeader(platform.getDeviceIp(), platform.getTransport());
  890 +
  891 + SIPRequest messageRequest = (SIPRequest)headerProviderPlatformProvider.createMessageRequest(platform, mediaStatusXml.toString(),
  892 + SipUtils.getNewFromTag(), SipUtils.getNewViaTag(), callIdHeader);
  893 +
  894 + sipSender.transmitRequest(platform.getDeviceIp(),messageRequest, errorEvent, okEvent);
  895 + }
  896 +
  897 + @Override
  898 + public void broadcastInviteCmd(ParentPlatform platform, String channelId, MediaServerItem mediaServerItem,
  899 + SSRCInfo ssrcInfo, ZlmHttpHookSubscribe.Event event, SipSubscribe.Event okEvent,
  900 + SipSubscribe.Event errorEvent) throws ParseException, SipException, InvalidArgumentException {
  901 + String stream = ssrcInfo.getStream();
  902 +
  903 + if (platform == null) {
  904 + return;
  905 + }
  906 +
  907 + logger.info("{} 分配的ZLM为: {} [{}:{}]", stream, mediaServerItem.getId(), mediaServerItem.getIp(), ssrcInfo.getPort());
  908 + HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", stream, true, "rtsp", mediaServerItem.getId());
  909 + subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, HookParam hookParam) -> {
  910 + if (event != null) {
  911 + event.response(mediaServerItemInUse, hookParam);
  912 + subscribe.removeSubscribe(hookSubscribe);
  913 + }
  914 + });
  915 + String sdpIp = mediaServerItem.getSdpIp();
  916 +
  917 + StringBuffer content = new StringBuffer(200);
  918 + content.append("v=0\r\n");
  919 + content.append("o=" + channelId + " 0 0 IN IP4 " + sdpIp + "\r\n");
  920 + content.append("s=Play\r\n");
  921 + content.append("c=IN IP4 " + sdpIp + "\r\n");
  922 + content.append("t=0 0\r\n");
  923 +
  924 + if ("TCP-PASSIVE".equalsIgnoreCase(userSetting.getBroadcastForPlatform())) {
  925 + content.append("m=audio " + ssrcInfo.getPort() + " TCP/RTP/AVP 8 96\r\n");
  926 + } else if ("TCP-ACTIVE".equalsIgnoreCase(userSetting.getBroadcastForPlatform())) {
  927 + content.append("m=audio " + ssrcInfo.getPort() + " TCP/RTP/AVP 8 96\r\n");
  928 + } else if ("UDP".equalsIgnoreCase(userSetting.getBroadcastForPlatform())) {
  929 + content.append("m=audio " + ssrcInfo.getPort() + " RTP/AVP 8 96\r\n");
  930 + }
  931 +
  932 + content.append("a=recvonly\r\n");
  933 + content.append("a=rtpmap:8 PCMA/8000\r\n");
  934 + content.append("a=rtpmap:96 PS/90000\r\n");
  935 + if ("TCP-PASSIVE".equalsIgnoreCase(userSetting.getBroadcastForPlatform())) {
  936 + content.append("a=setup:passive\r\n");
  937 + content.append("a=connection:new\r\n");
  938 + }else if ("TCP-ACTIVE".equalsIgnoreCase(userSetting.getBroadcastForPlatform())) {
  939 + content.append("a=setup:active\r\n");
  940 + content.append("a=connection:new\r\n");
  941 + }
  942 +
  943 + content.append("y=" + ssrcInfo.getSsrc() + "\r\n");//ssrc
  944 + CallIdHeader callIdHeader = sipSender.getNewCallIdHeader(sipLayer.getLocalIp(platform.getDeviceIp()), platform.getTransport());
  945 +
  946 + Request request = headerProviderPlatformProvider.createInviteRequest(platform, channelId,
  947 + content.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), ssrcInfo.getSsrc(),
  948 + callIdHeader);
  949 + sipSender.transmitRequest(sipLayer.getLocalIp(platform.getDeviceIp()), request, (e -> {
  950 + streamSession.remove(platform.getServerGBId(), channelId, ssrcInfo.getStream());
  951 + mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
  952 + subscribe.removeSubscribe(hookSubscribe);
  953 + errorEvent.response(e);
  954 + }), e -> {
  955 + ResponseEvent responseEvent = (ResponseEvent) e.event;
  956 + SIPResponse response = (SIPResponse) responseEvent.getResponse();
  957 + streamSession.put(platform.getServerGBId(), channelId, callIdHeader.getCallId(), stream, ssrcInfo.getSsrc(), mediaServerItem.getId(), response, InviteSessionType.BROADCAST);
  958 + okEvent.response(e);
  959 + });
835 } 960 }
836 } 961 }
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/SIPRequestProcessorParent.java
@@ -82,6 +82,7 @@ public abstract class SIPRequestProcessorParent { @@ -82,6 +82,7 @@ public abstract class SIPRequestProcessorParent {
82 return responseAck(sipRequest, statusCode, msg, null); 82 return responseAck(sipRequest, statusCode, msg, null);
83 } 83 }
84 84
  85 +
85 public SIPResponse responseAck(SIPRequest sipRequest, int statusCode, String msg, ResponseAckExtraParam responseAckExtraParam) throws SipException, InvalidArgumentException, ParseException { 86 public SIPResponse responseAck(SIPRequest sipRequest, int statusCode, String msg, ResponseAckExtraParam responseAckExtraParam) throws SipException, InvalidArgumentException, ParseException {
86 if (sipRequest.getToHeader().getTag() == null) { 87 if (sipRequest.getToHeader().getTag() == null) {
87 sipRequest.getToHeader().setTag(SipUtils.getNewTag()); 88 sipRequest.getToHeader().setTag(SipUtils.getNewTag());
@@ -124,6 +125,8 @@ public abstract class SIPRequestProcessorParent { @@ -124,6 +125,8 @@ public abstract class SIPRequestProcessorParent {
124 return response; 125 return response;
125 } 126 }
126 127
  128 +
  129 +
127 /** 130 /**
128 * 回复带sdp的200 131 * 回复带sdp的200
129 */ 132 */
@@ -141,7 +144,10 @@ public abstract class SIPRequestProcessorParent { @@ -141,7 +144,10 @@ public abstract class SIPRequestProcessorParent {
141 responseAckExtraParam.content = sdp; 144 responseAckExtraParam.content = sdp;
142 responseAckExtraParam.sipURI = sipURI; 145 responseAckExtraParam.sipURI = sipURI;
143 146
144 - return responseAck(request, Response.OK, null, responseAckExtraParam); 147 + SIPResponse sipResponse = responseAck(request, Response.OK, null, responseAckExtraParam);
  148 +
  149 +
  150 + return sipResponse;
145 } 151 }
146 152
147 /** 153 /**
@@ -174,7 +180,8 @@ public abstract class SIPRequestProcessorParent { @@ -174,7 +180,8 @@ public abstract class SIPRequestProcessorParent {
174 reader.setEncoding(charset); 180 reader.setEncoding(charset);
175 // 对海康出现的未转义字符做处理。 181 // 对海康出现的未转义字符做处理。
176 String[] destStrArray = new String[]{"&lt;","&gt;","&amp;","&apos;","&quot;"}; 182 String[] destStrArray = new String[]{"&lt;","&gt;","&amp;","&apos;","&quot;"};
177 - char despChar = '&'; // 或许可扩展兼容其他字符 183 + // 或许可扩展兼容其他字符
  184 + char despChar = '&';
178 byte destBye = (byte) despChar; 185 byte destBye = (byte) despChar;
179 List<Byte> result = new ArrayList<>(); 186 List<Byte> result = new ArrayList<>();
180 byte[] rawContent = request.getRawContent(); 187 byte[] rawContent = request.getRawContent();
@@ -220,4 +227,5 @@ public abstract class SIPRequestProcessorParent { @@ -220,4 +227,5 @@ public abstract class SIPRequestProcessorParent {
220 return xml.getRootElement(); 227 return xml.getRootElement();
221 } 228 }
222 229
  230 +
223 } 231 }