Commit b86f0aaae2f0212bc01ddfd3e5d646c22eb1d8c0
Committed by
Gitee
!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
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<Object> { | @@ -32,7 +32,7 @@ public class GlobalResponseAdvice implements ResponseBodyAdvice<Object> { | ||
| 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<Object> { | @@ -59,8 +59,8 @@ public class GlobalResponseAdvice implements ResponseBodyAdvice<Object> { | ||
| 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
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[]{"<",">","&","'","""}; | 182 | String[] destStrArray = new String[]{"<",">","&","'","""}; |
| 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 | } |